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 if a != b && a == d && b == c {
63 if in_brackets {
64 part1_valid = false;
65 } else {
66 part1_match = true;
67 }
68 }
69 }
70
71 if a != b && a == c && !part2_match {
73 let index;
74 if in_brackets {
75 index = (b - b'a') as usize * 26 + (a - b'a') as usize; part2_pairs[index] |= 1;
77 } else {
78 index = (a - b'a') as usize * 26 + (b - b'a') as usize;
79 part2_pairs[index] |= 2;
80 }
81 part2_match = part2_pairs[index] == 3;
82 }
83 }
84
85 if in_brackets {
86 return Err(InputError::new(
87 input,
88 &line[line.len()..],
89 "expected close bracket",
90 ));
91 }
92
93 if part1_valid && part1_match {
94 part1_total += 1;
95 }
96 if part2_match {
97 part2_total += 1;
98 }
99 }
100
101 Ok(Self {
102 part1: part1_total,
103 part2: part2_total,
104 })
105 }
106
107 #[must_use]
108 pub fn part1(&self) -> u32 {
109 self.part1
110 }
111
112 #[must_use]
113 pub fn part2(&self) -> u32 {
114 self.part2
115 }
116}
117
118examples!(Day07 -> (u32, u32) [
119 {input: "abba[mnop]qrst", part1: 1},
120 {input: "abcd[bddb]xyyx", part1: 0},
121 {input: "aaaa[qwer]tyui", part1: 0},
122 {input: "ioxxoj[asdfgh]zxcvbn", part1: 1},
123 {input: "aba[bab]xyz", part2: 1},
124 {input: "xyx[xyx]xyx", part2: 0},
125 {input: "aaa[kek]eke", part2: 1},
126 {input: "zazbz[bzb]cdb", part2: 1},
127]);