sequence.rs

4.5 kB · rust · 153 lines

1use mrlycore::state::{boolean, choice, randint, sample};2use mrlymath::life::{Counts, Sequence};34/// One drawn rule: the sequences behind it and the parity rolls.5#[derive(Clone, Debug)]6pub struct Rulebook {7    /// The sequence behind the birth counts.8    pub birth_sequence: Sequence,9    /// The sequence behind the survive counts.10    pub survive_sequence: Sequence,11    /// Whether one sequence serves both sides.12    pub reflect: bool,13    /// Whether zero stays in the counts.14    pub zeros: bool,15    /// Whether one stays in the counts.16    pub ones: bool,17}1819impl Rulebook {20    /// Returns the counts that create a cell.21    pub fn birth(&self) -> Counts {22        Counts::drawn(self.birth_sequence, self.zeros, self.ones)23    }24    /// Returns the counts that keep a cell.25    pub fn survive(&self) -> Counts {26        Counts::drawn(self.survive_sequence, self.zeros, self.ones)27    }28}2930fn options(simple: bool) -> Vec<Sequence> {31    if simple {32        return Sequence::numbers().to_vec();33    }34    let mut both = Sequence::numbers().to_vec();35    both.extend(Sequence::designs());36    both.retain(|s| !s.is_random());37    both38}3940fn sown(seq: Sequence) -> Sequence {41    if seq.is_random() {42        Sequence::Random(randint(0, i64::MAX) as u64)43    } else {44        seq45    }46}4748/// Draws a rulebook, number sequences only on the simple path, random draws given a seed.49pub fn rulebook(simple: bool) -> Rulebook {50    let pool = options(simple);51    let reflect = boolean();52    let (birth_sequence, survive_sequence) = if reflect {53        let one = sown(choice(&pool));54        (one, one)55    } else {56        let pair = sample(&pool, 2);57        (sown(pair[0]), sown(pair[1]))58    };59    Rulebook {60        birth_sequence,61        survive_sequence,62        reflect,63        zeros: boolean(),64        ones: boolean(),65    }66}6768#[cfg(test)]69mod tests {70    use super::*;71    use mrlycore::state::{guard, seed};72    #[test]73    fn the_simple_tier_holds_the_six_numbers() {74        let pool = options(true);75        assert_eq!(pool.len(), 6);76        assert!(pool.iter().any(|s| s.is_random()));77    }78    #[test]79    fn the_full_tier_drops_random() {80        let pool = options(false);81        assert_eq!(pool.len(), 22);82        assert!(!pool.iter().any(|s| s.is_random()));83        assert!(pool.contains(&Sequence::GridSquares));84    }85    #[test]86    fn reflection_serves_one_sequence_to_both_sides() {87        let _g = guard();88        let mut mirrored = false;89        let mut split = false;90        for s in 0..50 {91            seed(s);92            let rule = rulebook(true);93            if rule.reflect {94                assert_eq!(rule.birth_sequence, rule.survive_sequence);95                mirrored = true;96            } else {97                assert_ne!(rule.birth_sequence, rule.survive_sequence);98                split = true;99            }100        }101        assert!(mirrored && split);102    }103    #[test]104    fn counts_respect_the_budget_and_the_rolls() {105        let _g = guard();106        for s in 0..50 {107            seed(s);108            let rule = rulebook(false);109            let birth = rule.birth().values(8).unwrap();110            let survive = rule.survive().values(8).unwrap();111            for n in birth.iter().chain(&survive) {112                assert!(*n <= 8);113                if *n == 0 {114                    assert!(rule.zeros);115                }116                if *n == 1 {117                    assert!(rule.ones);118                }119            }120        }121    }122    #[test]123    fn a_random_draw_carries_its_own_seed() {124        let _g = guard();125        for s in 0..200 {126            seed(s);127            let rule = rulebook(true);128            if let Sequence::Random(inner) = rule.birth_sequence {129                assert_ne!(inner, 0, "the listed placeholder seed leaked");130                assert_eq!(131                    rule.birth().values(8).unwrap(),132                    Counts::drawn(Sequence::Random(inner), rule.zeros, rule.ones)133                        .values(8)134                        .unwrap()135                );136                return;137            }138        }139        panic!("no seed drew the random sequence");140    }141    #[test]142    fn the_draw_replays_from_a_seed() {143        let _g = guard();144        seed(42);145        let a = rulebook(true);146        seed(42);147        let b = rulebook(true);148        assert_eq!(a.birth_sequence, b.birth_sequence);149        assert_eq!(a.survive_sequence, b.survive_sequence);150        assert_eq!(a.birth().values(8).unwrap(), b.birth().values(8).unwrap());151        assert_eq!(a.reflect, b.reflect);152    }153}