diff --git a/2021/Cargo.lock b/2021/Cargo.lock index 06f126a..8464c49 100644 --- a/2021/Cargo.lock +++ b/2021/Cargo.lock @@ -10,6 +10,7 @@ dependencies = [ "anyhow", "aoc-runner", "aoc-runner-derive", + "pretty_assertions", "thiserror", ] @@ -57,12 +58,49 @@ dependencies = [ "serde_json", ] +[[package]] +name = "ctor" +version = "0.1.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccc0a48a9b826acdf4028595adc9db92caea352f7af011a3034acd172a52a0aa" +dependencies = [ + "quote", + "syn", +] + +[[package]] +name = "diff" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e25ea47919b1560c4e3b7fe0aaab9becf5b84a10325ddf7db0f0ba5e1026499" + [[package]] name = "itoa" version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" +[[package]] +name = "output_vt100" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53cdc5b785b7a58c5aad8216b3dfa114df64b0b06ae6e1501cef91df2fbdf8f9" +dependencies = [ + "winapi", +] + +[[package]] +name = "pretty_assertions" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0cfe1b2403f172ba0f234e500906ee0a3e493fb81092dac23ebefe129301cc" +dependencies = [ + "ansi_term", + "ctor", + "diff", + "output_vt100", +] + [[package]] name = "proc-macro2" version = "1.0.32" diff --git a/2021/Cargo.toml b/2021/Cargo.toml index 28957a2..957d90a 100644 --- a/2021/Cargo.toml +++ b/2021/Cargo.toml @@ -10,4 +10,5 @@ ansi_term = "0.12.1" anyhow = "1.0.45" aoc-runner = "0.3.0" aoc-runner-derive = "0.3.0" +pretty_assertions = "1.0.0" thiserror = "1.0.30" diff --git a/2021/input/2021/day11.txt b/2021/input/2021/day11.txt new file mode 100644 index 0000000..7586cf4 --- /dev/null +++ b/2021/input/2021/day11.txt @@ -0,0 +1,10 @@ +7313511551 +3724855867 +2374331571 +4438213437 +6511566287 +6727245532 +3736868662 +2348138263 +2417483121 +8812617112 diff --git a/2021/src/day11.rs b/2021/src/day11.rs new file mode 100644 index 0000000..e152e79 --- /dev/null +++ b/2021/src/day11.rs @@ -0,0 +1,583 @@ +use std::{ + collections::HashSet, + convert::Infallible, + fmt::{Debug, Error, Formatter}, + num::ParseIntError, + ops::{Index, IndexMut}, + str::FromStr, +}; + +use anyhow::Result; +use aoc_runner_derive::{aoc, aoc_generator}; +use thiserror::Error; + +struct Image { + width: usize, + height: usize, + pixels: Vec, + flashes: usize, +} + +impl Image { + fn kernel3x3(&mut self, (x, y): (usize, usize), func: F) + where + F: Fn(u8) -> u8, + { + println!("flash @ ({}, {})", x, y); + if x > 0 { + self[(x - 1, y)] = func(self[(x - 1, y)]); + if y > 0 { + self[(x - 1, y - 1)] = func(self[(x - 1, y - 1)]); + } + if y < self.height - 1 { + self[(x - 1, y + 1)] = func(self[(x - 1, y + 1)]); + } + } + + if y > 0 { + self[(x, y - 1)] = func(self[(x, y - 1)]); + } + if y < self.height - 1 { + self[(x, y + 1)] = func(self[(x, y + 1)]); + } + + if x < self.width - 1 { + self[(x + 1, y)] = func(self[(x + 1, y)]); + if y > 0 { + self[(x + 1, y - 1)] = func(self[(x + 1, y - 1)]); + } + if y < self.height - 1 { + self[(x + 1, y + 1)] = func(self[(x + 1, y + 1)]); + } + } + } + + fn step(&mut self) { + self.pixels.iter_mut().for_each(|p| *p += 1); + let mut flashed: HashSet<(usize, usize)> = HashSet::new(); + loop { + let mut flashes = 0; + // Apply the effect of a flash on neighbors + dbg!(&self); + let mut need_to_flash = Vec::new(); + for y in 0..self.height { + for x in 0..self.width { + if self[(x, y)] > 9 && !flashed.contains(&(x, y)) { + need_to_flash.push((x, y)); + } + } + } + for (x, y) in need_to_flash { + self.kernel3x3((x, y), |x| x + 1); + flashed.insert((x, y)); + flashes += 1; + } + + if flashes == 0 { + break; + } + self.flashes += flashes; + } + + self.pixels.iter_mut().for_each(|p| { + if *p > 9 { + *p = 0 + } + }); + } + + fn sync(&self) -> bool { + let sentinel = self[(0, 0)]; + for p in &self.pixels { + if *p != sentinel { + return false; + } + } + true + } +} + +impl PartialEq for Image { + fn eq(&self, other: &Self) -> bool { + self.width == other.width && self.height == other.height && self.pixels == other.pixels + } +} + +impl Debug for Image { + fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> { + writeln!(f)?; + for y in 0..self.height { + for x in 0..self.width { + write!(f, "{:3}", self[(x, y)])?; + } + writeln!(f)?; + } + Ok(()) + } +} + +impl FromStr for Image { + type Err = Infallible; + + fn from_str(s: &str) -> Result { + let rows: Vec<_> = s.lines().collect(); + let width = rows[0].len(); + let height = rows.len(); + let pixels = rows + .iter() + .flat_map(|row| row.as_bytes().iter().map(|b| b - b'0')) + .collect(); + + Ok(Image { + width, + height, + pixels, + flashes: 0, + }) + } +} + +impl Index<(usize, usize)> for Image { + type Output = u8; + fn index(&self, (x, y): (usize, usize)) -> &Self::Output { + &self.pixels[x + y * self.width] + } +} + +impl IndexMut<(usize, usize)> for Image { + fn index_mut(&mut self, (x, y): (usize, usize)) -> &mut Self::Output { + &mut self.pixels[x + y * self.width] + } +} + +#[aoc(day11, part1)] +fn part1(input: &str) -> Result { + let mut im: Image = input.parse()?; + for _ in 0..100 { + im.step(); + } + if im.width > 11 { + assert!(im.flashes > 1355); + } + Ok(im.flashes) +} + +#[aoc(day11, part2)] +fn part2(input: &str) -> Result { + let mut im: Image = input.parse()?; + for i in 1.. { + im.step(); + if im.sync() { + return Ok(i); + } + } + unreachable!(); +} + +#[cfg(test)] +mod tests { + use super::*; + use pretty_assertions::{assert_eq, assert_ne}; + + #[test] + fn test_part1() -> Result<()> { + let input = r#" +5483143223 +2745854711 +5264556173 +6141336146 +6357385478 +4167524645 +2176841721 +6882881134 +4846848554 +5283751526 +"# + .trim(); + assert_eq!(part1(input)?, 1656); + Ok(()) + } + + #[test] + fn test_step() -> Result<()> { + let mut im: Image = r#" +11111 +19991 +19191 +19991 +11111 +"# + .trim() + .parse()?; + let step1: Image = r#" +34543 +40004 +50005 +40004 +34543 +"# + .trim() + .parse()?; + + let step2: Image = r#" +45654 +51115 +61116 +51115 +45654 +"# + .trim() + .parse()?; + + im.step(); + assert_eq!(im, step1); + im.step(); + assert_eq!(im, step2); + Ok(()) + } + + #[test] + fn test_many_iterations() -> Result<()> { + let mut im: Image = r#" +5483143223 +2745854711 +5264556173 +6141336146 +6357385478 +4167524645 +2176841721 +6882881134 +4846848554 +5283751526 +"# + .trim() + .parse()?; + + let step1: Image = r#" +6594254334 +3856965822 +6375667284 +7252447257 +7468496589 +5278635756 +3287952832 +7993992245 +5957959665 +6394862637 +"# + .trim() + .parse()?; + + let step2: Image = r#" +8807476555 +5089087054 +8597889608 +8485769600 +8700908800 +6600088989 +6800005943 +0000007456 +9000000876 +8700006848 +"# + .trim() + .parse()?; + + let step3: Image = r#" +0050900866 +8500800575 +9900000039 +9700000041 +9935080063 +7712300000 +7911250009 +2211130000 +0421125000 +0021119000 +"# + .trim() + .parse()?; + + let step4: Image = r#" +2263031977 +0923031697 +0032221150 +0041111163 +0076191174 +0053411122 +0042361120 +5532241122 +1532247211 +1132230211 +"# + .trim() + .parse()?; + + let step5: Image = r#" +4484144000 +2044144000 +2253333493 +1152333274 +1187303285 +1164633233 +1153472231 +6643352233 +2643358322 +2243341322 +"# + .trim() + .parse()?; + + let step6: Image = r#" +5595255111 +3155255222 +3364444605 +2263444496 +2298414396 +2275744344 +2264583342 +7754463344 +3754469433 +3354452433 +"# + .trim() + .parse()?; + + let step7: Image = r#" +6707366222 +4377366333 +4475555827 +3496655709 +3500625609 +3509955566 +3486694453 +8865585555 +4865580644 +4465574644 +"# + .trim() + .parse()?; + + let step8: Image = r#" +7818477333 +5488477444 +5697666949 +4608766830 +4734946730 +4740097688 +6900007564 +0000009666 +8000004755 +6800007755 +"# + .trim() + .parse()?; + + let step9: Image = r#" +9060000644 +7800000976 +6900000080 +5840000082 +5858000093 +6962400000 +8021250009 +2221130009 +9111128097 +7911119976 +"# + .trim() + .parse()?; + + let step10: Image = r#" +0481112976 +0031112009 +0041112504 +0081111406 +0099111306 +0093511233 +0442361130 +5532252350 +0532250600 +0032240000 +"# + .trim() + .parse()?; + let step10_flashes = 204; + + let step20: Image = r#" +3936556452 +5686556806 +4496555690 +4448655580 +4456865570 +5680086577 +7000009896 +0000000344 +6000000364 +4600009543 +"# + .trim() + .parse()?; + + let step30: Image = r#" +0643334118 +4253334611 +3374333458 +2225333337 +2229333338 +2276733333 +2754574565 +5544458511 +9444447111 +7944446119 +"# + .trim() + .parse()?; + + let step40: Image = r#" +6211111981 +0421111119 +0042111115 +0003111115 +0003111116 +0065611111 +0532351111 +3322234597 +2222222976 +2222222762 +"# + .trim() + .parse()?; + + let step50: Image = r#" +9655556447 +4865556805 +4486555690 +4458655580 +4574865570 +5700086566 +6000009887 +8000000533 +6800000633 +5680000538 +"# + .trim() + .parse()?; + + let step60: Image = r#" +2533334200 +2743334640 +2264333458 +2225333337 +2225333338 +2287833333 +3854573455 +1854458611 +1175447111 +1115446111 +"# + .trim() + .parse()?; + + let step70: Image = r#" +8211111164 +0421111166 +0042111114 +0004211115 +0000211116 +0065611111 +0532351111 +7322235117 +5722223475 +4572222754 +"# + .trim() + .parse()?; + + let step80: Image = r#" +1755555697 +5965555609 +4486555680 +4458655580 +4570865570 +5700086566 +7000008666 +0000000990 +0000000800 +0000000000 +"# + .trim() + .parse()?; + + let step90: Image = r#" +7433333522 +2643333522 +2264333458 +2226433337 +2222433338 +2287833333 +2854573333 +4854458333 +3387779333 +3333333333 +"# + .trim() + .parse()?; + + let step100: Image = r#" +0397666866 +0749766918 +0053976933 +0004297822 +0004229892 +0053222877 +0532222966 +9322228966 +7922286866 +6789998766 +"# + .trim() + .parse()?; + + im.step(); + assert_eq!(im, step1, "step1"); + im.step(); + assert_eq!(im, step2, "step2"); + im.step(); + assert_eq!(im, step3, "step3"); + im.step(); + assert_eq!(im, step4, "step4"); + im.step(); + assert_eq!(im, step5, "step5"); + im.step(); + assert_eq!(im, step6, "step6"); + im.step(); + assert_eq!(im, step7, "step7"); + im.step(); + assert_eq!(im, step8, "step8"); + im.step(); + assert_eq!(im, step9, "step9"); + im.step(); + assert_eq!(im, step10, "step10"); + assert_eq!(im.flashes, step10_flashes, "step10 wrong flashes"); + Ok(()) + } + #[test] + fn test_part2() -> Result<()> { + let input = r#" +5483143223 +2745854711 +5264556173 +6141336146 +6357385478 +4167524645 +2176841721 +6882881134 +4846848554 +5283751526 + "# + .trim(); + assert_eq!(part2(input)?, 195); + Ok(()) + } +} diff --git a/2021/src/lib.rs b/2021/src/lib.rs index 69f1578..a9465b2 100644 --- a/2021/src/lib.rs +++ b/2021/src/lib.rs @@ -1,5 +1,6 @@ pub mod day1; pub mod day10; +pub mod day11; pub mod day2; pub mod day3; pub mod day4;