generated from luke-else/AdventOfCodeXXXX
feat: Completed Dat 4
All checks were successful
Continuous integration / Check (push) Successful in 40s
Continuous integration / Test Suite (push) Successful in 41s
Continuous integration / Rustfmt (push) Successful in 27s
Continuous integration / Clippy (push) Successful in 40s
Continuous integration / build (push) Successful in 39s
All checks were successful
Continuous integration / Check (push) Successful in 40s
Continuous integration / Test Suite (push) Successful in 41s
Continuous integration / Rustfmt (push) Successful in 27s
Continuous integration / Clippy (push) Successful in 40s
Continuous integration / build (push) Successful in 39s
This commit is contained in:
@@ -15,7 +15,7 @@ async fn main() -> Result<(), Box<dyn Error>> {
|
||||
Box::new(day01::Day01 {}),
|
||||
Box::new(day02::Day02 {}),
|
||||
Box::new(day03::Day03 {}),
|
||||
// Box::new(day04::Day04 {}),
|
||||
Box::new(day04::Day04 {}),
|
||||
// Box::new(day05::Day05 {}),
|
||||
// Box::new(day06::Day06 {}),
|
||||
// Box::new(day07::Day07 {}),
|
||||
|
||||
@@ -5,16 +5,54 @@ pub struct Day04 {}
|
||||
impl Solution for Day04 {
|
||||
fn part1(
|
||||
&self,
|
||||
_input: &mut Vec<String>,
|
||||
input: &mut Vec<String>,
|
||||
) -> Result<Box<dyn std::fmt::Display>, Box<dyn std::error::Error>> {
|
||||
Ok(Box::new("Ready"))
|
||||
// Convert to a 2D vector of chars
|
||||
let grid = Grid::from_input(input);
|
||||
|
||||
let mut count = 0;
|
||||
for r in 0..grid.h {
|
||||
for c in 0..grid.w {
|
||||
if grid.is_accessible(r, c) {
|
||||
count += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(Box::new(count))
|
||||
}
|
||||
|
||||
fn part2(
|
||||
&self,
|
||||
_input: &mut Vec<String>,
|
||||
input: &mut Vec<String>,
|
||||
) -> Result<Box<dyn std::fmt::Display>, Box<dyn std::error::Error>> {
|
||||
Ok(Box::new("Ready"))
|
||||
let mut grid = Grid::from_input(input);
|
||||
let mut removed_total = 0;
|
||||
|
||||
loop {
|
||||
let mut to_remove = Vec::new();
|
||||
|
||||
// Collect all accessible rolls in this pass.
|
||||
for r in 0..grid.h {
|
||||
for c in 0..grid.w {
|
||||
if grid.is_accessible(r, c) {
|
||||
to_remove.push((r, c));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If none can be removed, we're done.
|
||||
if to_remove.is_empty() {
|
||||
break;
|
||||
}
|
||||
|
||||
removed_total += to_remove.len();
|
||||
|
||||
// Remove them.
|
||||
for (r, c) in to_remove {
|
||||
grid.cells[r][c] = '.';
|
||||
}
|
||||
}
|
||||
Ok(Box::new(removed_total))
|
||||
}
|
||||
|
||||
fn get_day(&self) -> u8 {
|
||||
@@ -24,6 +62,73 @@ impl Solution for Day04 {
|
||||
|
||||
impl Day04 {}
|
||||
|
||||
/// A 2D grid representing rolls of paper (`@`) and empty space (`.`).
|
||||
///
|
||||
/// The grid keeps the raw cell data plus cached height and width
|
||||
/// to make neighbour checks simpler and avoid repeated recalculation.
|
||||
#[derive(Clone)]
|
||||
struct Grid {
|
||||
cells: Vec<Vec<char>>,
|
||||
h: usize,
|
||||
w: usize,
|
||||
}
|
||||
|
||||
impl Grid {
|
||||
/// Constructs a `Grid` from raw puzzle input.
|
||||
///
|
||||
/// Each line becomes a row, and each character becomes a cell.
|
||||
/// Assumes all lines are the same width (as per Advent of Code input).
|
||||
fn from_input(s: &[String]) -> Self {
|
||||
let cells: Vec<Vec<char>> = s.iter().map(|line| line.chars().collect()).collect();
|
||||
|
||||
let h = cells.len();
|
||||
let w = cells[0].len();
|
||||
Grid { cells, h, w }
|
||||
}
|
||||
|
||||
/// Counts the number of adjacent `@` cells around the position `(r, c)`.
|
||||
///
|
||||
/// Neighbours are the 8 surrounding cells in the Moore neighbourhood:
|
||||
/// diagonals plus orthogonals.
|
||||
/// If `(r, c)` is on an edge, out-of-bounds neighbours are ignored.
|
||||
fn count_adjacent(&self, r: usize, c: usize) -> usize {
|
||||
let dirs = [
|
||||
(-1, -1),
|
||||
(-1, 0),
|
||||
(-1, 1),
|
||||
(0, -1),
|
||||
(0, 1),
|
||||
(1, -1),
|
||||
(1, 0),
|
||||
(1, 1),
|
||||
];
|
||||
|
||||
dirs.iter()
|
||||
.filter(|(dr, dc)| {
|
||||
let nr = r as isize + dr;
|
||||
let nc = c as isize + dc;
|
||||
|
||||
nr >= 0
|
||||
&& nr < self.h as isize
|
||||
&& nc >= 0
|
||||
&& nc < self.w as isize
|
||||
&& self.cells[nr as usize][nc as usize] == '@'
|
||||
})
|
||||
.count()
|
||||
}
|
||||
|
||||
/// Determines whether a roll at `(r, c)` is accessible to a forklift.
|
||||
///
|
||||
/// A roll is accessible if:
|
||||
/// • the cell contains `@`, and
|
||||
/// • fewer than 4 of the 8 surrounding cells contain `@`.
|
||||
///
|
||||
/// This logic is shared by Part 1 and Part 2.
|
||||
fn is_accessible(&self, r: usize, c: usize) -> bool {
|
||||
self.cells[r][c] == '@' && self.count_adjacent(r, c) < 4
|
||||
}
|
||||
}
|
||||
|
||||
/// Test from puzzle input
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
@@ -61,6 +166,6 @@ mod test {
|
||||
.unwrap()
|
||||
.to_string();
|
||||
|
||||
assert_eq!(answer, "Ready");
|
||||
assert_eq!(answer, "43");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user