ca_rules/rules/neumann.rs
1//! Totalistic rules with von Neumann neighborhood.
2
3use super::Gen;
4use crate::ParseRuleError;
5
6rule_struct!(Neumann);
7
8impl Neumann {
9 parse_bs!(4);
10 parse_rule!('V');
11}
12
13/// A trait for parsing totalistic rules with
14/// [von Neumann neighborhood](http://www.conwaylife.com/wiki/Von_Neumann_neighbourhood).
15///
16/// The `b` / `s` data of this type of rules consists of numbers of live neighbors
17/// that cause a cell to be born / survive.
18///
19/// # Examples
20///
21/// ```
22/// use ca_rules::ParseNeumann;
23///
24/// #[derive(Debug, Eq, PartialEq)]
25/// struct Rule {
26/// b: Vec<u8>,
27/// s: Vec<u8>,
28/// }
29///
30/// impl ParseNeumann for Rule {
31/// fn from_bs(b: Vec<u8>, s: Vec<u8>) -> Self {
32/// Rule { b, s }
33/// }
34/// }
35///
36/// let life = Rule::parse_rule("B2/S013V").unwrap();
37///
38/// assert_eq!(
39/// life,
40/// Rule {
41/// b: vec![2],
42/// s: vec![0, 1, 3],
43/// }
44/// )
45/// ```
46pub trait ParseNeumann {
47 /// Construct the rule from `b` / `s` data.
48 fn from_bs(b: Vec<u8>, s: Vec<u8>) -> Self;
49
50 /// The parser.
51 fn parse_rule(input: &str) -> Result<Self, ParseRuleError>
52 where
53 Self: Sized,
54 {
55 let Neumann { b, s } = Neumann::parse_rule(input)?;
56 Ok(Self::from_bs(b, s))
57 }
58}
59
60/// A trait for parsing totalistic [Generations](http://www.conwaylife.com/wiki/Generations) rules
61/// with [von Neumann neighborhood](http://www.conwaylife.com/wiki/Von_Neumann_neighbourhood).
62///
63/// The `b` / `s` data of this type of rules consists of numbers of live neighbors
64/// that cause a cell to be born / survive.
65///
66/// # Examples
67///
68/// ```
69/// use ca_rules::ParseNeumannGen;
70///
71/// #[derive(Debug, Eq, PartialEq)]
72/// struct Rule {
73/// b: Vec<u8>,
74/// s: Vec<u8>,
75/// gen: usize,
76/// }
77///
78/// impl ParseNeumannGen for Rule {
79/// fn from_bsg(b: Vec<u8>, s: Vec<u8>, gen: usize) -> Self {
80/// Rule { b, s, gen }
81/// }
82/// }
83///
84/// let life = Rule::parse_rule("B2/S013/3V").unwrap();
85///
86/// assert_eq!(
87/// life,
88/// Rule {
89/// b: vec![2],
90/// s: vec![0, 1, 3],
91/// gen: 3,
92/// }
93/// )
94/// ```
95pub trait ParseNeumannGen {
96 /// Construct the rule from `b` / `s` data and the number of states.
97 fn from_bsg(b: Vec<u8>, s: Vec<u8>, gen: usize) -> Self;
98
99 /// The parser.
100 fn parse_rule(input: &str) -> Result<Self, ParseRuleError>
101 where
102 Self: Sized,
103 {
104 let Gen {
105 rule: Neumann { b, s },
106 gen,
107 } = Neumann::parse_rule_gen(input)?;
108 Ok(Self::from_bsg(b, s, gen))
109 }
110}
111
112#[cfg(test)]
113mod tests {
114 use super::*;
115
116 struct Rule;
117
118 impl ParseNeumann for Rule {
119 fn from_bs(_b: Vec<u8>, _s: Vec<u8>) -> Self {
120 Rule
121 }
122 }
123
124 #[test]
125 fn valid_rules() -> Result<(), ParseRuleError> {
126 Rule::parse_rule("B3/S23V")?;
127 Rule::parse_rule("B3S23V")?;
128 Rule::parse_rule("b3s23v")?;
129 Rule::parse_rule("23/3V")?;
130 Rule::parse_rule("23/v")?;
131 Ok(())
132 }
133
134 #[test]
135 fn invalid_rules() {
136 assert_eq!(
137 Rule::parse_rule("B3/S23va").err(),
138 Some(ParseRuleError::ExtraJunk)
139 );
140 assert_eq!(
141 Rule::parse_rule("B3V/S23").err(),
142 Some(ParseRuleError::Missing('S'))
143 );
144 assert_eq!(
145 Rule::parse_rule("B3/S23").err(),
146 Some(ParseRuleError::Missing('V'))
147 );
148 assert_eq!(
149 Rule::parse_rule("B3/S25V").err(),
150 Some(ParseRuleError::Missing('V'))
151 );
152 assert_eq!(
153 Rule::parse_rule("233v").err(),
154 Some(ParseRuleError::Missing('/'))
155 );
156 }
157}