summaryrefslogtreecommitdiffstats
path: root/src/bin/4.rs
blob: 6fddcd624612a6703c2ff078705cdc5116869169 (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
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
use std::{
    error::Error,
    fs,
    ops::{Add, Mul},
};

#[derive(Debug, PartialEq, Eq, Copy, Clone)]
struct Point {
    pub x: i64,
    pub y: i64,
}

impl Point {
    fn new(x: i64, y: i64) -> Self {
        Self { x, y }
    }
}

impl Mul<i64> for Point {
    type Output = Self;
    fn mul(self, rhs: i64) -> Self::Output {
        Point {
            x: self.x * rhs,
            y: self.y * rhs,
        }
    }
}

impl Add<Point> for Point {
    type Output = Self;
    fn add(self, rhs: Self) -> Self::Output {
        Point {
            x: self.x + rhs.x,
            y: self.y + rhs.y,
        }
    }
}

#[derive(Debug, PartialEq, Eq, Copy, Clone)]
enum Dir {
    North,
    NorthEast,
    East,
    SouthEast,
    South,
    SouthWest,
    West,
    NorthWest,
}

impl Dir {
    const DIRS: [Dir; 8] = [
        Dir::North,
        Dir::NorthEast,
        Dir::East,
        Dir::SouthEast,
        Dir::South,
        Dir::SouthWest,
        Dir::West,
        Dir::NorthWest,
    ];
    fn grid_offset(self) -> Point {
        match self {
            Dir::North => Point::new(0, 1),
            Dir::NorthEast => Point::new(1, 1),
            Dir::East => Point::new(1, 0),
            Dir::SouthEast => Point::new(1, -1),
            Dir::South => Point::new(0, -1),
            Dir::SouthWest => Point::new(-1, -1),
            Dir::West => Point::new(-1, 0),
            Dir::NorthWest => Point::new(-1, 1),
        }
    }
}

fn index_at(board: &[&[u8]], point: Point) -> Option<u8> {
    Some(
        *board
            .get(usize::try_from(point.y).ok()?)?
            .get(usize::try_from(point.x).ok()?)?,
    )
}

fn main() -> Result<(), Box<dyn Error>> {
    let mut xmas_count = 0;
    let mut x_mas_count = 0;
    let to_find = b"XMAS";
    let input = fs::read("input/4")?;
    let input: Box<[&[u8]]> = input.trim_ascii_end().split(|e| *e == b'\n').collect();
    for y in 0..input.len() {
        for x in 0..input[y].len() {
            let p = Point::new(x as i64, y as i64);
            for d in Dir::DIRS {
                if to_find
                    .iter()
                    .copied()
                    .enumerate()
                    .all(|c| index_at(&input, p + d.grid_offset() * c.0 as i64) == Some(c.1))
                {
                    xmas_count += 1;
                }
            }
            if input[y][x] == b'A' {
                let check = |a, b| {
                    (a == Some(b'M') && b == Some(b'S')) || (a == Some(b'S') && b == Some(b'M'))
                };
                if check(
                    index_at(&input, p + Dir::NorthEast.grid_offset()),
                    index_at(&input, p + Dir::SouthWest.grid_offset()),
                ) && check(
                    index_at(&input, p + Dir::NorthWest.grid_offset()),
                    index_at(&input, p + Dir::SouthEast.grid_offset()),
                ) {
                    x_mas_count += 1;
                }
            }
        }
    }
    println!("{xmas_count}\n{x_mas_count}");
    Ok(())
}