summaryrefslogtreecommitdiff
path: root/src/bin/day18.rs
blob: 36850eba4bb41ce51229279a6045fc52cd9f7f58 (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
use std::collections::HashMap;

fn main() {
    let input = advent::read_lines(18);
    println!("18a: {}", count_lights(&input, 100, false));
    println!("18b: {}", count_lights(&input, 100, true));
}

fn count_neighbors(grid: &HashMap<(isize, isize), bool>, pos: (isize, isize)) -> usize {
    let mut count = 0;
    for x in pos.0 - 1 ..= pos.0 + 1 {
        for y in pos.1 - 1 ..= pos.1 + 1 {
            if (x, y) == pos {
                continue;
            }
            if let Some(true) = grid.get(&(x, y)) {
                count += 1;
            }
        }
    }
    count
}

fn stuck_grid(grid: &mut HashMap<(isize, isize), bool>, dim: isize) {
    grid.insert((0, 0), true);
    grid.insert((dim-1, dim-1), true);
    grid.insert((0, dim-1), true);
    grid.insert((dim-1, 0), true);
}

fn step(grid: HashMap<(isize, isize), bool>, dim: usize, stuck: bool) -> HashMap<(isize, isize), bool> {
    let mut next_grid = HashMap::new();

    for y in 0 .. dim {
        for x in 0 .. dim {
            let pos = (x as isize, y as isize);
            let val = *grid.get(&pos).unwrap();
            let neighbors = count_neighbors(&grid, pos);

            let new_val = match val {
                true => [2, 3].contains(&neighbors),
                false => neighbors == 3,
            };
            next_grid.insert(pos, new_val);
        }
    }
    if stuck {
        stuck_grid(&mut next_grid, dim as isize);
    }

    next_grid
}

fn count_lights(input: &[String], steps: u16, stuck: bool) -> usize {
    let dim = input.len();

    let mut grid = HashMap::new();

    for (y, line) in input.iter().enumerate() {
        for (x, c) in line.chars().enumerate() {
            let pos = (x as isize, y as isize);
            match c {
                '#' => grid.insert(pos, true),
                '.' => grid.insert(pos, false),
                _ => unimplemented!(),
            };
        }
    }
    if stuck {
        stuck_grid(&mut grid, dim as isize);
    }

    for _ in 0 .. steps {
        grid = step(grid, dim, stuck);
    }
    grid.values().filter(|&val| *val).count()
}

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

    #[test]
    fn test() {
        let input = [
            ".#.#.#".to_string(),
            "...##.".to_string(),
            "#....#".to_string(),
            "..#...".to_string(),
            "#.#..#".to_string(),
            "####..".to_string(),
        ];
        assert_eq!(count_lights(&input, 4, false), 4);
        assert_eq!(count_lights(&input, 5, true), 17);
    }
}