diff --git a/Cargo.lock b/Cargo.lock index ec033d8..c725663 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,10 +2,20 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "ansi_term" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2" +dependencies = [ + "winapi", +] + [[package]] name = "aoc21" version = "0.1.0" dependencies = [ + "ansi_term", "itertools", ] @@ -23,3 +33,25 @@ checksum = "a9a9d19fa1e79b6215ff29b9d6880b706147f16e9b1dbb1e4e5947b5b02bc5e3" dependencies = [ "either", ] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/Cargo.toml b/Cargo.toml index e2c0e6a..471ab37 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,3 +7,4 @@ edition = "2021" [dependencies] itertools = "0.10.3" +ansi_term = "0.12.1" diff --git a/input/day11.txt b/input/day11.txt new file mode 100644 index 0000000..db2a113 --- /dev/null +++ b/input/day11.txt @@ -0,0 +1,10 @@ +1553421288 +5255384882 +1224315732 +4258242274 +1658564216 +6872651182 +5775552238 +5622545172 +8766672318 +2178374835 diff --git a/src/day11.rs b/src/day11.rs new file mode 100644 index 0000000..905ab40 --- /dev/null +++ b/src/day11.rs @@ -0,0 +1,148 @@ +use ansi_term::{Color, Style}; +use std::collections::{HashSet, VecDeque}; +use std::fmt::{Debug, Formatter}; +use std::ops::RangeInclusive; + +pub fn day11() { + // let input = r#" + // 11111 + // 19991 + // 19191 + // 19991 + // 11111 + // "#; + + // let grid: Grid<5> = input.into(); + // dbg!(&grid); + // dbg!(&grid.step()); + // dbg!(&grid.step().step()); + + // let input = r#" + // 5483143223 + // 2745854711 + // 5264556173 + // 6141336146 + // 6357385478 + // 4167524645 + // 2176841721 + // 6882881134 + // 4846848554 + // 5283751526 + // "#; + let input = include_str!("../input/day11.txt"); + + let mut grid: Grid<10> = input.into(); + let mut total_flashes = 0; + + println!("{:?}", grid); + + for step in 0..100 { + let (new, flashed) = grid.step(); + // println!("after step: {}, new grid: {:?}", step + 1, new); + grid = new; + total_flashes += flashed; + } + + println!("grid: {:?}, total flashes: {}", grid, total_flashes); + + let mut grid2: Grid<10> = input.into(); + let mut step = 0; + loop { + step += 1; + let (new, flashed) = grid2.step(); + grid2 = new; + if flashed == grid.size() { + break; + } + } + println!("grid: {:?}, after step: {}", grid2, step); +} + +struct Grid { + grid: [[u32; N]; N], +} + +impl Debug for Grid { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!(f, "\n").expect("write"); + for row in 0..N { + for col in 0..N { + let mut style = Style::new(); + if self.grid[row][col] == 0 { + style = Color::White.bold(); + } + write!( + f, + "{}{}{}", + style.prefix(), + self.grid[row][col], + style.suffix() + ) + .expect("write"); + } + write!(f, "\n").expect("write"); + } + Ok(()) + } +} + +impl From<&str> for Grid { + fn from(s: &str) -> Self { + let mut grid = [[0; N]; N]; + for (row, line) in s.trim().lines().enumerate() { + for (col, c) in line.trim().chars().enumerate() { + grid[row][col] = c.to_digit(10).unwrap(); + } + } + Self { grid } + } +} + +impl Grid { + fn step(&self) -> (Grid, usize) { + let mut new_grid = [[0; N]; N]; + + for row in 0..N { + for col in 0..N { + new_grid[row][col] = self.grid[row][col] + 1; + } + } + + let mut to_flash = (0..N) + .flat_map(|row| (0..N).map(move |col| (row, col))) + .filter(|&(row, col)| new_grid[row][col] > 9) + .collect::>(); + let mut already_flashed: HashSet<(usize, usize)> = HashSet::new(); + while let Some((row, col)) = to_flash.pop_front() { + if already_flashed.contains(&(row, col)) { + continue; + } + + already_flashed.insert((row, col)); + for r in adjacent(row, N) { + for c in adjacent(col, N) { + new_grid[r][c] += 1; + if new_grid[r][c] > 9 && !already_flashed.contains(&(r, c)) { + to_flash.push_back((r, c)); + } + } + } + } + + for &(row, col) in already_flashed.iter() { + new_grid[row][col] = 0; + } + + (Self { grid: new_grid }, already_flashed.len()) + } + + fn size(&self) -> usize { + N * N + } +} + +fn adjacent(n: usize, max: usize) -> RangeInclusive { + let min = if n > 0 { n - 1 } else { n }; + let max = if n < max - 1 { n + 1 } else { n }; + min..=max +} diff --git a/src/main.rs b/src/main.rs index c90783c..05bb30f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -9,7 +9,8 @@ mod day07; mod day08; mod day09; mod day10; +mod day11; fn main() { - day10::day10(); + day11::day11(); }