#![feature(test)]
extern crate algs4;
extern crate rand;
extern crate test;
use std::env;
use std::iter;
use test::stats::Stats;
use rand::{thread_rng, Rng};
use algs4::fundamentals::union_find::UF;
use algs4::fundamentals::union_find::weighted_quick_union::UnionFind;
pub struct Percolation {
uf: UnionFind,
n: usize,
opened: Vec<bool>
}
impl Percolation {
pub fn new(n: usize) -> Percolation {
Percolation {
uf: UnionFind::new(n * n),
n: n,
opened: iter::repeat(false).take(n * n).collect()
}
}
#[inline]
fn idx_of(&self, i: usize, j: usize) -> usize {
(i - 1) * self.n + j - 1
}
fn neighbor_of(&self, i: usize, j: usize) -> ::std::vec::IntoIter<usize> {
let n = self.n;
let mut result: Vec<usize> = Vec::new();
if i != 1 {
result.push(self.idx_of(i - 1, j));
}
if i != n {
result.push(self.idx_of(i + 1, j));
}
if j != 1 {
result.push(self.idx_of(i, j - 1));
}
if j != n {
result.push(self.idx_of(i, j + 1));
}
result.into_iter()
}
#[inline]
pub fn is_open(&self, i: usize, j: usize) -> bool {
self.opened[self.idx_of(i, j)]
}
pub fn is_full(&self, i: usize, j: usize) -> bool {
let idx = self.idx_of(i, j);
for col in 1 .. self.n + 1 {
if self.is_open(1, col) && self.uf.connected(self.idx_of(1, col), idx) {
return true;
}
}
false
}
pub fn open(&mut self, i: usize, j: usize) {
assert!(i >= 1 && i <= self.n && j >= 1 && j <= self.n, "(i, j) are out of bounds");
let idx = self.idx_of(i, j);
self.opened[idx] = true;
for nid in self.neighbor_of(i, j) {
if self.opened[nid] {
self.uf.union(idx, nid);
}
}
}
pub fn percolates(&self) -> bool {
for col in 1 .. self.n + 1 {
if self.is_open(self.n, col) && self.is_full(self.n, col) {
return true;
}
}
false
}
#[allow(dead_code)]
fn dump(&self) {
for i in 0 .. self.n * self.n {
if self.opened[i] {
print!(" ");
} else {
print!("█");
}
if (i + 1) % self.n == 0 {
println!("|");
}
}
println!("");
}
}
pub struct PercolationStats {
t: usize,
xs: Vec<f64>
}
impl PercolationStats {
pub fn new(n: usize, t: usize) -> PercolationStats {
let mut rng = thread_rng();
let mut xs = Vec::new();
let n_sites = (n as f64) * (n as f64);
for _ in 0 .. t {
let mut sites = Percolation::new(n);
let mut cnt = 0f64;
loop {
let r = rng.gen_range(0, n * n);
let i = r / n + 1;
let j = r % n + 1;
if sites.is_open(i, j) {
continue;
}
sites.open(i, j);
cnt += 1.0;
if sites.percolates() {
break
}
}
xs.push(cnt / n_sites);
}
PercolationStats { t: t, xs: xs }
}
pub fn mean(&self) -> f64 {
self.xs.mean()
}
pub fn std_dev(&self) -> f64 {
self.xs.std_dev()
}
pub fn confidence_low(&self) -> f64 {
self.xs.mean() - 1.96 * self.std_dev() / (self.t as f64).sqrt()
}
pub fn confidence_high(&self) -> f64 {
self.xs.mean() + 1.96 * self.std_dev() / (self.t as f64).sqrt()
}
}
fn main() {
let mut args = env::args();
args.next();
let n: usize = args.next().unwrap().parse().unwrap();
let t: usize = args.next().unwrap().parse().unwrap();
if t < 30 {
println!("Warning: T is not sufficiently large! (at least 30).");
}
let stats = PercolationStats::new(n, t);
println!("{:23} = {}", "mean", stats.mean());
println!("{:23} = {}", "stddev", stats.std_dev());
println!("{:23} = {}, {}", "95% confidence interval", stats.confidence_low(), stats.confidence_high());
}