#[macro_use]
extern crate ndarray;
use ndarray::prelude::*;
const INPUT: &'static [u8] = include_bytes!("life.txt");
const N: usize = 100;
type Board = Array2<u8>;
fn parse(x: &[u8]) -> Board {
let mut map = Board::from_elem(((N + 2) as Ix, (N + 2) as Ix), 0);
let a = Array::from_iter(x.iter().filter_map(|&b| match b {
b'#' => Some(1),
b'.' => Some(0),
_ => None,
}));
let a = a.into_shape((N as Ix, N as Ix)).unwrap();
map.slice_mut(s![1..-1, 1..-1]).assign(&a);
map
}
fn iterate(z: &mut Board, scratch: &mut Board) {
let mut neigh = scratch.view_mut();
neigh.fill(0);
neigh += &z.slice(s![0..-2, 0..-2]);
neigh += &z.slice(s![0..-2, 1..-1]);
neigh += &z.slice(s![0..-2, 2.. ]);
neigh += &z.slice(s![1..-1, 0..-2]);
neigh += &z.slice(s![1..-1, 2.. ]);
neigh += &z.slice(s![2.. , 0..-2]);
neigh += &z.slice(s![2.. , 1..-1]);
neigh += &z.slice(s![2.. , 2.. ]);
let mut zv = z.slice_mut(s![1..-1, 1..-1]);
zv.zip_mut_with(&neigh, |y, &n| {
*y = ((n == 3) || (n == 2 && *y > 0)) as u8
});
}
fn turn_on_corners(z: &mut Board) {
let n = z.rows();
let m = z.cols();
z[[1 , 1 ]] = 1;
z[[1 , m - 2]] = 1;
z[[n - 2, 1 ]] = 1;
z[[n - 2, m - 2]] = 1;
}
fn render(a: &Board) {
for row in a.inner_iter() {
for &x in row {
if x > 0 {
print!("#");
} else {
print!(".");
}
}
println!("");
}
}
fn main() {
let mut a = parse(INPUT);
let mut scratch = Board::zeros((N as Ix, N as Ix));
let steps = 100;
turn_on_corners(&mut a);
for _ in 0..steps {
iterate(&mut a, &mut scratch);
turn_on_corners(&mut a);
}
render(&a);
let alive = a.iter().filter(|&&x| x > 0).count();
println!("After {} steps there are {} cells alive", steps, alive);
}