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