From df55d78decc30dbb41883daaa2ed16a42ca4c794 Mon Sep 17 00:00:00 2001 From: Joseph Montanaro Date: Sat, 25 Dec 2021 16:57:34 -0800 Subject: [PATCH] day 11 --- 2021/src/day11.rs | 76 ++++++++++++++++++++++++++++++++++++++++++ 2021/src/lib.rs | 85 +++++++++++++++++++++++++++++++++++++++++++++++ 2021/src/main.rs | 6 ++-- 3 files changed, 164 insertions(+), 3 deletions(-) create mode 100644 2021/src/day11.rs diff --git a/2021/src/day11.rs b/2021/src/day11.rs new file mode 100644 index 0000000..da265ec --- /dev/null +++ b/2021/src/day11.rs @@ -0,0 +1,76 @@ +use std::collections::HashSet; + +use color_eyre::eyre; +use eyre::eyre; + +use crate::lib::Vec2; + + +struct Octopi { + grid: Vec2, + flashed: HashSet<(usize, usize)>, +} + +impl Octopi { + fn step(&mut self) -> usize { + for row in 0..self.grid.row_count() { + for col in 0..self.grid.col_count() { + self.inc(row, col); + } + } + let count = self.flashed.len(); + self.flashed.clear(); + count + } + + fn inc(&mut self, row: usize, col: usize) { + if self.flashed.contains(&(row, col)) { + return; + } + + let energy = self.grid.get_mut(row, col); + *energy += 1; + if *energy > 9 { + self.flashed.insert((row, col)); + *energy = 0; + for (n_row, n_col) in self.grid.neighbor_coords(row, col) { + self.inc(n_row, n_col); + } + } + } +} + + +fn load(data: &str) -> eyre::Result { + let mut grid = Vec2::new(10); + for line in data.lines() { + let mut row = Vec::with_capacity(10); // kinda inefficient but whatever, it only happens once + for c in line.chars() { + match c.to_digit(10) { + Some(d) => row.push(d as u8), + None => return Err(eyre!("Invalid digit: {}", c)), + } + } + grid.push(row); + } + Ok(Octopi {grid, flashed: HashSet::new()}) +} + + +pub fn run(data: &str) -> eyre::Result<(usize, usize)> { + let mut octopi = load(data)?; + + let mut num_flashes = 0; + let mut two = None; + for i in 0.. { + let n = octopi.step(); + if i < 100 { + num_flashes += n; + } + if n == 100 { + two = Some(i); + break; + } + } + Ok((num_flashes, two.unwrap() + 1)) +} diff --git a/2021/src/lib.rs b/2021/src/lib.rs index a60f344..ba532f8 100644 --- a/2021/src/lib.rs +++ b/2021/src/lib.rs @@ -2,6 +2,7 @@ use std::io::Read; use std::collections::VecDeque; use std::str::FromStr; use std::fs::File; +use std::fmt::{Display, Formatter}; use std::ops::{Index, IndexMut}; use color_eyre::{eyre}; @@ -108,6 +109,43 @@ pub struct Vec2 { } +pub struct NeighborCoords { + num_rows: usize, + num_cols: usize, + start_row: usize, + start_col: usize, + i: usize, +} + +impl Iterator for NeighborCoords { + type Item = (usize, usize); + fn next(&mut self) -> Option { + if self.i > 8 { + return None; + } + + let (rel_row, rel_col) = (self.i / 3, self.i % 3); + self.i += 1; + if rel_row == 1 && rel_col == 1 { + return self.next(); + } + + let row_offset = self.start_row + rel_row; + let col_offset = self.start_col + rel_col; + // the "neighbor window" is off by 1, so we make the comparisons off by 1 as well + if + (row_offset > 0 && row_offset <= self.num_rows + && col_offset > 0 && col_offset <= self.num_cols) + { + Some((row_offset - 1, col_offset - 1)) + } + else { + self.next() + } + } +} + + #[allow(dead_code)] impl Vec2 { pub fn new(columns: usize) -> Vec2 { @@ -131,6 +169,11 @@ impl Vec2 { (i / self.columns, i % self.columns) } + pub fn offset(&self, row: usize, col: usize) -> usize { + // and the reverse + self.columns * row + col + } + pub fn rows(&self) -> impl Iterator { self.data.chunks_exact(self.columns) } @@ -142,6 +185,33 @@ impl Vec2 { pub fn values(&self) -> impl Iterator { self.data.iter() } + + pub fn values_mut(&mut self) -> impl Iterator { + self.data.iter_mut() + } + + pub fn neighbor_coords(&self, row: usize, col: usize) -> NeighborCoords { + NeighborCoords { + num_rows: self.row_count(), + num_cols: self.col_count(), + start_row: row, + start_col: col, + i: 0, + } + } + + pub fn get(&self, row: usize, col: usize) -> &T { + &self.data[self.offset(row, col)] + } + + pub fn get_mut(&mut self, row: usize, col: usize) -> &mut T { + self.data.index_mut(self.offset(row, col)) + } + + pub fn set(&mut self, row: usize, col: usize, val: T) { + let existing = self.data.index_mut(self.offset(row, col)); + *existing = val; + } } @@ -160,3 +230,18 @@ impl IndexMut for Vec2 { &mut self.data[start..(start + self.columns)] } } + + +impl Display for Vec2 { + fn fmt(&self, f: &mut Formatter) -> std::fmt::Result { + for row in self.rows() { + write!(f, "[")?; + for (i, v) in row.iter().enumerate() { + if i > 0 {write!(f, ", ")?;} + write!(f, "{}", v)?; + } + write!(f, "]\n")?; + } + Ok(()) + } +} diff --git a/2021/src/main.rs b/2021/src/main.rs index 824a2a4..478f56f 100644 --- a/2021/src/main.rs +++ b/2021/src/main.rs @@ -4,14 +4,14 @@ use color_eyre::eyre; mod lib; use lib::load; -mod day10; +mod day11; fn main() -> eyre::Result<()> { - let data = load("data/10.txt")?; + let data = load("data/11.txt")?; let start = Instant::now(); - let (one, two) = day10::run(&data)?; + let (one, two) = day11::run(&data)?; let (dur, unit) = format_ns(start.elapsed().as_nanos()); let precision = 2.0 - dur.log10().floor();