1use utils::prelude::*;
2
3#[derive(Clone, Debug)]
5pub struct Day07 {
6 part1: u32,
7 part2: u32,
8}
9
10impl Day07 {
11 pub fn new(input: &str, _: InputType) -> Result<Self, InputError> {
12 let mut part1_total = 0;
14 let mut part2_total = 0;
15
16 for line in input.lines().map(|l| l.as_bytes()) {
17 let mut part1_valid = true;
18 let mut part1_match = false;
19
20 let mut part2_pairs = [0u8; 26 * 26];
21 let mut part2_match = false;
22
23 let mut in_brackets = false;
24 for i in 0..line.len() {
25 if line[i] == b'[' {
27 if in_brackets {
28 return Err(InputError::new(
29 input,
30 &line[i..],
31 "unexpected nested bracket",
32 ));
33 }
34 in_brackets = true;
35 continue;
36 }
37
38 if line[i] == b']' {
39 if !in_brackets {
40 return Err(InputError::new(
41 input,
42 &line[i..],
43 "unexpected close bracket",
44 ));
45 }
46 in_brackets = false;
47 continue;
48 }
49
50 if !line[i].is_ascii_lowercase() {
51 return Err(InputError::new(input, &line[i..], "unexpected character"));
52 }
53
54 if i + 2 >= line.len() || !line[i + 1].is_ascii_lowercase() {
56 continue; }
58 let (a, b, c) = (line[i], line[i + 1], line[i + 2]);
59
60 if let Some(&d) = line.get(i + 3)
62 && a != b
63 && a == d
64 && b == c
65 {
66 if in_brackets {
67 part1_valid = false;
68 } else {
69 part1_match = true;
70 }
71 }
72
73 if a != b && a == c && !part2_match {
75 let index;
76 if in_brackets {
77 index = (b - b'a') as usize * 26 + (a - b'a') as usize; part2_pairs[index] |= 1;
79 } else {
80 index = (a - b'a') as usize * 26 + (b - b'a') as usize;
81 part2_pairs[index] |= 2;
82 }
83 part2_match = part2_pairs[index] == 3;
84 }
85 }
86
87 if in_brackets {
88 return Err(InputError::new(
89 input,
90 &line[line.len()..],
91 "expected close bracket",
92 ));
93 }
94
95 if part1_valid && part1_match {
96 part1_total += 1;
97 }
98 if part2_match {
99 part2_total += 1;
100 }
101 }
102
103 Ok(Self {
104 part1: part1_total,
105 part2: part2_total,
106 })
107 }
108
109 #[must_use]
110 pub fn part1(&self) -> u32 {
111 self.part1
112 }
113
114 #[must_use]
115 pub fn part2(&self) -> u32 {
116 self.part2
117 }
118}
119
120examples!(Day07 -> (u32, u32) [
121 {input: "abba[mnop]qrst", part1: 1},
122 {input: "abcd[bddb]xyyx", part1: 0},
123 {input: "aaaa[qwer]tyui", part1: 0},
124 {input: "ioxxoj[asdfgh]zxcvbn", part1: 1},
125 {input: "aba[bab]xyz", part2: 1},
126 {input: "xyx[xyx]xyx", part2: 0},
127 {input: "aaa[kek]eke", part2: 1},
128 {input: "zazbz[bzb]cdb", part2: 1},
129]);