advent_of_code/year2021/
day11.rs1use crate::input::Input;
2
3pub fn solve(input: &Input) -> Result<u64, String> {
4 const MAX_STEPS_PART_TWO: usize = 100_000;
5
6 let mut board = Board::parse(input.text)?;
7
8 for step in 1..=input.part_values(100, MAX_STEPS_PART_TWO) {
9 let before = board.num_flashes;
10
11 board.advance();
12
13 if input.is_part_two() && (board.num_flashes - before) == 100 {
14 return Ok(step as u64);
15 }
16 }
17
18 if input.is_part_two() {
19 return Err(format!(
20 "No simultaneous flash within {MAX_STEPS_PART_TWO} steps"
21 ));
22 }
23
24 Ok(board.num_flashes)
25}
26
27struct Board {
28 cells: [u8; Self::WIDTH * Self::WIDTH],
29 num_flashes: u64,
30}
31
32impl Board {
33 const WIDTH: usize = 10;
34
35 fn parse(s: &str) -> Result<Self, String> {
36 let mut board = Self {
37 cells: [0; Self::WIDTH * Self::WIDTH],
38 num_flashes: 0,
39 };
40
41 if s.lines().count() != 10 {
42 return Err("Board is not 10 rows".to_string());
43 }
44
45 for (y, line) in s.lines().enumerate() {
46 if line.len() != 10 {
47 return Err("Not every row in the board is 10 wide".to_string());
48 }
49 for (x, b) in line.bytes().enumerate() {
50 if !b.is_ascii_digit() {
51 return Err("Not every character is an ASCII digit".to_string());
52 }
53 board.set(x, y, b - b'0');
54 }
55 }
56
57 Ok(board)
58 }
59
60 const fn at(&self, x: usize, y: usize) -> u8 {
61 self.cells[x + (y * Self::WIDTH)]
62 }
63
64 fn set(&mut self, x: usize, y: usize, value: u8) {
65 self.cells[x + (y * Self::WIDTH)] = value;
66 }
67
68 fn bump(&mut self, x: usize, y: usize) {
69 let current_value = self.at(x, y);
70 if current_value == 0 {
71 return;
72 }
73
74 self.set(x, y, current_value + 1);
75
76 if current_value + 1 > 9 {
77 self.set(x, y, 0);
78 self.num_flashes += 1;
79
80 for dy in -1..=1 {
81 for dx in -1..=1 {
82 if (dx, dy) != (0, 0) {
83 let n_x = x as i32 + dx;
84 let n_y = y as i32 + dy;
85 if (0..10).contains(&n_x) && (0..10).contains(&n_y) {
86 self.bump(n_x as usize, n_y as usize);
87 }
88 }
89 }
90 }
91 }
92 }
93
94 fn advance(&mut self) {
95 self.cells.iter_mut().for_each(|c| *c += 1);
96
97 for y in 0..10 {
98 for x in 0..10 {
99 if self.at(x, y) > 9 {
100 self.bump(x, y);
101 }
102 }
103 }
104 }
105}
106
107#[test]
108pub fn tests() {
109 use crate::input::{test_part_one, test_part_two};
110
111 let example = "5483143223
1122745854711
1135264556173
1146141336146
1156357385478
1164167524645
1172176841721
1186882881134
1194846848554
1205283751526";
121 test_part_one!(example => 1656);
122 test_part_two!(example => 195);
123
124 let real_input = include_str!("day11_input.txt");
125 test_part_one!(real_input => 1546);
126 test_part_two!(real_input => 471);
127}