1use utils::parser::{ParseError, ParseResult};
2use utils::prelude::*;
3
4#[derive(Clone, Debug)]
6pub struct Day09 {
7 part1: u32,
8 part2: u32,
9}
10
11impl Day09 {
12 pub fn new(input: &str, _: InputType) -> Result<Self, InputError> {
13 let (part1, part2) = Self::parse.parse_complete(input)?;
14 Ok(Self { part1, part2 })
15 }
16
17 fn parse(mut input: &[u8]) -> ParseResult<(u32, u32)> {
19 let mut group_depth = 0;
20 let mut in_garbage = false;
21
22 let mut group_score = 0;
23 let mut garbage_count = 0;
24
25 loop {
26 input = if in_garbage {
27 match input {
28 [b'!', _, rest @ ..] => rest,
29 [b'>', rest @ ..] => {
30 in_garbage = false;
31 if group_depth == 0 {
32 return Ok(((group_score, garbage_count), rest));
33 }
34 rest
35 }
36 [_, rest @ ..] => {
37 garbage_count += 1;
38 rest
39 }
40 [] => return Err((ParseError::ExpectedByte(b'>'), input)),
41 }
42 } else {
43 match input {
44 [b'{', rest @ ..] => {
45 group_depth += 1;
46 group_score += group_depth;
47 rest
48 }
49 [b'}', rest @ ..] if group_depth > 0 => {
50 group_depth -= 1;
51 if group_depth == 0 {
52 return Ok(((group_score, garbage_count), rest));
53 }
54 rest
55 }
56 [b'<', rest @ ..] => {
57 in_garbage = true;
58 rest
59 }
60 [b',', rest @ ..] if group_depth > 0 => rest,
61 _ if group_depth > 0 => {
62 return Err((ParseError::Custom("expected '{', '}', ',' or '<'"), input))
63 }
64 _ => return Err((ParseError::Custom("expected '{' or '<'"), input)),
65 }
66 }
67 }
68 }
69
70 #[must_use]
71 pub fn part1(&self) -> u32 {
72 self.part1
73 }
74
75 #[must_use]
76 pub fn part2(&self) -> u32 {
77 self.part2
78 }
79}
80
81examples!(Day09 -> (u32, u32) [
82 {input: "{}", part1: 1},
83 {input: "{{{}}}", part1: 6},
84 {input: "{{},{}}", part1: 5},
85 {input: "{{{},{},{{}}}}", part1: 16},
86 {input: "{<a>,<a>,<a>,<a>}", part1: 1},
87 {input: "{{<ab>},{<ab>},{<ab>},{<ab>}}", part1: 9},
88 {input: "{{<!!>},{<!!>},{<!!>},{<!!>}}", part1: 9},
89 {input: "{{<a!>},{<a!>},{<a!>},{<ab>}}", part1: 3},
90 {input: "<>", part2: 0},
91 {input: "<random characters>", part2: 17},
92 {input: "<<<<>", part2: 3},
93 {input: "<{!>}>", part2: 2},
94 {input: "<!!>", part2: 0},
95 {input: "<!!!>>", part2: 0},
96 {input: "<{o\"i!a,<{i<a>", part2: 10},
97]);