use super::circular_index; use crate::game_of_life::opts::Opts; use crate::game_of_life::simulation::plane::Plane; use std::ops::Index; /// Game of Life universe struct for running simulations #[derive(Debug, Clone, PartialEq)] pub(crate) struct Universe { pub opts: Opts, pub current: Vec, pub future: Vec, } impl Index for Universe { type Output = Plane; fn index(&self, idx: isize) -> &Plane { let len = self.current.len() as isize; &self.current[circular_index(idx, len)] } } #[cfg(test)] mod index { use super::*; #[test] fn get_element() { let opts = Opts { seed: 1337, input: None, width: 13, height: 13, live_cell: 'L', dead_cell: 'D', delay: 13, }; let u = Universe { opts, current: vec![ Plane(vec![false; 5]), Plane(vec![false, false, true, false, false]), Plane(vec![false; 5]), ], future: vec![Plane(vec![])], }; assert_eq!(u[-3][0], false); assert_eq!(u[-3][1], false); assert_eq!(u[-3][3], false); assert_eq!(u[-3][4], false); assert_eq!(u[0][0], false); assert_eq!(u[0][1], false); assert_eq!(u[0][3], false); assert_eq!(u[0][4], false); assert_eq!(u[2][0], false); assert_eq!(u[2][1], false); assert_eq!(u[2][3], false); assert_eq!(u[2][4], false); assert_eq!(u[5][0], false); assert_eq!(u[5][1], false); assert_eq!(u[5][3], false); assert_eq!(u[5][4], false); assert_eq!(u[-2][-3], true); assert_eq!(u[-2][2], true); assert_eq!(u[-2][7], true); assert_eq!(u[1][-3], true); assert_eq!(u[1][2], true); assert_eq!(u[1][7], true); assert_eq!(u[4][-3], true); assert_eq!(u[4][2], true); assert_eq!(u[4][7], true); } } impl Universe { /// Return the neighboring cells to the cell in index (Y,X) on a plane /// /// given a cell "C" in a universe of cells "." the immediate neighbors would be "x" as in /// the following different examples /// /// ..... | .xxx. | .xCx. | xCx.. | Cx..x | xx..x | /// .xxx. | .xCx. | .xxx. | xxx.. | xx..x | Cx..x | /// .xCx. | .xxx. | ..... | ..... | ..... | xx..x | /// .xxx. | ..... | ..... | ..... | ..... | ..... | /// ..... | ..... | .xxx. | xxx.. | xx..x | ..... | /// pub(crate) fn neighbors(self, y: isize, x: isize) -> Vec { vec![ self[y - 1][x - 1], self[y - 1][x], self[y - 1][x + 1], self[y][x - 1], self[y][x + 1], self[y + 1][x - 1], self[y + 1][x], self[y + 1][x + 1], ] } } #[cfg(test)] mod neighbors { use super::*; fn opts() -> Opts { Opts { seed: 1337, input: None, width: 13, height: 13, live_cell: 'L', dead_cell: 'D', delay: 13, } } #[test] fn center() { let u = Universe { opts: opts(), future: vec![Plane(vec![])], current: vec![ Plane(vec![false, false, false, false, false]), Plane(vec![false, true, true, true, false]), Plane(vec![false, true, true, true, false]), Plane(vec![false, true, true, true, false]), Plane(vec![false, false, false, false, false]), ], }; assert_eq!(u.neighbors(2,2), vec![true; 8]); } #[test] fn top_edge() { let u = Universe { opts: opts(), future: vec![Plane(vec![])], current: vec![ Plane(vec![false, true, true, true, false]), Plane(vec![false, true, true, true, false]), Plane(vec![false, false, false, false, false]), Plane(vec![false, false, false, false, false]), Plane(vec![false, true, true, true, false]), ], }; assert_eq!(u.neighbors(0,2), vec![true; 8]); } #[test] fn bottom_edge() { let u = Universe { opts: opts(), future: vec![Plane(vec![])], current: vec![ Plane(vec![false, true, true, true, false]), Plane(vec![false, false, false, false, false]), Plane(vec![false, false, false, false, false]), Plane(vec![false, true, true, true, false]), Plane(vec![false, true, true, true, false]), ], }; assert_eq!(u.neighbors(4,2), vec![true; 8]); } #[test] fn left_edge() { let u = Universe { opts: opts(), future: vec![Plane(vec![])], current: vec![ Plane(vec![false, false, false, false, false]), Plane(vec![true, true, false, false, true]), Plane(vec![true, true, false, false, true]), Plane(vec![true, true, false, false, true]), Plane(vec![false, false, false, false, false]), ], }; assert_eq!(u.neighbors(2,0), vec![true; 8]); } #[test] fn right_edge() { let u = Universe { opts: opts(), future: vec![Plane(vec![])], current: vec![ Plane(vec![false, false, false, false, false]), Plane(vec![true, false, false, true, true]), Plane(vec![true, false, false, true, true]), Plane(vec![true, false, false, true, true]), Plane(vec![false, false, false, false, false]), ], }; assert_eq!(u.neighbors(2,4), vec![true; 8]); } #[test] fn bottom_corner_edge() { let u = Universe { opts: opts(), future: vec![Plane(vec![])], current: vec![ Plane(vec![true, false, false, true, true]), Plane(vec![false, false, false, false, false]), Plane(vec![false, false, false, false, false]), Plane(vec![true, false, false, true, true]), Plane(vec![true, false, false, true, true]), ], }; assert_eq!(u.neighbors(4,4), vec![true; 8]); } #[test] fn top_corner_edge() { let u = Universe { opts: opts(), future: vec![Plane(vec![])], current: vec![ Plane(vec![true, true, false, false, true]), Plane(vec![true, true, false, false, true]), Plane(vec![false, false, false, false, false]), Plane(vec![false, false, false, false, false]), Plane(vec![true, true, false, false, true]), ], }; assert_eq!(u.neighbors(0,0), vec![true; 8]); } }