summaryrefslogtreecommitdiff
path: root/2024/04/rust/src/main.rs
blob: 191e4615dc4b41027f9f3a35c05d687aa48c0b92 (plain)
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
79
80
81
82
use std::io;

fn main() -> io::Result<()> {
    let grid = io::stdin()
        .lines()
        .flatten()
        .map(|line| line.chars().collect())
        .collect::<Vec<Vec<char>>>();
    let grid = Grid(grid);

    let silver: usize = silver(&grid);
    let gold: usize = gold(&grid);

    println!("silver: {silver}");
    println!("gold: {gold}");

    return Ok(());
}

struct Grid(Vec<Vec<char>>);

impl Grid {
    fn at(&self, (x, y): (isize, isize)) -> Option<&char> {
        self.0
            .get(usize::try_from(y).ok()?)?
            .get(usize::try_from(x).ok()?)
    }

    fn check<'a>(
        &self,
        (x, y): (isize, isize),
        mut pat: impl Iterator<Item = &'a ((isize, isize), char)>,
    ) -> bool {
        pat.all(|((dx, dy), ch)| self.at((x + dx, y + dy)).is_some_and(|c| c == ch))
    }

    fn pts(&self) -> impl Iterator<Item = (isize, isize)> + use<'_> {
        (0..self.0[0].len()).flat_map(|x| (0..self.0.len()).map(move |y| (x as isize, y as isize)))
    }
}

fn silver(grid: &Grid) -> usize {
    let dirs = vec![
        (-1, -1),
        (-1, 0),
        (-1, 1),
        (0, -1),
        (0, 1),
        (1, -1),
        (1, 0),
        (1, 1),
    ];

    let xmases: Vec<Vec<((isize, isize), char)>> = dirs
        .iter()
        .map(|(dx, dy)| {
            (0..4)
                .map(move |n| (dx * n, dy * n))
                .zip("XMAS".chars())
                .collect()
        })
        .collect();

    grid.pts()
        .flat_map(|p| xmases.iter().map(move |xmas| grid.check(p, xmas.iter())))
        .filter(|p| *p)
        .count()
}

fn gold(grid: &Grid) -> usize {
    let dirs = vec![(-1, -1), (1, -1), (0, 0), (-1, 1), (1, 1)];

    let xmases: Vec<Vec<((isize, isize), char)>> = vec!["MMASS", "SMASM", "SSAMM", "MSAMS"]
        .iter()
        .map(|x| dirs.clone().into_iter().zip(x.chars()).collect())
        .collect();

    grid.pts()
        .flat_map(|p| xmases.iter().map(move |xmas| grid.check(p, xmas.iter())))
        .filter(|p| *p)
        .count()
}