This commit is contained in:
Joseph Montanaro 2021-12-25 16:57:34 -08:00
parent 584cad1690
commit df55d78dec
3 changed files with 164 additions and 3 deletions

76
2021/src/day11.rs Normal file
View 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))
}

View File

@ -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(())
}
}

View File

@ -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();