Add solution for "Day 4: Printing Department", part 2
This commit is contained in:
@@ -1,9 +1,24 @@
|
||||
use std::ops;
|
||||
use std::str::FromStr;
|
||||
|
||||
#[derive(Hash, PartialEq, Eq, Debug, Copy, Clone)]
|
||||
pub struct Point2(pub i64, pub i64);
|
||||
|
||||
impl Point2 {
|
||||
pub const EIGHT_POINT_DIRECTIONS: &'static [Point2] = &[
|
||||
Point2(-1, -1),
|
||||
Point2(-1, 0),
|
||||
Point2(-1, 1),
|
||||
Point2(0, 1),
|
||||
Point2(1, 1),
|
||||
Point2(1, 0),
|
||||
Point2(1, -1),
|
||||
Point2(0, -1),
|
||||
];
|
||||
|
||||
pub const FORWARD_DOWN_DIRECTIONS: &'static [Point2] =
|
||||
&[Point2(-1, 1), Point2(0, 1), Point2(1, 1), Point2(1, 0)];
|
||||
|
||||
const POINT_SPLIT_CHAR: char = ',';
|
||||
|
||||
pub fn rect_area(&self, other: &Self) -> u64 {
|
||||
@@ -24,6 +39,14 @@ impl FromStr for Point2 {
|
||||
}
|
||||
}
|
||||
|
||||
impl ops::Add<&Self> for Point2 {
|
||||
type Output = Self;
|
||||
|
||||
fn add(self, rhs: &Self) -> Self {
|
||||
Self(self.0 + rhs.0, self.1 + rhs.1)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Hash, PartialEq, Eq, Debug)]
|
||||
pub struct Point3(pub i64, pub i64, pub i64);
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
use crate::common::geometry::Point2;
|
||||
use crate::solvers::Solver;
|
||||
use grid::Grid;
|
||||
use std::io::BufRead;
|
||||
@@ -6,6 +7,78 @@ pub struct PrintingDepartment {}
|
||||
|
||||
impl PrintingDepartment {
|
||||
const PAPER_ROLL_CHAR: char = '@';
|
||||
const MAX_NEIGHBORS_ACCESSIBLE: u8 = 3;
|
||||
|
||||
fn init_paper_roll_grid<R: BufRead>(&self, 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(&self, 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(
|
||||
&self,
|
||||
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 {
|
||||
@@ -13,41 +86,9 @@ impl Solver for PrintingDepartment {
|
||||
const PUZZLE_NAME: &'static str = "Printing Department";
|
||||
|
||||
fn process_data<R: BufRead>(&self, reader: R) -> (u64, u64) {
|
||||
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)
|
||||
.collect(),
|
||||
);
|
||||
}
|
||||
|
||||
let mut part1 = 0;
|
||||
'cells: for cell in grid.indexed_iter() {
|
||||
if *cell.1 {
|
||||
let mut count = 0;
|
||||
// TODO: This could be a loop over eight directions instead.
|
||||
for i in -1i32..=1 {
|
||||
for j in -1i32..=1 {
|
||||
if i != 0 || j != 0 {
|
||||
if let Some(&blocked) = grid.get(
|
||||
i32::try_from(cell.0.0).unwrap() + i,
|
||||
i32::try_from(cell.0.1).unwrap() + j,
|
||||
) {
|
||||
if blocked {
|
||||
if count <= 2 {
|
||||
count += 1;
|
||||
} else {
|
||||
continue 'cells;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
part1 += 1;
|
||||
}
|
||||
}
|
||||
(part1, 0)
|
||||
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))
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user