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(&self, reader: R) -> Grid> { 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>) -> Vec { 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>, mut removables: Vec, ) -> 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(&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)) } }