1
0

Update structure of modules

This commit is contained in:
Stefan Müller
2025-12-06 00:59:48 +01:00
parent 0730ce7f01
commit e8a91164d3
6 changed files with 8 additions and 6 deletions
+123
View File
@@ -0,0 +1,123 @@
use crate::common::interval::Interval;
use std::collections::BTreeSet;
use std::fs::File;
use std::io;
use std::io::BufRead;
use std::path::Path;
pub struct Cafeteria {
part1: u64,
part2: u64,
}
impl Cafeteria {
pub fn new() -> Cafeteria {
Cafeteria { part1: 0, part2: 0 }
}
pub fn run(&mut self) {
println!("--- Day 5: Cafeteria ---");
// 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("cafeteria.txt", &paths) {
Ok(lines) => {
self.process_data(lines);
self.print_result();
}
Err(error) => eprintln!("{}", error),
};
}
fn process_data(&mut self, mut lines: io::Lines<io::BufReader<File>>) {
// Builds intervals collection.
let mut intervals: BTreeSet<Interval> = BTreeSet::new();
for line in lines
.by_ref()
.map_while(|x| x.ok().filter(|s| !s.is_empty()))
{
let values: Vec<u64> = line.split('-').map_while(|s| s.parse().ok()).collect();
let mut interval = Interval::new(values[0], values[1]);
let mut to_delete = Vec::new();
for next in intervals.range(&interval..) {
if interval.contains(next.start) || interval.end + 1 == next.start {
// New interval overlaps with the "next" interval already in the collection.
if interval.end < next.end {
interval.end = next.end;
}
to_delete.push(next.clone());
} else {
break;
}
}
let mut do_insert = true;
if let Some(prev) = intervals.range(..=&interval).next_back() {
if interval.contains(prev.end) || prev.end + 1 == interval.start {
// Enlarges new interval to replace the "previous" interval already in the collection.
interval.start = prev.start;
to_delete.push(prev.clone());
} else if interval.end <= prev.end {
do_insert = false;
}
}
for del in to_delete {
intervals.remove(&del);
}
if do_insert {
intervals.insert(interval);
}
}
// Tests values against intervals.
for value in lines.map_while(|x| x.ok()?.parse::<u64>().ok()) {
if intervals.iter().any(|interval| interval.contains(value)) {
self.part1 += 1;
}
}
self.part2 = intervals.iter().map(|x| x.len()).sum();
}
fn print_result(&self) {
println!("Part 1: {:?}\nPart 2: {:?}\n", 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 open puzzle input file, searched these paths:\n{}",
message
))
}
// This code is taken from https://doc.rust-lang.org/stable/rust-by-example/std_misc/file/read_lines.html
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())
}
+102
View File
@@ -0,0 +1,102 @@
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!("--- 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: {:?}\n", 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 open puzzle input file, searched these paths:\n{}",
message
))
}
// This code is taken from https://doc.rust-lang.org/stable/rust-by-example/std_misc/file/read_lines.html
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())
}