91 lines
3.4 KiB
Rust
91 lines
3.4 KiB
Rust
use crate::common::geometry::Point2;
|
|
use crate::solvers::Solver;
|
|
use grid::Grid;
|
|
use std::io::BufRead;
|
|
|
|
pub struct PrintingDepartment {}
|
|
|
|
impl PrintingDepartment {
|
|
const PAPER_ROLL_CHAR: char = '@';
|
|
const MAX_NEIGHBORS_ACCESSIBLE: u8 = 3;
|
|
|
|
fn init_paper_roll_grid<R: BufRead>(reader: R) -> Grid<Option<u8>> {
|
|
let mut grid = Grid::new(0, 0);
|
|
for line in reader.lines().map_while(Result::ok) {
|
|
grid.push_row(
|
|
line.bytes()
|
|
.map(|c| (c == Self::PAPER_ROLL_CHAR as u8).then_some(0_u8))
|
|
.collect(),
|
|
);
|
|
}
|
|
grid
|
|
}
|
|
|
|
fn count_neighbors(grid: &mut Grid<Option<u8>>) -> Vec<Point2> {
|
|
let mut removables = Vec::new();
|
|
let mut location = Point2(0, 0);
|
|
// Loops over the grid.
|
|
for j in 0..grid.rows() {
|
|
location.1 = i64::try_from(j).unwrap();
|
|
for i in 0..grid.cols() {
|
|
location.0 = i64::try_from(i).unwrap();
|
|
let mut count = 0;
|
|
if grid.get(j, i).unwrap().is_some() {
|
|
// Loops only over the four neighbors that have not yet been encountered. This
|
|
// still ensures that we handle each pair of neighbors.
|
|
for direction in Point2::FORWARD_DOWN_DIRECTIONS {
|
|
if let Some(Some(other)) =
|
|
grid.get_mut(location.1 + direction.1, location.0 + direction.0)
|
|
{
|
|
*other += 1;
|
|
count += 1;
|
|
}
|
|
}
|
|
// We know that the cell is Some because of the indices of the loops, and we
|
|
// also know that the value in the cell is Some because of the enclosing "if".
|
|
let cell_count = grid.get_mut(j, i).unwrap().as_mut().unwrap();
|
|
*cell_count += count;
|
|
if *cell_count <= Self::MAX_NEIGHBORS_ACCESSIBLE {
|
|
removables.push(location);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
removables
|
|
}
|
|
|
|
fn count_removable_paper_rolls(mut grid: Grid<Option<u8>>, mut removables: Vec<Point2>) -> u64 {
|
|
// Considers everything in "removables" as already counted.
|
|
let mut result = removables.len() as u64;
|
|
while let Some(current) = removables.pop() {
|
|
// Updates the neighbors.
|
|
for direction in Point2::EIGHT_POINT_DIRECTIONS {
|
|
let neighbor = current + direction;
|
|
if let Some(Some(other)) = grid.get_mut(neighbor.1, neighbor.0) {
|
|
*other -= 1;
|
|
if *other == Self::MAX_NEIGHBORS_ACCESSIBLE {
|
|
result += 1;
|
|
removables.push(neighbor);
|
|
}
|
|
}
|
|
}
|
|
// Updates the current location.
|
|
let cell = grid.get_mut(current.1, current.0).unwrap();
|
|
*cell = None;
|
|
}
|
|
result
|
|
}
|
|
}
|
|
|
|
impl Solver for PrintingDepartment {
|
|
const PUZZLE_INDEX: u8 = 4;
|
|
const PUZZLE_NAME: &'static str = "Printing Department";
|
|
|
|
fn process_data<R: BufRead>(&self, reader: R) -> (u64, u64) {
|
|
let mut grid = Self::init_paper_roll_grid(reader);
|
|
let removables = Self::count_neighbors(&mut grid);
|
|
let part1 = removables.len() as u64;
|
|
(part1, Self::count_removable_paper_rolls(grid, removables))
|
|
}
|
|
}
|