From 05994ef2bede3bba50241ea3061b45d3f24b730d Mon Sep 17 00:00:00 2001 From: Quentin Boyer Date: Fri, 5 Dec 2025 00:03:26 +0100 Subject: [PATCH] Move the Grid type to the common library --- src/bin/day4.rs | 123 ++++++++++++++---------------------------------- src/lib.rs | 82 ++++++++++++++++++++++++++++++++ 2 files changed, 117 insertions(+), 88 deletions(-) diff --git a/src/bin/day4.rs b/src/bin/day4.rs index 05a27d4..95e1eb1 100644 --- a/src/bin/day4.rs +++ b/src/bin/day4.rs @@ -1,77 +1,27 @@ use std::time::Instant; -use aoc_2025::{load, print_res}; +use aoc_2025::{Grid, load, print_res}; use bstr::{BString, ByteSlice}; use color_eyre::eyre::ContextCompat; -type Parsed = Grid; +type Parsed = Grid; -pub struct Grid { - values: Vec, - line_len: usize, - col_len: usize, +#[derive(PartialEq, Eq)] +pub enum RollSlot { + Roll, + Space, } -impl Grid { - fn get(&self, line: isize, col: isize) -> Option { - if line < 0 || col < 0 || line as usize >= self.line_len || col as usize >= self.col_len { - None - } else { - Some(self[(line as usize, col as usize)]) - } - } - - fn neighbours(&self, line: usize, col: usize) -> usize { - let mut sum = 0; - for l in -1..=1 { - for c in -1..=1 { - if l == 0 && c == 0 { - continue; - } - - if self - .get(line as isize + l, col as isize + c) - .unwrap_or(false) - { - sum += 1 - } - } - } - sum - } -} - -impl std::ops::Index<(usize, usize)> for Grid { - type Output = bool; - - fn index(&self, (line, col): (usize, usize)) -> &Self::Output { - &self.values[line * self.line_len + col] - } -} - -impl std::ops::IndexMut<(usize, usize)> for Grid { - fn index_mut(&mut self, (line, col): (usize, usize)) -> &mut Self::Output { - &mut self.values[line * self.line_len + col] - } -} - -impl std::fmt::Display for Grid { +impl std::fmt::Display for RollSlot { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - for line in self.values.chunks_exact(self.line_len) { - line.iter().try_for_each(|v| { - write!( - f, - "{}", - match v { - true => '@', - false => '.', - } - ) - })?; - writeln!(f)?; - } - - Ok(()) + write!( + f, + "{}", + match self { + RollSlot::Roll => '@', + RollSlot::Space => '.', + } + ) } } @@ -81,30 +31,27 @@ pub fn parsing(input: &BString) -> color_eyre::Result { let values: Vec<_> = input .iter() .filter(|&&v| v != b'\n') - .map(|&v| v == b'@') + .map(|&v| { + if v == b'@' { + RollSlot::Roll + } else { + RollSlot::Space + } + }) .collect(); - assert_eq!( - values.len() % line_len, - 0, - "Line length does not divide the grid size" - ); - Ok(Grid { - line_len, - col_len: values.len() / line_len, - values, - }) + Ok(Grid::new(values, line_len)) } #[inline(never)] pub fn part1(input: Parsed) { let mut count = 0; - for line in 0..input.line_len { - for col in 0..input.line_len { - if input[(line, col)] && input.neighbours(line, col) < 4 { - count += 1; - } + for (line, col) in input.coords() { + if input[(line, col)] == RollSlot::Roll + && input.neighbour_count_like(line, col, &RollSlot::Roll) < 4 + { + count += 1; } } @@ -117,13 +64,13 @@ pub fn part2(mut input: Parsed) { loop { let mut found = false; - for line in 0..input.line_len { - for col in 0..input.line_len { - if input[(line, col)] && input.neighbours(line, col) < 4 { - input[(line, col)] = false; - found = true; - count += 1; - } + for (line, col) in input.coords() { + if input[(line, col)] == RollSlot::Roll + && input.neighbour_count_like(line, col, &RollSlot::Roll) < 4 + { + input[(line, col)] = RollSlot::Space; + found = true; + count += 1; } } diff --git a/src/lib.rs b/src/lib.rs index 7af1ebe..292986a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -6,6 +6,88 @@ use clap::Parser; pub mod tinyvec; +pub struct Grid { + values: Vec, + line_len: usize, + col_len: usize, +} + +impl Grid { + pub fn get(&self, line: isize, col: isize) -> Option<&T> { + if line < 0 || col < 0 || line as usize >= self.line_len || col as usize >= self.col_len { + None + } else { + Some(&self[(line as usize, col as usize)]) + } + } + + pub fn new(values: Vec, line_len: usize) -> Self { + assert_eq!( + values.len() % line_len, + 0, + "Line length does not divide the grid size" + ); + + Grid { + line_len, + col_len: values.len() / line_len, + values, + } + } + + pub fn coords(&self) -> impl Iterator + use { + let line_len = self.line_len; + let col_len = self.col_len; + + (0..line_len).flat_map(move |l| (0..col_len).map(move |c| (l, c))) + } +} + +impl Grid { + pub fn neighbour_count_like(&self, line: usize, col: usize, like: &T) -> usize { + let mut sum = 0; + for l in -1..=1 { + for c in -1..=1 { + if l == 0 && c == 0 { + continue; + } + + if let Some(v) = self.get(line as isize + l, col as isize + c) + && v == like + { + sum += 1 + } + } + } + sum + } +} + +impl std::ops::Index<(usize, usize)> for Grid { + type Output = T; + + fn index(&self, (line, col): (usize, usize)) -> &Self::Output { + &self.values[line * self.line_len + col] + } +} + +impl std::ops::IndexMut<(usize, usize)> for Grid { + fn index_mut(&mut self, (line, col): (usize, usize)) -> &mut Self::Output { + &mut self.values[line * self.line_len + col] + } +} + +impl std::fmt::Display for Grid { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + for line in self.values.chunks_exact(self.line_len) { + line.iter().try_for_each(|v| write!(f, "{v}"))?; + writeln!(f)?; + } + + Ok(()) + } +} + pub fn neighbours(l: usize, c: usize, map: L) -> ArrayVec<(usize, usize), 4> where L: AsRef<[C]>,