use crate::game_of_life::opts::Opts; use crate::game_of_life::simulation::{plane::Plane, universe::Universe}; use clap::Error; use rand::rngs::StdRng; use rand::{Rng, SeedableRng}; use rand_distr::{Distribution, Uniform}; #[cfg(test)] use mocktopus::macros::mockable; /// Generate a new Universe/Board from a seed number /// /// The generation of the seed should be stable across different machines /// using the same language package, version, width and height. #[cfg_attr(test, mockable)] pub(crate) fn new(opts: Opts) -> Result { let range = generator(opts.seed); Ok(populate(opts, range)) } /// Create a StdRng using Uniform distribution for generating same data from /// the same seed fn generator(seed: usize) -> StdRng { let mut range = StdRng::seed_from_u64(seed as u64); Uniform::new_inclusive(0, 1).sample(&mut range); range } #[cfg(test)] mod generator { use super::*; #[test] fn seed_1337() { let mut rng = generator(1337); assert_eq!(rng.gen::(), true); assert_eq!(rng.gen::(), false); assert_eq!(rng.gen::(), true); assert_eq!(rng.gen::(), true); assert_eq!(rng.gen::(), false); } #[test] fn seed_42() { let mut rng = generator(42); assert_eq!(rng.gen::(), true); assert_eq!(rng.gen::(), false); assert_eq!(rng.gen::(), true); assert_eq!(rng.gen::(), true); assert_eq!(rng.gen::(), true); } } /// Return a universe struct with populated data from the seedable range fn populate(opts: Opts, mut range: StdRng) -> Universe { let (width, height) = (opts.width as usize, opts.height as usize); let mut current = Plane(vec![Plane(vec![false; width]); height]); for i in 0..height { for j in 0..width { current[i as isize][j as isize] = range.gen() } } Universe { opts, current, future: Plane(vec![Plane(vec![false; width]); height]), } } #[cfg(test)] mod populate { use super::*; fn opts(seed: usize) -> Opts { Opts { seed, input: None, width: 5, height: 3, live_cell: 'L', dead_cell: 'D', delay: 13, } } #[test] fn seed_1337() { let rng = generator(1337); let opts = opts(1337); let universe = populate(opts.clone(), rng); assert_eq!( universe, Universe { opts, future: Plane(vec![Plane(vec![false; 5]); 3]), current: Plane(vec![ Plane(vec![true, false, true, true, false]), Plane(vec![true, false, true, false, true]), Plane(vec![false, false, true, true, true]), ]), } ) } #[test] fn seed_42() { let rng = generator(42); let opts = opts(42); let universe = populate(opts.clone(), rng); assert_eq!( universe, Universe { opts, future: Plane(vec![Plane(vec![false; 5]); 3]), current: Plane(vec![ Plane(vec![true, false, true, true, true]), Plane(vec![true, false, true, false, true]), Plane(vec![false, false, true, false, true]), ]), } ) } }