step.rs
2.6 kB · rust · 75 lines
1use super::Boundary;2use crate::dim::models::counting_dtype;3use crate::two::Cell2d;4use mrlycore::cell::Cell;5use mrlycore::errors::Result;6use mrlycore::tensor::Tensor;78/// Advances a grid one generation under birth and survive counts, a neighbor mask and a boundary.9pub fn next_grid(10 cell: &Cell2d,11 birth: &[usize],12 survive: &[usize],13 mask: &Tensor,14 boundary: Boundary,15) -> Result<Cell2d> {16 let dtype = counting_dtype(mask);17 let counted = Cell::new(cell.types().clone()).neighbors(mask, 1, boundary.wrap(), dtype)?;18 let neighbors = counted.tags.expect("neighbors sets tags");19 let types = &counted.types;20 let mut next = Tensor::new(types.shape.clone());21 for (i, slot) in next.bytes_mut().iter_mut().enumerate() {22 let n = neighbors.at(i) as usize;23 let alive = types.bytes()[i] == 1;24 let lives = if alive {25 survive.contains(&n)26 } else {27 birth.contains(&n)28 };29 *slot = if lives { 1 } else { 0 };30 }31 Ok(Cell2d::new(next))32}3334#[cfg(test)]35mod tests {36 use super::*;37 use crate::life::moore;38 use crate::two::designs;39 #[test]40 fn conway_blinker_oscillates() {41 let mut t = Tensor::new(vec![5, 5]);42 t.set(&[1, 2], 1);43 t.set(&[2, 2], 1);44 t.set(&[3, 2], 1);45 let cell = Cell2d::new(t);46 let mask = moore().types().clone();47 let next = next_grid(&cell, &[3], &[2, 3], &mask, Boundary::Constant).unwrap();48 assert_eq!(next.types().get(&[2, 1]), 1);49 assert_eq!(next.types().get(&[2, 2]), 1);50 assert_eq!(next.types().get(&[2, 3]), 1);51 assert_eq!(next.types().get(&[1, 2]), 0);52 assert_eq!(next.types().get(&[3, 2]), 0);53 let back = next_grid(&next, &[3], &[2, 3], &mask, Boundary::Constant).unwrap();54 assert_eq!(back.types(), cell.types());55 }56 #[test]57 fn empty_stays_empty() {58 let cell = designs::zeros(3, 1).unwrap();59 let mask = moore().types().clone();60 let next = next_grid(&cell, &[3], &[2, 3], &mask, Boundary::Constant).unwrap();61 assert_eq!(next.types().sum(), 0);62 }63 #[test]64 fn wide_masks_count_beyond_a_byte() {65 use mrlycore::tensor::Tensor;66 let mut mask = Tensor::full(vec![17, 17], 1);67 mask.set(&[8, 8], 0);68 let full = 17 * 17 - 1;69 let cell = Cell2d::new(Tensor::full(vec![21, 21], 1));70 let kept = next_grid(&cell, &[], &[full], &mask, Boundary::Wrap).unwrap();71 assert_eq!(kept.types().sum() as usize, 21 * 21);72 let gone = next_grid(&cell, &[], &[full - 1], &mask, Boundary::Wrap).unwrap();73 assert_eq!(gone.types().sum(), 0);74 }75}