year2024/
day25.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
use utils::prelude::*;

/// Finding matching keys and locks.
#[derive(Clone, Debug)]
pub struct Day25 {
    locks: Vec<u32>,
    keys: Vec<u32>,
}

const LOOKUP: [Option<bool>; 256] = {
    let mut x = [None; 256];
    x['#' as usize] = Some(true);
    x['.' as usize] = Some(false);
    x
};

impl Day25 {
    pub fn new(input: &str, _: InputType) -> Result<Self, InputError> {
        let mut locks = Vec::with_capacity(250);
        let mut keys = Vec::with_capacity(250);

        for item in parser::byte()
            .map_res(|b| LOOKUP[b as usize].ok_or("expected '.' or '#'"))
            .repeat_n::<5, _>(parser::noop())
            .repeat_n::<7, _>(parser::eol())
            .with_consumed()
            .with_suffix(parser::eol().then(parser::eol()))
            .parse_iterator(input)
        {
            let (grid, grid_str) = item?;

            let top = grid[0][0];
            let bottom = grid[6][0];
            if top == bottom
                || grid[0][1..].iter().any(|&x| x != top)
                || grid[6][1..].iter().any(|&x| x != bottom)
            {
                return Err(InputError::new(input, grid_str, "expected lock or key"));
            }

            let mask = grid[1..6]
                .as_flattened()
                .iter()
                .enumerate()
                .fold(0, |acc, (i, &x)| acc | (u32::from(x == top) << i));

            if top {
                locks.push(mask);
            } else {
                keys.push(mask);
            }
        }

        Ok(Self { locks, keys })
    }

    #[must_use]
    pub fn part1(&self) -> u32 {
        let mut total = 0;
        for &lock in &self.locks {
            for &key in &self.keys {
                if lock & key == lock {
                    total += 1;
                }
            }
        }
        total
    }

    #[must_use]
    pub fn part2(&self) -> &'static str {
        "🎄"
    }
}

examples!(Day25 -> (u32, &'static str) [
    {file: "day25_example0.txt", part1: 3},
]);