ca_rules/rules/
life.rs

1//! Totalistic life-like rules.
2
3use super::Gen;
4use crate::ParseRuleError;
5
6rule_struct!(Life);
7
8impl Life {
9    parse_bs!(8);
10    parse_rule!();
11}
12
13/// A trait for parsing [totalistic life-like rules](http://www.conwaylife.com/wiki/Totalistic_Life-like_cellular_automaton).
14///
15/// The `b` / `s` data of this type of rules consists of numbers of live neighbors
16/// that cause a cell to be born / survive.
17///
18/// # Examples
19///
20/// ```
21/// use ca_rules::ParseLife;
22///
23/// #[derive(Debug, Eq, PartialEq)]
24/// struct Rule {
25///     b: Vec<u8>,
26///     s: Vec<u8>,
27/// }
28///
29/// impl ParseLife for Rule {
30///     fn from_bs(b: Vec<u8>, s: Vec<u8>) -> Self {
31///         Rule { b, s }
32///     }
33/// }
34///
35/// let life = Rule::parse_rule("B3/S23").unwrap();
36///
37/// assert_eq!(
38///     life,
39///     Rule {
40///         b: vec![3],
41///         s: vec![2, 3],
42///     }
43/// )
44/// ```
45pub trait ParseLife {
46    /// Construct the rule from `b` / `s` data.
47    fn from_bs(b: Vec<u8>, s: Vec<u8>) -> Self;
48
49    /// The parser.
50    fn parse_rule(input: &str) -> Result<Self, ParseRuleError>
51    where
52        Self: Sized,
53    {
54        let Life { b, s } = Life::parse_rule(input)?;
55        Ok(Self::from_bs(b, s))
56    }
57}
58
59/// A trait for parsing [totalistic life-like](http://www.conwaylife.com/wiki/Totalistic_Life-like_cellular_automaton)
60/// [Generations](http://www.conwaylife.com/wiki/Generations) rules.
61///
62/// The `b` / `s` data of this type of rules consists of numbers of live neighbors
63/// that cause a cell to be born / survive.
64///
65/// # Examples
66///
67/// ```
68/// use ca_rules::ParseLifeGen;
69///
70/// #[derive(Debug, Eq, PartialEq)]
71/// struct Rule {
72///     b: Vec<u8>,
73///     s: Vec<u8>,
74///     gen: usize,
75/// }
76///
77/// impl ParseLifeGen for Rule {
78///     fn from_bsg(b: Vec<u8>, s: Vec<u8>, gen: usize) -> Self {
79///         Rule { b, s, gen }
80///     }
81/// }
82///
83/// let life = Rule::parse_rule("3457/357/5").unwrap();
84///
85/// assert_eq!(
86///     life,
87///     Rule {
88///         b: vec![3, 5, 7],
89///         s: vec![3, 4, 5, 7],
90///         gen: 5,
91///     }
92/// )
93/// ```
94pub trait ParseLifeGen {
95    /// Construct the rule from `b` / `s` data and the number of states.
96    fn from_bsg(b: Vec<u8>, s: Vec<u8>, gen: usize) -> Self;
97
98    /// The parser.
99    fn parse_rule(input: &str) -> Result<Self, ParseRuleError>
100    where
101        Self: Sized,
102    {
103        let Gen {
104            rule: Life { b, s },
105            gen,
106        } = Life::parse_rule_gen(input)?;
107        Ok(Self::from_bsg(b, s, gen))
108    }
109}
110
111#[cfg(test)]
112mod tests {
113    use super::*;
114
115    struct Rule;
116
117    impl ParseLife for Rule {
118        fn from_bs(_b: Vec<u8>, _s: Vec<u8>) -> Self {
119            Rule
120        }
121    }
122
123    struct GenRule;
124
125    impl ParseLifeGen for GenRule {
126        fn from_bsg(_b: Vec<u8>, _s: Vec<u8>, _gen: usize) -> Self {
127            GenRule
128        }
129    }
130
131    #[test]
132    fn valid_rules() -> Result<(), ParseRuleError> {
133        Rule::parse_rule("B3/S23")?;
134        Rule::parse_rule("B3S23")?;
135        Rule::parse_rule("b3s23")?;
136        Rule::parse_rule("23/3")?;
137        Rule::parse_rule("23/")?;
138        Ok(())
139    }
140
141    #[test]
142    fn invalid_rules() {
143        assert_eq!(
144            Rule::parse_rule("B3/S23h").err(),
145            Some(ParseRuleError::ExtraJunk)
146        );
147        assert_eq!(
148            Rule::parse_rule("B3/23").err(),
149            Some(ParseRuleError::Missing('S'))
150        );
151        assert_eq!(
152            Rule::parse_rule("B2e3-anq/S12-a3").err(),
153            Some(ParseRuleError::Missing('S'))
154        );
155        assert_eq!(
156            Rule::parse_rule("233").err(),
157            Some(ParseRuleError::Missing('/'))
158        );
159    }
160
161    #[test]
162    fn valid_rules_gen() -> Result<(), ParseRuleError> {
163        GenRule::parse_rule("B3/S23/C3")?;
164        GenRule::parse_rule("B3S23G3")?;
165        GenRule::parse_rule("g3b3s23")?;
166        GenRule::parse_rule("B3/S23")?;
167        GenRule::parse_rule("23/3/3")?;
168        GenRule::parse_rule("23//3")?;
169        GenRule::parse_rule("23/3")?;
170        Ok(())
171    }
172
173    #[test]
174    fn invalid_rules_gen() {
175        assert_eq!(
176            GenRule::parse_rule("B3/S23h").err(),
177            Some(ParseRuleError::ExtraJunk)
178        );
179        assert_eq!(
180            GenRule::parse_rule("B3/S23/").err(),
181            Some(ParseRuleError::MissingNumber)
182        );
183        assert_eq!(
184            GenRule::parse_rule("g1b3s23").err(),
185            Some(ParseRuleError::GenLessThan2)
186        );
187        assert_eq!(
188            GenRule::parse_rule("2333").err(),
189            Some(ParseRuleError::Missing('/'))
190        );
191        assert_eq!(
192            GenRule::parse_rule("23/3/18446744073709551617").err(),
193            Some(ParseRuleError::GenOverflow)
194        );
195    }
196}