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}