year2016/
day04.rs

1use utils::prelude::*;
2
3/// Decrypting room names.
4#[derive(Clone, Debug)]
5pub struct Day04<'a> {
6    input: Vec<(&'a [u8], u32, &'a [u8])>,
7}
8
9impl<'a> Day04<'a> {
10    pub fn new(input: &'a str, _: InputType) -> Result<Self, InputError> {
11        let mut rooms = parser::take_while1(|&x| matches!(x, b'a'..=b'z' | b'-'))
12            .then(parser::u32())
13            .then(
14                parser::take_while1(u8::is_ascii_lowercase)
15                    .with_prefix(b'[')
16                    .with_suffix(b']'),
17            )
18            .parse_lines(input)?;
19
20        rooms.retain(|&(name, _, checksum)| {
21            let mut counts = [0; 26];
22            for &c in name {
23                if c.is_ascii_lowercase() {
24                    counts[(c - b'a') as usize] += 1;
25                }
26            }
27
28            for &c in checksum {
29                // Find the index/letter with the highest count. max_by_key(...) returns the last
30                // max element so use .rev() to get first instead, to break ties alphabetically.
31                let (letter, _) = counts
32                    .iter()
33                    .enumerate()
34                    .rev()
35                    .max_by_key(|&(_, &c)| c)
36                    .unwrap();
37
38                if c != b'a' + letter as u8 {
39                    return false;
40                }
41                counts[letter] = 0;
42            }
43
44            true
45        });
46
47        Ok(Self { input: rooms })
48    }
49
50    #[must_use]
51    pub fn part1(&self) -> u32 {
52        self.input.iter().map(|&r| r.1).sum()
53    }
54
55    #[must_use]
56    pub fn part2(&self) -> u32 {
57        const NAME: [u8; 25] = *b"northpole-object-storage-";
58
59        self.input
60            .iter()
61            .find(|&&(name, sector_id, _)| {
62                name.len() == NAME.len()
63                    && name.iter().enumerate().all(|(i, &c)| {
64                        if c == b'-' {
65                            NAME[i] == b'-'
66                        } else {
67                            ((c - b'a' + (sector_id % 26) as u8) % 26 + b'a') == NAME[i]
68                        }
69                    })
70            })
71            .unwrap()
72            .1
73    }
74}
75
76examples!(Day04<'_> -> (u32, u32) [
77    {
78        input: "aaaaa-bbb-z-y-x-123[abxyz]\n\
79            a-b-c-d-e-f-g-h-987[abcde]\n\
80            not-a-real-room-404[oarel]\n\
81            totally-real-room-200[decoy]",
82        part1: 1514,
83    },
84]);