Skip to main content

year2020/
day02.rs

1use utils::prelude::*;
2
3/// Counting valid passwords.
4#[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]);