summaryrefslogtreecommitdiff
path: root/src/bin/day4.rs
blob: 768ca25baf8f3409cdce82e46beb34c13566fd52 (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
122
123
124
125
126
127
128
129
use std::collections::HashMap;

static DAY: u8 = 4;

fn main() {
    let input = advent::read_lines(DAY);
    println!("{DAY}a: {}", count_xmas(&input));
    println!("{DAY}b: {}", count_x_mas(&input));
}

fn get_letter_grid(input: &[String]) -> HashMap<(isize,isize), char> {
    let mut grid = HashMap::new();
    for (y, line) in input.iter().enumerate() {
        for (x, c) in line.chars().enumerate() {
            grid.insert((x as isize, y as isize), c);
        }
    }
    grid
}

fn word_search(grid: &HashMap<(isize,isize), char>, x: isize, y: isize, diffx: isize, diffy: isize, word: &str) -> bool {
    for (i, c) in word.chars().enumerate() {
        let i = i as isize;
        if let Some(letter) = grid.get(&(x + i*diffx, y + i*diffy)) {
            if *letter != c {
                return false;
            }
        } else {
            return false;
        }
    }
    true
}

fn word_up(grid: &HashMap<(isize,isize), char>, x: isize, y: isize, word: &str) -> bool {
    word_search(grid, x, y, 0, -1, word)
}

fn word_down(grid: &HashMap<(isize,isize), char>, x: isize, y: isize, word: &str) -> bool {
    word_search(grid, x, y, 0, 1, word)
}

fn word_left(grid: &HashMap<(isize,isize), char>, x: isize, y: isize, word: &str) -> bool {
    word_search(grid, x, y, -1, 0, word)
}

fn word_right(grid: &HashMap<(isize,isize), char>, x: isize, y: isize, word: &str) -> bool {
    word_search(grid, x, y, 1, 0, word)
}

fn word_ne(grid: &HashMap<(isize,isize), char>, x: isize, y: isize, word: &str) -> bool {
    word_search(grid, x, y, 1, -1, word)
}

fn word_se(grid: &HashMap<(isize,isize), char>, x: isize, y: isize, word: &str) -> bool {
    word_search(grid, x, y, 1, 1, word)
}

fn word_sw(grid: &HashMap<(isize,isize), char>, x: isize, y: isize, word: &str) -> bool {
    word_search(grid, x, y, -1, 1, word)
}

fn word_nw(grid: &HashMap<(isize,isize), char>, x: isize, y: isize, word: &str) -> bool {
    word_search(grid, x, y, -1, -1, word)
}

fn count_xmas(input: &[String]) -> usize {
    let grid = get_letter_grid(input);
    let max_y = input.len() as isize;
    let max_x = input[0].len() as isize;
    let mut xmas_count = 0;

    for x in 0..max_x {
        for y in 0..max_y {
            if word_up(&grid, x, y, "XMAS") { xmas_count += 1; }
            if word_down(&grid, x, y, "XMAS") { xmas_count += 1; }
            if word_left(&grid, x, y, "XMAS") { xmas_count += 1; }
            if word_right(&grid, x, y, "XMAS") { xmas_count += 1; }
            if word_ne(&grid, x, y, "XMAS") { xmas_count += 1; }
            if word_se(&grid, x, y, "XMAS") { xmas_count += 1; }
            if word_sw(&grid, x, y, "XMAS") { xmas_count += 1; }
            if word_nw(&grid, x, y, "XMAS") { xmas_count += 1; }
        }
    }

    xmas_count
}

fn count_x_mas(input: &[String]) -> usize {
    let grid = get_letter_grid(input);
    let max_y = input.len() as isize;
    let max_x = input[0].len() as isize;
    let mut xmas_count = 0;

    for x in 0..max_x {
        for y in 0..max_y {
            for word1 in ["MAS", "SAM"] {
                for word2 in ["MAS", "SAM"] {
                    if word_se(&grid, x, y, word1) && word_sw(&grid, x+2, y, word2) { xmas_count += 1; }
                }
            }
        }
    }

    xmas_count
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test() {
        let input = [
            "MMMSXXMASM",
            "MSAMXMSMSA",
            "AMXSXMAAMM",
            "MSAMASMSMX",
            "XMASAMXAMM",
            "XXAMMXXAMA",
            "SMSMSASXSS",
            "SAXAMASAAA",
            "MAMMMXMMMM",
            "MXMXAXMASX",
        ].iter().map(|&x| String::from(x)).collect::<Vec<_>>();
        assert_eq!(count_xmas(&input), 18);
        assert_eq!(count_x_mas(&input), 9);
    }
}