1use super::{
4 life::{ParseLife, ParseLifeGen},
5 nthex::{ParseNtHex, ParseNtHexGen},
6 ntneumann::{ParseNtNeumann, ParseNtNeumannGen},
7 Gen,
8};
9use crate::ParseRuleError;
10
11rule_struct!(NtLife);
12
13impl NtLife {
14 parse_bs! {
15 '0' => {
16 'c' => [0x00],
17 },
18 '1' => {
19 'c' => [0x01, 0x04, 0x20, 0x80],
20 'e' => [0x02, 0x08, 0x10, 0x40],
21 },
22 '2' => {
23 'c' => [0x05, 0x21, 0x84, 0xa0],
24 'e' => [0x0a, 0x12, 0x48, 0x50],
25 'k' => [0x0c, 0x11, 0x22, 0x30, 0x41, 0x44, 0x82, 0x88],
26 'a' => [0x03, 0x06, 0x09, 0x14, 0x28, 0x60, 0x90, 0xc0],
27 'i' => [0x18, 0x42],
28 'n' => [0x24, 0x81],
29 },
30 '3' => {
31 'c' => [0x25, 0x85, 0xa1, 0xa4],
32 'e' => [0x1a, 0x4a, 0x52, 0x58],
33 'k' => [0x32, 0x4c, 0x51, 0x8a],
34 'a' => [0x0b, 0x16, 0x68, 0xd0],
35 'i' => [0x07, 0x29, 0x94, 0xe0],
36 'n' => [0x0d, 0x15, 0x23, 0x61, 0x86, 0xa8, 0xb0, 0xc4],
37 'y' => [0x31, 0x45, 0x8c, 0xa2],
38 'q' => [0x26, 0x2c, 0x34, 0x64, 0x83, 0x89, 0x91, 0xc1],
39 'j' => [0x0e, 0x13, 0x2a, 0x49, 0x54, 0x70, 0x92, 0xc8],
40 'r' => [0x19, 0x1c, 0x38, 0x43, 0x46, 0x62, 0x98, 0xc2],
41 },
42 '4' => {
43 'c' => [0xa5],
44 'e' => [0x5a],
45 'k' => [0x33, 0x4d, 0x55, 0x71, 0x8e, 0xaa, 0xb2, 0xcc],
46 'a' => [0x0f, 0x17, 0x2b, 0x69, 0x96, 0xd4, 0xe8, 0xf0],
47 'i' => [0x1d, 0x63, 0xb8, 0xc6],
48 'n' => [0x27, 0x2d, 0x87, 0x95, 0xa9, 0xb4, 0xe1, 0xe4],
49 'y' => [0x35, 0x65, 0x8d, 0xa3, 0xa6, 0xac, 0xb1, 0xc5],
50 'q' => [0x36, 0x6c, 0x8b, 0xd1],
51 'j' => [0x3a, 0x4e, 0x53, 0x59, 0x5c, 0x72, 0x9a, 0xca],
52 'r' => [0x1b, 0x1e, 0x4b, 0x56, 0x6a, 0x78, 0xd2, 0xd8],
53 't' => [0x39, 0x47, 0x9c, 0xe2],
54 'w' => [0x2e, 0x74, 0x93, 0xc9],
55 'z' => [0x3c, 0x66, 0x99, 0xc3],
56 },
57 '5' => {
58 'c' => [0x5b, 0x5e, 0x7a, 0xda],
59 'e' => [0xa7, 0xad, 0xb5, 0xe5],
60 'k' => [0x75, 0xae, 0xb3, 0xcd],
61 'a' => [0x2f, 0x97, 0xe9, 0xf4],
62 'i' => [0x1f, 0x6b, 0xd6, 0xf8],
63 'n' => [0x3b, 0x4f, 0x57, 0x79, 0x9e, 0xdc, 0xea, 0xf2],
64 'y' => [0x5d, 0x73, 0xba, 0xce],
65 'q' => [0x3e, 0x6e, 0x76, 0x7c, 0x9b, 0xcb, 0xd3, 0xd9],
66 'j' => [0x37, 0x6d, 0x8f, 0xab, 0xb6, 0xd5, 0xec, 0xf1],
67 'r' => [0x3d, 0x67, 0x9d, 0xb9, 0xbc, 0xc7, 0xe3, 0xe6],
68 },
69 '6' => {
70 'c' => [0x5f, 0x7b, 0xde, 0xfa],
71 'e' => [0xaf, 0xb7, 0xed, 0xf5],
72 'k' => [0x77, 0x7d, 0xbb, 0xbe, 0xcf, 0xdd, 0xee, 0xf3],
73 'a' => [0x3f, 0x6f, 0x9f, 0xd7, 0xeb, 0xf6, 0xf9, 0xfc],
74 'i' => [0xbd, 0xe7],
75 'n' => [0x7e, 0xdb],
76 },
77 '7' => {
78 'c' => [0x7f, 0xdf, 0xfb, 0xfe],
79 'e' => [0xbf, 0xef, 0xf7, 0xfd],
80 },
81 '8' => {
82 'c' => [0xff],
83 },
84 }
85 parse_rule!();
86 parse_rule_map!(8);
87}
88
89impl_parser!(
90 (ParseLife, ParseLifeGen) for NtLife,
91 |i: u8| i.count_ones() as u8,
92 0xff,
93);
94
95impl_parser!(
96 (ParseNtHex, ParseNtHexGen) for NtLife,
97 |i: u8| (i & 0xc0) >> 2 | (i & 0x18) >> 1 | (i & 0x03),
98 0xff,
99);
100
101impl_parser!(
102 (ParseNtNeumann, ParseNtNeumannGen) for NtLife,
103 |i: u8| (i & 0x40) >> 3 | (i & 0x18) >> 2 | (i & 0x02) >> 1,
104 0xff,
105);
106
107pub trait ParseNtLife {
145 fn from_bs(b: Vec<u8>, s: Vec<u8>) -> Self;
147
148 fn parse_rule(input: &str) -> Result<Self, ParseRuleError>
150 where
151 Self: Sized,
152 {
153 let NtLife { b, s } = ParseLife::parse_rule(input)
154 .or_else(|_| NtLife::parse_rule(input))
155 .or_else(|e| ParseNtHex::parse_rule(input).map_err(|_| e))
156 .or_else(|e| ParseNtNeumann::parse_rule(input).map_err(|_| e))
157 .or_else(|e| {
158 NtLife::parse_rule_map(input).map_err(|e_map| {
159 if e_map == ParseRuleError::NotMapRule {
160 e
161 } else {
162 e_map
163 }
164 })
165 })?;
166 Ok(Self::from_bs(b, s))
167 }
168}
169
170pub trait ParseNtLifeGen {
210 fn from_bsg(b: Vec<u8>, s: Vec<u8>, gen: usize) -> Self;
212
213 fn parse_rule(input: &str) -> Result<Self, ParseRuleError>
215 where
216 Self: Sized,
217 {
218 let Gen {
219 rule: NtLife { b, s },
220 gen,
221 } = ParseLifeGen::parse_rule(input)
222 .or_else(|_| NtLife::parse_rule_gen(input))
223 .or_else(|e| ParseNtHexGen::parse_rule(input).map_err(|_| e))
224 .or_else(|e| ParseNtNeumannGen::parse_rule(input).map_err(|_| e))
225 .or_else(|e| {
226 NtLife::parse_rule_gen_map(input).map_err(|e_map| {
227 if e_map == ParseRuleError::NotMapRule {
228 e
229 } else {
230 e_map
231 }
232 })
233 })?;
234 Ok(Self::from_bsg(b, s, gen))
235 }
236}
237
238#[cfg(test)]
239mod tests {
240 use super::*;
241
242 struct Rule;
243
244 impl ParseNtLife for Rule {
245 fn from_bs(_b: Vec<u8>, _s: Vec<u8>) -> Self {
246 Rule
247 }
248 }
249
250 #[test]
251 fn valid_rules() -> Result<(), ParseRuleError> {
252 Rule::parse_rule("B3/S23")?;
253 Rule::parse_rule("B3/S23V")?;
254 Rule::parse_rule("B2e3-anq/S12-a3")?;
255 Rule::parse_rule("B35y/S1e2-ci3-a5i")?;
256 Rule::parse_rule("B2o3p4-o5/S2-p3p45H")?;
257 Rule::parse_rule("MAPFgFoF2gXgH5oF4B+gH4A6A")?;
258 Rule::parse_rule("B2i34cj6a7c8/S2-i3-a4ceit6in")?;
259 Rule::parse_rule("1e2cik3ejqry4anrwz5a6k/2c3aenq4aijryz5cikqr6ac8")?;
260 Rule::parse_rule("MAPARYXfhZofugWaH7oaIDogBZofuhogOiAaIDogIAAgAAWaH7oaIDogGiA6ICAAIAAaIDogIAAgACAAIAAAAAAAA")?;
261 Rule::parse_rule("MAPARYXfhZofugWaH7oaIDogBZofuhogOiAaIDogIAAgAAWaH7oaIDogGiA6ICAAIAAaIDogIAAgACAAIAAAAAAAA==")?;
262 Ok(())
263 }
264
265 #[test]
266 fn invalid_rules() {
267 assert_eq!(
268 Rule::parse_rule("12-a3/B2e3-anq").err(),
269 Some(ParseRuleError::ExtraJunk)
270 );
271 assert_eq!(
272 Rule::parse_rule("B35y/1e2-ci3-a5i").err(),
273 Some(ParseRuleError::Missing('S'))
274 );
275 assert_eq!(
276 Rule::parse_rule("B2i34cj6a7c82-i3-a4ceit6in").err(),
277 Some(ParseRuleError::Missing('S'))
278 );
279 assert_eq!(
280 Rule::parse_rule("B2c3aenq4aijryz5cikqrz6ac8/S1e2cik3ejqry4anrwz5a6k").err(),
281 Some(ParseRuleError::Missing('S'))
282 );
283 assert_eq!(
284 Rule::parse_rule("MAPARYXfhZofugWaH7oaIDogBZofuhogOiAaIDogIAAgAAWaH7oaIDogGiA6ICAAIAAaIDogIAAgACAAIA").err(),
285 Some(ParseRuleError::InvalidLength)
286 );
287 assert_eq!(
288 Rule::parse_rule("MAPARYXfhZofugWaH7oaIDogBZofuhogOiAaIDogIAAgAAWaH7oaIDogGiA6ICAAIAAaIDogIAAgACAAIAAAAAAAX").err(),
289 Some(ParseRuleError::Base64Error)
290 );
291 }
292
293 #[test]
294 fn parse_life_as_ntlife() -> Result<(), ParseRuleError> {
295 let rule: NtLife = ParseLife::parse_rule("B2/S23")?;
296 for b in 0..=0xff {
297 assert_eq!(rule.b.contains(&b), [2].contains(&b.count_ones()));
298 }
299
300 for s in 0..=0xff {
301 assert_eq!(rule.s.contains(&s), [2, 3].contains(&s.count_ones()));
302 }
303 Ok(())
304 }
305
306 #[test]
307 fn parse_hex_as_ntlife() -> Result<(), ParseRuleError> {
308 let rule: NtLife = ParseNtHex::parse_rule("B2/S34H")?;
309 for b in 0..=0xff {
310 assert_eq!(
311 rule.b.contains(&b),
312 [2].contains(&(b & 0b1101_1011).count_ones())
313 );
314 }
315
316 for s in 0..=0xff {
317 assert_eq!(
318 rule.s.contains(&s),
319 [3, 4].contains(&(s & 0b1101_1011).count_ones())
320 );
321 }
322 Ok(())
323 }
324
325 #[test]
326 fn parse_neumann_as_ntlife() -> Result<(), ParseRuleError> {
327 let rule: NtLife = ParseNtNeumann::parse_rule("B2/S013V")?;
328 for b in 0..=0xff {
329 assert_eq!(
330 rule.b.contains(&b),
331 [2].contains(&(b & 0b0101_1010).count_ones())
332 );
333 }
334
335 for s in 0..=0xff {
336 assert_eq!(
337 rule.s.contains(&s),
338 [0, 1, 3].contains(&(s & 0b0101_1010).count_ones())
339 );
340 }
341 Ok(())
342 }
343
344 #[test]
345 fn parse_map() -> Result<(), ParseRuleError> {
346 let rule1: NtLife = NtLife::parse_rule("B3/S23")?;
347 let rule2: NtLife = NtLife::parse_rule_map("MAPARYXfhZofugWaH7oaIDogBZofuhogOiAaIDogIAAgAAWaH7oaIDogGiA6ICAAIAAaIDogIAAgACAAIAAAAAAAA")?;
348 assert_eq!(rule1, rule2);
349 Ok(())
350 }
351
352 #[test]
353 fn parse_gen_map() -> Result<(), ParseRuleError> {
354 let rule1: Gen<NtLife> = NtLife::parse_rule_gen("3457/357/5")?;
355 let rule2: Gen<NtLife> = NtLife::parse_rule_gen_map("MAPARYBFxZpF38WaRd/aZZ//hZpF39pln/+aZZ//pZp/ukWaRd/aZZ//mmWf/6Waf7paZZ//pZp/umWaf7paZbplg/5")?;
356 assert_eq!(rule1, rule2);
357 Ok(())
358 }
359}