1use utils::grid;
2use utils::prelude::*;
3
4#[derive(Clone, Debug)]
6pub struct Day18 {
7 data: Vec<bool>,
8 size: usize,
9 part1_steps: u32,
10 part2_steps: u32,
11}
12
13impl Day18 {
14 pub fn new(input: &str, input_type: InputType) -> Result<Self, InputError> {
15 let (rows, columns, data) = grid::parse(
16 input,
17 1,
18 false,
19 |b| b == b'#',
20 |b| b == b'#' || b == b'.',
21 |_, _| Err("expected '.' or '#'"),
22 )?;
23
24 if rows != columns {
25 return Err(InputError::new(input, input, "expected square grid"));
26 }
27
28 let (part1_steps, part2_steps) = match input_type {
29 InputType::Example => (4, 5),
30 InputType::Real => (100, 100),
31 };
32
33 Ok(Self {
34 size: rows,
35 data,
36 part1_steps,
37 part2_steps,
38 })
39 }
40
41 #[must_use]
42 pub fn part1(&self) -> u32 {
43 self.count_lights(self.part1_steps, |_| {})
44 }
45
46 #[must_use]
47 pub fn part2(&self) -> u32 {
48 let top_left = self.size + 1;
49 let top_right = self.size + (self.size - 2);
50 let bottom_left = (self.size - 2) * self.size + 1;
51 let bottom_right = (self.size - 2) * self.size + (self.size - 2);
52
53 self.count_lights(self.part2_steps, |grid| {
54 grid[top_left] = true;
55 grid[top_right] = true;
56 grid[bottom_left] = true;
57 grid[bottom_right] = true;
58 })
59 }
60
61 fn count_lights(&self, steps: u32, callback: impl Fn(&mut [bool])) -> u32 {
62 let mut grid = self.data.clone();
63 let mut grid2 = vec![false; grid.len()];
64
65 callback(&mut grid);
66
67 for _ in 0..steps {
68 self.advance(&grid, &mut grid2);
69 callback(&mut grid2);
70 (grid, grid2) = (grid2, grid);
71 }
72
73 grid.iter().copied().filter(|&x| x).count() as u32
74 }
75
76 fn advance(&self, input: &[bool], output: &mut [bool]) {
77 for (((above, row), below), out) in input
79 .chunks_exact(self.size)
80 .zip(input.chunks_exact(self.size).skip(1))
81 .zip(input.chunks_exact(self.size).skip(2))
82 .zip(output.chunks_exact_mut(self.size).skip(1))
83 {
84 for i in 1..self.size - 1 {
85 let neighbours = u8::from(above[i - 1])
86 + u8::from(above[i])
87 + u8::from(above[i + 1])
88 + u8::from(row[i - 1])
89 + u8::from(row[i + 1])
90 + u8::from(below[i - 1])
91 + u8::from(below[i])
92 + u8::from(below[i + 1]);
93 out[i] = (neighbours | u8::from(row[i])) == 3;
94 }
95 }
96 }
97}
98
99examples!(Day18 -> (u32, u32) [
100 {input: ".#.#.#\n...##.\n#....#\n..#...\n#.#..#\n####..", part1: 4, part2: 17},
101]);