1use utils::prelude::*;
2
3#[derive(Clone, Debug)]
5pub struct Day02 {
6 part1: usize,
7 part2: usize,
8}
9
10impl Day02 {
11 pub fn new(input: &str, _: InputType) -> Result<Self, InputError> {
12 let entry = parser::nonzero_u32()
13 .with_suffix(b'-')
14 .then(parser::nonzero_u32().with_suffix(b' '))
15 .then(parser::byte_range(b'a'..=b'z').with_suffix(": "))
16 .then(parser::take_while1(u8::is_ascii_lowercase))
17 .with_consumed()
18 .with_eol();
19
20 let (mut part1, mut part2) = (0, 0);
21 for entry in entry.parse_iterator(input) {
22 let ((min, max, letter, password), line) = entry?;
23 let (min, max) = (min.get() as usize, max.get() as usize);
24
25 if min >= max {
26 return Err(InputError::new(
27 input,
28 line,
29 "expected min to be less than max",
30 ));
31 }
32 if max > password.len() {
33 return Err(InputError::new(
34 input,
35 line,
36 "expected max to be less than password length",
37 ));
38 }
39
40 let count = password.iter().filter(|&&b| b == letter).count();
41 part1 += usize::from((min..=max).contains(&count));
42
43 let first = password[min - 1];
44 let second = password[max - 1];
45 part2 += usize::from((first == letter) != (second == letter));
46 }
47
48 Ok(Self { part1, part2 })
49 }
50
51 #[must_use]
52 pub fn part1(&self) -> usize {
53 self.part1
54 }
55
56 #[must_use]
57 pub fn part2(&self) -> usize {
58 self.part2
59 }
60}
61
62examples!(Day02 -> (usize, usize) [
63 {input: "1-3 a: abcde\n1-3 b: cdefg\n2-9 c: ccccccccc", part1: 2, part2: 1},
64]);