1
0

Add solution for "Day 4: Printing Department", part 1

This commit is contained in:
Stefan Müller
2025-12-04 23:46:44 +01:00
parent 5d32a0c219
commit 312731ce06
5 changed files with 124 additions and 1 deletions
Generated
+9
View File
@@ -5,3 +5,12 @@ version = 4
[[package]] [[package]]
name = "advent_of_code_2025" name = "advent_of_code_2025"
version = "0.1.0" version = "0.1.0"
dependencies = [
"grid",
]
[[package]]
name = "grid"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f9e2d4c0a8296178d8802098410ca05d86b17a10bb5ab559b3fb404c1f948220"
+1
View File
@@ -4,3 +4,4 @@ version = "0.1.0"
edition = "2024" edition = "2024"
[dependencies] [dependencies]
grid = "1.0.0"
+6
View File
@@ -8,6 +8,12 @@ This is a single command line application for the puzzles written in [Rust](http
This project does not contain the puzzle or example inputs as per the [copyright notice of Advent of Code](https://adventofcode.com/about). In order to run the compiled application, the puzzle inputs have to be downloaded from the [Advent of Code 2025](https://adventofcode.com/2025/) puzzle pages, and placed as text files into the `AdventOfCode2025\data` directory, e.g. `AdventOfCode2025\data\secret_entrance.txt`, or `AdventOfCode2025\data\example\secret_entrance.txt` for the unit tests. The application will output an error message with details if it cannot find an input file. This project does not contain the puzzle or example inputs as per the [copyright notice of Advent of Code](https://adventofcode.com/about). In order to run the compiled application, the puzzle inputs have to be downloaded from the [Advent of Code 2025](https://adventofcode.com/2025/) puzzle pages, and placed as text files into the `AdventOfCode2025\data` directory, e.g. `AdventOfCode2025\data\secret_entrance.txt`, or `AdventOfCode2025\data\example\secret_entrance.txt` for the unit tests. The application will output an error message with details if it cannot find an input file.
## Solutions
### Day 4: Printing Department
:mag_right: Puzzle: <https://adventofcode.com/2025/day/4>, :white_check_mark: Solver: [`PrintingDepartment`](src/printing_department.rs)
## Tests ## Tests
The package contains unit tests for each solver to help troubleshoot issues and prevent regressions. These tests cover the solutions for provided examples and full data inputs. The solutions used within the tests are user-specific. The package contains unit tests for each solver to help troubleshoot issues and prevent regressions. These tests cover the solutions for provided examples and full data inputs. The solutions used within the tests are user-specific.
+7 -1
View File
@@ -1,3 +1,9 @@
mod printing_department;
use printing_department::PrintingDepartment;
fn main() { fn main() {
println!("Hello, world!"); println!("### Advent of Code 2025 ###");
let mut solver = PrintingDepartment::new();
solver.run();
} }
+101
View File
@@ -0,0 +1,101 @@
use grid::*;
use std::fs::File;
use std::io;
use std::io::BufRead;
use std::path::Path;
pub struct PrintingDepartment {
part1: u64,
part2: u64,
}
impl PrintingDepartment {
pub fn new() -> PrintingDepartment {
PrintingDepartment { part1: 0, part2: 0 }
}
pub fn run(&mut self) {
println!("\n--- Day 4: Printing Department ---");
// The "../../data" and "../../../data" paths are useful for running the binary from
// "target/release/" directory with "data/" directory in package root or parent directory.
let paths = vec!["./data", "../data", "../../data", "../../../data"];
match read_data_file("printing_department.txt", &paths) {
Ok(lines) => {
self.process_data(lines);
self.print_result();
}
Err(error) => eprintln!("{}", error),
};
}
fn process_data(&mut self, lines: io::Lines<io::BufReader<File>>) {
let mut grid = Grid::new(0, 0);
for line in lines.map_while(Result::ok) {
grid.push_row(line.bytes().map(|c| c == b'@').collect());
}
'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;
}
}
}
}
}
}
self.part1 += 1;
}
}
}
fn print_result(&self) {
println!("Part 1: {:?}\nPart 2: {:?}", self.part1, self.part2);
}
}
fn read_data_file<T>(
filename: T,
search_paths: &Vec<T>,
) -> Result<io::Lines<io::BufReader<File>>, String>
where
T: AsRef<Path>,
{
for path in search_paths {
if let Ok(lines) = read_lines(path.as_ref().join(&filename)) {
return Ok(lines);
}
}
let message = search_paths
.iter()
.map(|path| path.as_ref().join(&filename).display().to_string())
.collect::<Vec<_>>()
.join("\n");
Err(format!(
"Cannot find puzzle input file, searched these paths:\n{}",
message
))
}
fn read_lines<T>(filename: T) -> io::Result<io::Lines<io::BufReader<File>>>
where
T: AsRef<Path>,
{
let file = File::open(filename)?;
Ok(io::BufReader::new(file).lines())
}