Move the Grid type to the common library

This commit is contained in:
Quentin Boyer 2025-12-05 00:03:26 +01:00
parent 92a66b3d5f
commit 05994ef2be
2 changed files with 117 additions and 88 deletions

View file

@ -1,77 +1,27 @@
use std::time::Instant; use std::time::Instant;
use aoc_2025::{load, print_res}; use aoc_2025::{Grid, load, print_res};
use bstr::{BString, ByteSlice}; use bstr::{BString, ByteSlice};
use color_eyre::eyre::ContextCompat; use color_eyre::eyre::ContextCompat;
type Parsed = Grid; type Parsed = Grid<RollSlot>;
pub struct Grid { #[derive(PartialEq, Eq)]
values: Vec<bool>, pub enum RollSlot {
line_len: usize, Roll,
col_len: usize, Space,
} }
impl Grid { impl std::fmt::Display for RollSlot {
fn get(&self, line: isize, col: isize) -> Option<bool> {
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 {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
for line in self.values.chunks_exact(self.line_len) { write!(
line.iter().try_for_each(|v| { f,
write!( "{}",
f, match self {
"{}", RollSlot::Roll => '@',
match v { RollSlot::Space => '.',
true => '@', }
false => '.', )
}
)
})?;
writeln!(f)?;
}
Ok(())
} }
} }
@ -81,30 +31,27 @@ pub fn parsing(input: &BString) -> color_eyre::Result<Parsed> {
let values: Vec<_> = input let values: Vec<_> = input
.iter() .iter()
.filter(|&&v| v != b'\n') .filter(|&&v| v != b'\n')
.map(|&v| v == b'@') .map(|&v| {
if v == b'@' {
RollSlot::Roll
} else {
RollSlot::Space
}
})
.collect(); .collect();
assert_eq!( Ok(Grid::new(values, line_len))
values.len() % line_len,
0,
"Line length does not divide the grid size"
);
Ok(Grid {
line_len,
col_len: values.len() / line_len,
values,
})
} }
#[inline(never)] #[inline(never)]
pub fn part1(input: Parsed) { pub fn part1(input: Parsed) {
let mut count = 0; let mut count = 0;
for line in 0..input.line_len { for (line, col) in input.coords() {
for col in 0..input.line_len { if input[(line, col)] == RollSlot::Roll
if input[(line, col)] && input.neighbours(line, col) < 4 { && input.neighbour_count_like(line, col, &RollSlot::Roll) < 4
count += 1; {
} count += 1;
} }
} }
@ -117,13 +64,13 @@ pub fn part2(mut input: Parsed) {
loop { loop {
let mut found = false; let mut found = false;
for line in 0..input.line_len { for (line, col) in input.coords() {
for col in 0..input.line_len { if input[(line, col)] == RollSlot::Roll
if input[(line, col)] && input.neighbours(line, col) < 4 { && input.neighbour_count_like(line, col, &RollSlot::Roll) < 4
input[(line, col)] = false; {
found = true; input[(line, col)] = RollSlot::Space;
count += 1; found = true;
} count += 1;
} }
} }

View file

@ -6,6 +6,88 @@ use clap::Parser;
pub mod tinyvec; pub mod tinyvec;
pub struct Grid<T> {
values: Vec<T>,
line_len: usize,
col_len: usize,
}
impl<T> Grid<T> {
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<T>, 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<Item = (usize, usize)> + use<T> {
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<T: PartialEq + Eq> Grid<T> {
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<T> std::ops::Index<(usize, usize)> for Grid<T> {
type Output = T;
fn index(&self, (line, col): (usize, usize)) -> &Self::Output {
&self.values[line * self.line_len + col]
}
}
impl<T> std::ops::IndexMut<(usize, usize)> for Grid<T> {
fn index_mut(&mut self, (line, col): (usize, usize)) -> &mut Self::Output {
&mut self.values[line * self.line_len + col]
}
}
impl<T: std::fmt::Display> std::fmt::Display for Grid<T> {
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, C, T>(l: usize, c: usize, map: L) -> ArrayVec<(usize, usize), 4> pub fn neighbours<L, C, T>(l: usize, c: usize, map: L) -> ArrayVec<(usize, usize), 4>
where where
L: AsRef<[C]>, L: AsRef<[C]>,