Refactor Solver trait to streamline usage
This commit is contained in:
+3
-5
@@ -3,9 +3,7 @@ mod solvers;
|
||||
|
||||
fn main() {
|
||||
println!("### Advent of Code 2025 ###\n");
|
||||
solvers::run(Box::new(
|
||||
solvers::printing_department::PrintingDepartment::new(),
|
||||
));
|
||||
solvers::run(Box::new(solvers::cafeteria::Cafeteria::new()));
|
||||
solvers::run(Box::new(solvers::trash_compactor::TrashCompactor::new()));
|
||||
solvers::run(solvers::printing_department::PrintingDepartment{});
|
||||
solvers::run(solvers::cafeteria::Cafeteria{});
|
||||
solvers::run(solvers::trash_compactor::TrashCompactor {});
|
||||
}
|
||||
|
||||
+25
-24
@@ -8,52 +8,53 @@ pub mod printing_department;
|
||||
pub mod trash_compactor;
|
||||
|
||||
pub trait Solver {
|
||||
fn get_puzzle_index(&self) -> u8;
|
||||
fn get_puzzle_name(&self) -> &str;
|
||||
fn get_input_filename(&self) -> &str;
|
||||
fn get_part1(&self) -> u64;
|
||||
fn get_part2(&self) -> u64;
|
||||
fn process_data(&mut self, lines: io::Lines<io::BufReader<File>>);
|
||||
const PUZZLE_INDEX: u8;
|
||||
const PUZZLE_NAME: &'static str;
|
||||
// TODO: Replace constant input filename by a conversion from the puzzle name in the runner.
|
||||
const INPUT_FILENAME: &'static str;
|
||||
|
||||
fn puzzle_index(&self) -> u8 { Self::PUZZLE_INDEX }
|
||||
fn puzzle_name(&self) -> &'static str { Self::PUZZLE_NAME }
|
||||
fn input_filename(&self) -> &'static str { Self::INPUT_FILENAME }
|
||||
|
||||
fn process_data<R: BufRead>(&self, reader: R) -> (u64, u64);
|
||||
}
|
||||
|
||||
pub fn run(mut solver: Box<dyn Solver>) {
|
||||
pub fn run<S: Solver>(solver: S) {
|
||||
println!(
|
||||
"--- Day {}: {} ---",
|
||||
solver.get_puzzle_index(),
|
||||
solver.get_puzzle_name()
|
||||
solver.puzzle_index(),
|
||||
solver.puzzle_name()
|
||||
);
|
||||
|
||||
// TODO: Convert to constant and add "example" paths.
|
||||
// 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(solver.get_input_filename(), &paths) {
|
||||
Ok(lines) => {
|
||||
solver.process_data(lines);
|
||||
print_result(solver);
|
||||
match read_data_file(solver.input_filename(), &paths) {
|
||||
Ok(reader) => {
|
||||
let result = solver.process_data(reader);
|
||||
print_result(result);
|
||||
}
|
||||
Err(error) => eprintln!("{}", error),
|
||||
};
|
||||
}
|
||||
|
||||
fn print_result(solver: Box<dyn Solver>) {
|
||||
println!(
|
||||
"Part 1: {:?}\nPart 2: {:?}\n",
|
||||
solver.get_part1(),
|
||||
solver.get_part2()
|
||||
);
|
||||
fn print_result(result: (u64, u64)) {
|
||||
println!("Part 1: {:?}\nPart 2: {:?}\n", result.0, result.1);
|
||||
}
|
||||
|
||||
fn read_data_file<T>(
|
||||
filename: T,
|
||||
search_paths: &Vec<T>,
|
||||
) -> Result<io::Lines<io::BufReader<File>>, String>
|
||||
) -> Result<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);
|
||||
if let Ok(reader) = read_file(path.as_ref().join(&filename)) {
|
||||
return Ok(reader);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,10 +70,10 @@ where
|
||||
}
|
||||
|
||||
// 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>>>
|
||||
fn read_file<T>(filename: T) -> io::Result<io::BufReader<File>>
|
||||
where
|
||||
T: AsRef<Path>,
|
||||
{
|
||||
let file = File::open(filename)?;
|
||||
Ok(io::BufReader::new(file).lines())
|
||||
Ok(io::BufReader::new(file))
|
||||
}
|
||||
|
||||
+12
-33
@@ -1,35 +1,19 @@
|
||||
use crate::common::interval::Interval;
|
||||
use crate::solvers::Solver;
|
||||
use std::collections::BTreeSet;
|
||||
use std::fs::File;
|
||||
use std::io;
|
||||
use std::io::BufRead;
|
||||
|
||||
pub struct Cafeteria {
|
||||
part1: u64,
|
||||
part2: u64,
|
||||
}
|
||||
pub struct Cafeteria {}
|
||||
|
||||
impl Solver for Cafeteria {
|
||||
fn get_puzzle_index(&self) -> u8 {
|
||||
5
|
||||
}
|
||||
fn get_puzzle_name(&self) -> &str {
|
||||
"Cafeteria"
|
||||
}
|
||||
fn get_input_filename(&self) -> &str {
|
||||
"cafeteria.txt"
|
||||
}
|
||||
fn get_part1(&self) -> u64 {
|
||||
self.part1
|
||||
}
|
||||
fn get_part2(&self) -> u64 {
|
||||
self.part2
|
||||
}
|
||||
fn process_data(&mut self, mut lines: io::Lines<io::BufReader<File>>) {
|
||||
const PUZZLE_INDEX: u8 = 5;
|
||||
const PUZZLE_NAME: &'static str = "Cafeteria";
|
||||
const INPUT_FILENAME: &'static str = "cafeteria.txt";
|
||||
|
||||
fn process_data<R: BufRead>(&self, mut reader: R) -> (u64, u64) {
|
||||
// Builds intervals collection.
|
||||
let mut intervals: BTreeSet<Interval> = BTreeSet::new();
|
||||
for line in lines
|
||||
.by_ref()
|
||||
for line in reader.by_ref().lines()
|
||||
.map_while(|x| x.ok().filter(|s| !s.is_empty()))
|
||||
{
|
||||
let values: Vec<u64> = line.split('-').map_while(|s| s.parse().ok()).collect();
|
||||
@@ -68,19 +52,14 @@ impl Solver for Cafeteria {
|
||||
}
|
||||
}
|
||||
|
||||
let mut part1 = 0;
|
||||
// Tests values against intervals.
|
||||
for value in lines.map_while(|x| x.ok()?.parse::<u64>().ok()) {
|
||||
for value in reader.lines().map_while(|x| x.ok()?.parse::<u64>().ok()) {
|
||||
if intervals.iter().any(|interval| interval.contains(value)) {
|
||||
self.part1 += 1;
|
||||
part1 += 1;
|
||||
}
|
||||
}
|
||||
|
||||
self.part2 = intervals.iter().map(|x| x.len()).sum();
|
||||
}
|
||||
}
|
||||
|
||||
impl Cafeteria {
|
||||
pub fn new() -> Cafeteria {
|
||||
Cafeteria { part1: 0, part2: 0 }
|
||||
(part1, intervals.iter().map(|x| x.len()).sum())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,35 +1,21 @@
|
||||
use crate::solvers::Solver;
|
||||
use grid::*;
|
||||
use std::fs::File;
|
||||
use std::io;
|
||||
use std::io::BufRead;
|
||||
|
||||
pub struct PrintingDepartment {
|
||||
part1: u64,
|
||||
part2: u64,
|
||||
}
|
||||
pub struct PrintingDepartment {}
|
||||
|
||||
impl Solver for PrintingDepartment {
|
||||
fn get_puzzle_index(&self) -> u8 {
|
||||
4
|
||||
}
|
||||
fn get_puzzle_name(&self) -> &str {
|
||||
"Printing Department"
|
||||
}
|
||||
fn get_input_filename(&self) -> &str {
|
||||
"printing_department.txt"
|
||||
}
|
||||
fn get_part1(&self) -> u64 {
|
||||
self.part1
|
||||
}
|
||||
fn get_part2(&self) -> u64 {
|
||||
self.part2
|
||||
}
|
||||
fn process_data(&mut self, lines: io::Lines<io::BufReader<File>>) {
|
||||
const PUZZLE_INDEX: u8 = 4;
|
||||
const PUZZLE_NAME: &'static str = "Printing Department";
|
||||
const INPUT_FILENAME: &'static str = "printing_department.txt";
|
||||
|
||||
fn process_data<R: BufRead>(&self, reader: R) -> (u64, u64) {
|
||||
let mut grid = Grid::new(0, 0);
|
||||
for line in lines.map_while(Result::ok) {
|
||||
for line in reader.lines().map_while(Result::ok) {
|
||||
grid.push_row(line.bytes().map(|c| c == b'@').collect());
|
||||
}
|
||||
|
||||
let mut part1 = 0;
|
||||
'cells: for cell in grid.indexed_iter() {
|
||||
if *cell.1 {
|
||||
let mut count = 0;
|
||||
@@ -52,14 +38,9 @@ impl Solver for PrintingDepartment {
|
||||
}
|
||||
}
|
||||
}
|
||||
self.part1 += 1;
|
||||
part1 += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PrintingDepartment {
|
||||
pub fn new() -> PrintingDepartment {
|
||||
PrintingDepartment { part1: 0, part2: 0 }
|
||||
(part1, 0)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,51 +1,32 @@
|
||||
use crate::solvers::Solver;
|
||||
use grid::*;
|
||||
use std::fs::File;
|
||||
use std::io;
|
||||
use std::io::BufRead;
|
||||
|
||||
pub struct TrashCompactor {
|
||||
part1: u64,
|
||||
part2: u64,
|
||||
}
|
||||
pub struct TrashCompactor {}
|
||||
|
||||
impl Solver for TrashCompactor {
|
||||
fn get_puzzle_index(&self) -> u8 {
|
||||
6
|
||||
}
|
||||
fn get_puzzle_name(&self) -> &str {
|
||||
"Trash Compactor"
|
||||
}
|
||||
fn get_input_filename(&self) -> &str {
|
||||
"trash_compactor.txt"
|
||||
}
|
||||
fn get_part1(&self) -> u64 {
|
||||
self.part1
|
||||
}
|
||||
fn get_part2(&self) -> u64 {
|
||||
self.part2
|
||||
}
|
||||
fn process_data(&mut self, lines: io::Lines<io::BufReader<File>>) {
|
||||
const PUZZLE_INDEX: u8 = 6;
|
||||
const PUZZLE_NAME: &'static str = "Trash Compactor";
|
||||
const INPUT_FILENAME: &'static str = "trash_compactor.txt";
|
||||
|
||||
fn process_data<R: BufRead>(&self, reader: R) -> (u64, u64) {
|
||||
let mut part1 = 0;
|
||||
let mut grid = Grid::new(0, 0);
|
||||
for line in lines.map_while(Result::ok) {
|
||||
for line in reader.lines().map_while(Result::ok) {
|
||||
let v: Vec<&str> = line.split(' ').filter(|s| !s.is_empty()).collect();
|
||||
match v[0].parse::<u32>() {
|
||||
Ok(_) => grid.push_row(v.iter().map(|n| n.parse::<u64>().unwrap()).collect()),
|
||||
Err(_) => {
|
||||
for (i, sign) in v.iter().enumerate() {
|
||||
if *sign == "+" {
|
||||
self.part1 += grid.iter_col(i).sum::<u64>();
|
||||
part1 += grid.iter_col(i).sum::<u64>();
|
||||
} else {
|
||||
self.part1 += grid.iter_col(i).product::<u64>();
|
||||
part1 += grid.iter_col(i).product::<u64>();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TrashCompactor {
|
||||
pub fn new() -> TrashCompactor {
|
||||
TrashCompactor { part1: 0, part2: 0 }
|
||||
(part1, 0)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user