day 11
This commit is contained in:
		
							
								
								
									
										76
									
								
								2021/src/day11.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										76
									
								
								2021/src/day11.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,76 @@ | |||||||
|  | use std::collections::HashSet; | ||||||
|  |  | ||||||
|  | use color_eyre::eyre; | ||||||
|  | use eyre::eyre; | ||||||
|  |  | ||||||
|  | use crate::lib::Vec2; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | struct Octopi { | ||||||
|  |     grid: Vec2<u8>, | ||||||
|  |     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<Octopi> { | ||||||
|  |     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)) | ||||||
|  | } | ||||||
| @@ -2,6 +2,7 @@ use std::io::Read; | |||||||
| use std::collections::VecDeque; | use std::collections::VecDeque; | ||||||
| use std::str::FromStr; | use std::str::FromStr; | ||||||
| use std::fs::File; | use std::fs::File; | ||||||
|  | use std::fmt::{Display, Formatter}; | ||||||
| use std::ops::{Index, IndexMut}; | use std::ops::{Index, IndexMut}; | ||||||
|  |  | ||||||
| use color_eyre::{eyre}; | use color_eyre::{eyre}; | ||||||
| @@ -108,6 +109,43 @@ pub struct Vec2<T> { | |||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | 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<Self::Item> { | ||||||
|  |         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)] | #[allow(dead_code)] | ||||||
| impl<T> Vec2<T> { | impl<T> Vec2<T> { | ||||||
|     pub fn new(columns: usize) -> Vec2<T> { |     pub fn new(columns: usize) -> Vec2<T> { | ||||||
| @@ -131,6 +169,11 @@ impl<T> Vec2<T> { | |||||||
|         (i / self.columns, i % self.columns) |         (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<Item=&[T]> { |     pub fn rows(&self) -> impl Iterator<Item=&[T]> { | ||||||
|         self.data.chunks_exact(self.columns) |         self.data.chunks_exact(self.columns) | ||||||
|     } |     } | ||||||
| @@ -142,6 +185,33 @@ impl<T> Vec2<T> { | |||||||
|     pub fn values(&self) -> impl Iterator<Item=&T> { |     pub fn values(&self) -> impl Iterator<Item=&T> { | ||||||
|         self.data.iter() |         self.data.iter() | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     pub fn values_mut(&mut self) -> impl Iterator<Item=&mut T> { | ||||||
|  |         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<T> IndexMut<usize> for Vec2<T> { | |||||||
|         &mut self.data[start..(start + self.columns)] |         &mut self.data[start..(start + self.columns)] | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | impl<T: Display> Display for Vec2<T> { | ||||||
|  |     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(()) | ||||||
|  |     } | ||||||
|  | } | ||||||
|   | |||||||
| @@ -4,14 +4,14 @@ use color_eyre::eyre; | |||||||
|  |  | ||||||
| mod lib; | mod lib; | ||||||
| use lib::load; | use lib::load; | ||||||
| mod day10; | mod day11; | ||||||
|  |  | ||||||
|  |  | ||||||
| fn main() -> eyre::Result<()> { | fn main() -> eyre::Result<()> { | ||||||
|     let data = load("data/10.txt")?; |     let data = load("data/11.txt")?; | ||||||
|  |  | ||||||
|     let start = Instant::now(); |     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 (dur, unit) = format_ns(start.elapsed().as_nanos()); | ||||||
|  |  | ||||||
|     let precision = 2.0 - dur.log10().floor(); |     let precision = 2.0 - dur.log10().floor(); | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user