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(day01::Day01 {}),
|
||||||
Box::new(day02::Day02 {}),
|
Box::new(day02::Day02 {}),
|
||||||
Box::new(day03::Day03 {}),
|
Box::new(day03::Day03 {}),
|
||||||
// Box::new(day04::Day04 {}),
|
Box::new(day04::Day04 {}),
|
||||||
// Box::new(day05::Day05 {}),
|
// Box::new(day05::Day05 {}),
|
||||||
// Box::new(day06::Day06 {}),
|
// Box::new(day06::Day06 {}),
|
||||||
// Box::new(day07::Day07 {}),
|
// Box::new(day07::Day07 {}),
|
||||||
|
|||||||
@@ -5,16 +5,54 @@ pub struct Day04 {}
|
|||||||
impl Solution for Day04 {
|
impl Solution for Day04 {
|
||||||
fn part1(
|
fn part1(
|
||||||
&self,
|
&self,
|
||||||
_input: &mut Vec<String>,
|
input: &mut Vec<String>,
|
||||||
) -> Result<Box<dyn std::fmt::Display>, Box<dyn std::error::Error>> {
|
) -> 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(
|
fn part2(
|
||||||
&self,
|
&self,
|
||||||
_input: &mut Vec<String>,
|
input: &mut Vec<String>,
|
||||||
) -> Result<Box<dyn std::fmt::Display>, Box<dyn std::error::Error>> {
|
) -> 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 {
|
fn get_day(&self) -> u8 {
|
||||||
@@ -24,6 +62,73 @@ impl Solution for Day04 {
|
|||||||
|
|
||||||
impl 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
|
/// Test from puzzle input
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
@@ -61,6 +166,6 @@ mod test {
|
|||||||
.unwrap()
|
.unwrap()
|
||||||
.to_string();
|
.to_string();
|
||||||
|
|
||||||
assert_eq!(answer, "Ready");
|
assert_eq!(answer, "43");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user