1use utils::parser::ParseError;
2use utils::prelude::*;
3
4#[derive(Clone, Debug)]
6pub struct Day08 {
7 part1: u32,
8 part2: u32,
9}
10
11impl Day08 {
12 pub fn new(input: &str, _: InputType) -> Result<Self, InputError> {
13 let mut iter = parser::u32()
14 .with_consumed()
15 .with_suffix(b' '.or(parser::eof()))
16 .parse_iterator(input);
17
18 let (part1, part2) = Self::parse_node(&mut |name, min_bound, max_bound| {
19 let min_bound = min_bound.unwrap_or(0);
20 let max_bound = max_bound.unwrap_or(u32::MAX);
21 match iter.next() {
22 None => Err(InputError::new(
23 input,
24 input.len(),
25 ParseError::Expected(name),
26 )),
27 Some(Ok((n, pos))) if n < min_bound => Err(InputError::new(
28 input,
29 pos,
30 ParseError::NumberTooSmall(min_bound.into()),
31 )),
32 Some(Ok((n, pos))) if n > max_bound => Err(InputError::new(
33 input,
34 pos,
35 ParseError::NumberTooLarge(max_bound.into()),
36 )),
37 Some(Ok((n, _))) => Ok(n),
38 Some(Err(e)) => Err(e),
39 }
40 })?;
41
42 let remaining = iter.remaining();
43 if !remaining.is_empty() {
44 return Err(InputError::new(input, remaining, ParseError::ExpectedEof()));
45 }
46
47 Ok(Self { part1, part2 })
48 }
49
50 fn parse_node(
51 next: &mut impl FnMut(&'static str, Option<u32>, Option<u32>) -> Result<u32, InputError>,
52 ) -> Result<(u32, u32), InputError> {
53 let children = next("child count", None, Some(16))?;
54 let metadata = next("metadata count", Some(1), None)?;
55
56 let mut part1 = 0;
57 let mut child_values = [0; 16];
58 for i in 0..children {
59 let (p1, p2) = Self::parse_node(next)?;
60 part1 += p1;
61 child_values[i as usize] = p2;
62 }
63
64 let mut part2 = 0;
65 for _ in 0..metadata {
66 let e = next("metadata entry", None, None)?;
67 part1 += e;
68 part2 += child_values
69 .get(e.wrapping_sub(1) as usize)
70 .copied()
71 .unwrap_or(0);
72 }
73
74 if children == 0 {
75 part2 = part1;
76 }
77
78 Ok((part1, part2))
79 }
80
81 #[must_use]
82 pub fn part1(&self) -> u32 {
83 self.part1
84 }
85
86 #[must_use]
87 pub fn part2(&self) -> u32 {
88 self.part2
89 }
90}
91
92examples!(Day08 -> (u32, u32) [
93 {input: "2 3 0 3 10 11 12 1 1 0 1 99 2 1 1 2", part1: 138, part2: 66},
94]);