use rand::{ distributions::{Distribution, Standard}, Rng, }; use tapestry::{coord::Coord, grid::Grid, patterns, rect::Rect}; fn main() { let mut life_board = LifeBoard::random((16, 16)); for _i in 0..10 { println!("{}", life_board.grid); life_board.step(); } } struct LifeBoard { grid: Grid, } impl LifeBoard { fn random>(dimensions: C) -> Self { Self { grid: Grid::with_generator(Rect::new(dimensions), |(_x, _y)| { rand::random::() }), } } fn step(&mut self) { let neighbor_counts = self .grid .iter() .map(|cell| self.live_neighbor_count(cell.0)) // `collect` to release the borrow on `self`. .collect::>(); for (cell, neighbor_count) in self.grid.cell_iter_mut().zip(neighbor_counts) { *cell = LifeBoard::compute_state(*cell, neighbor_count) } } fn live_neighbor_count(&self, coord: Coord) -> usize { self.grid .selection_iter(patterns::neighborhood(coord)) .filter(|r_cell| { if let Ok(cell) = r_cell { *cell.1 == LifeState::Alive } else { false } }) .count() } fn compute_state(state: LifeState, neighbor_count: usize) -> LifeState { match state { LifeState::Alive => { if neighbor_count == 2 || neighbor_count == 3 { LifeState::Alive } else { LifeState::Dead } } LifeState::Dead => { if neighbor_count == 3 { LifeState::Alive } else { LifeState::Dead } } } } } #[derive(Copy, Clone, PartialEq, Eq, Debug)] enum LifeState { Dead, Alive, } impl Default for LifeState { fn default() -> Self { LifeState::Dead } } impl From for char { fn from(ls: LifeState) -> char { match ls { LifeState::Alive => 'O', LifeState::Dead => '∙', } } } // Allows us to randomly generate LifeState values. impl Distribution for Standard { fn sample(&self, rng: &mut R) -> LifeState { match rng.gen_bool(0.3) { true => LifeState::Alive, false => LifeState::Dead, } } }