year2024/
day25.rs

1use utils::prelude::*;
2
3/// Finding matching keys and locks.
4#[derive(Clone, Debug)]
5pub struct Day25 {
6    locks: Vec<u32>,
7    keys: Vec<u32>,
8}
9
10impl Day25 {
11    pub fn new(input: &str, _: InputType) -> Result<Self, InputError> {
12        let mut locks = Vec::with_capacity(250);
13        let mut keys = Vec::with_capacity(250);
14
15        for item in parser::byte_map!(b'#' => true, b'.' => false)
16            .repeat_n::<5, _>(parser::noop())
17            .repeat_n::<7, _>(parser::eol())
18            .with_consumed()
19            .with_suffix(parser::eol().then(parser::eol()))
20            .parse_iterator(input)
21        {
22            let (grid, grid_str) = item?;
23
24            let top = grid[0][0];
25            let bottom = grid[6][0];
26            if top == bottom
27                || grid[0][1..].iter().any(|&x| x != top)
28                || grid[6][1..].iter().any(|&x| x != bottom)
29            {
30                return Err(InputError::new(input, grid_str, "expected lock or key"));
31            }
32
33            let mask = grid[1..6]
34                .as_flattened()
35                .iter()
36                .enumerate()
37                .fold(0, |acc, (i, &x)| acc | (u32::from(x == top) << i));
38
39            if top {
40                locks.push(mask);
41            } else {
42                keys.push(mask);
43            }
44        }
45
46        Ok(Self { locks, keys })
47    }
48
49    #[must_use]
50    pub fn part1(&self) -> u32 {
51        let mut total = 0;
52        for &lock in &self.locks {
53            for &key in &self.keys {
54                if lock & key == lock {
55                    total += 1;
56                }
57            }
58        }
59        total
60    }
61
62    #[must_use]
63    pub fn part2(&self) -> &'static str {
64        "🎄"
65    }
66}
67
68examples!(Day25 -> (u32, &'static str) [
69    {file: "day25_example0.txt", part1: 3},
70]);