Add Solver trait and move common functionality out of concrete solvers
This commit is contained in:
+5
-3
@@ -1,8 +1,10 @@
|
|||||||
mod solvers;
|
|
||||||
mod common;
|
mod common;
|
||||||
|
mod solvers;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
println!("### Advent of Code 2025 ###\n");
|
println!("### Advent of Code 2025 ###\n");
|
||||||
solvers::printing_department::PrintingDepartment::new().run();
|
solvers::run(Box::new(
|
||||||
solvers::cafeteria::Cafeteria::new().run();
|
solvers::printing_department::PrintingDepartment::new(),
|
||||||
|
));
|
||||||
|
solvers::run(Box::new(solvers::cafeteria::Cafeteria::new()));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,2 +1,77 @@
|
|||||||
|
use std::fs::File;
|
||||||
|
use std::io;
|
||||||
|
use std::io::BufRead;
|
||||||
|
use std::path::Path;
|
||||||
|
|
||||||
pub mod cafeteria;
|
pub mod cafeteria;
|
||||||
pub mod printing_department;
|
pub mod printing_department;
|
||||||
|
|
||||||
|
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>>);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn run(mut solver: Box<dyn Solver>) {
|
||||||
|
println!(
|
||||||
|
"--- Day {}: {} ---",
|
||||||
|
solver.get_puzzle_index(),
|
||||||
|
solver.get_puzzle_name()
|
||||||
|
);
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
}
|
||||||
|
Err(error) => eprintln!("{}", error),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn print_result(solver: Box<dyn Solver>) {
|
||||||
|
println!(
|
||||||
|
"Part 1: {:?}\nPart 2: {:?}\n",
|
||||||
|
solver.get_part1(),
|
||||||
|
solver.get_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())
|
||||||
|
}
|
||||||
|
|||||||
+17
-54
@@ -1,36 +1,30 @@
|
|||||||
use crate::common::interval::Interval;
|
use crate::common::interval::Interval;
|
||||||
|
use crate::solvers::Solver;
|
||||||
use std::collections::BTreeSet;
|
use std::collections::BTreeSet;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::io::BufRead;
|
|
||||||
use std::path::Path;
|
|
||||||
|
|
||||||
pub struct Cafeteria {
|
pub struct Cafeteria {
|
||||||
part1: u64,
|
part1: u64,
|
||||||
part2: u64,
|
part2: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Cafeteria {
|
impl Solver for Cafeteria {
|
||||||
pub fn new() -> Cafeteria {
|
fn get_puzzle_index(&self) -> u8 {
|
||||||
Cafeteria { part1: 0, part2: 0 }
|
5
|
||||||
}
|
}
|
||||||
|
fn get_puzzle_name(&self) -> &str {
|
||||||
pub fn run(&mut self) {
|
"Cafeteria"
|
||||||
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 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>>) {
|
fn process_data(&mut self, mut lines: io::Lines<io::BufReader<File>>) {
|
||||||
// Builds intervals collection.
|
// Builds intervals collection.
|
||||||
let mut intervals: BTreeSet<Interval> = BTreeSet::new();
|
let mut intervals: BTreeSet<Interval> = BTreeSet::new();
|
||||||
@@ -83,41 +77,10 @@ impl Cafeteria {
|
|||||||
|
|
||||||
self.part2 = intervals.iter().map(|x| x.len()).sum();
|
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>(
|
impl Cafeteria {
|
||||||
filename: T,
|
pub fn new() -> Cafeteria {
|
||||||
search_paths: &Vec<T>,
|
Cafeteria { part1: 0, part2: 0 }
|
||||||
) -> 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())
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,35 +1,29 @@
|
|||||||
|
use crate::solvers::Solver;
|
||||||
use grid::*;
|
use grid::*;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::io::BufRead;
|
|
||||||
use std::path::Path;
|
|
||||||
|
|
||||||
pub struct PrintingDepartment {
|
pub struct PrintingDepartment {
|
||||||
part1: u64,
|
part1: u64,
|
||||||
part2: u64,
|
part2: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PrintingDepartment {
|
impl Solver for PrintingDepartment {
|
||||||
pub fn new() -> PrintingDepartment {
|
fn get_puzzle_index(&self) -> u8 {
|
||||||
PrintingDepartment { part1: 0, part2: 0 }
|
4
|
||||||
}
|
}
|
||||||
|
fn get_puzzle_name(&self) -> &str {
|
||||||
pub fn run(&mut self) {
|
"Printing Department"
|
||||||
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 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>>) {
|
fn process_data(&mut self, lines: io::Lines<io::BufReader<File>>) {
|
||||||
let mut grid = Grid::new(0, 0);
|
let mut grid = Grid::new(0, 0);
|
||||||
for line in lines.map_while(Result::ok) {
|
for line in lines.map_while(Result::ok) {
|
||||||
@@ -62,41 +56,10 @@ impl PrintingDepartment {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn print_result(&self) {
|
|
||||||
println!("Part 1: {:?}\nPart 2: {:?}\n", self.part1, self.part2);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_data_file<T>(
|
impl PrintingDepartment {
|
||||||
filename: T,
|
pub fn new() -> PrintingDepartment {
|
||||||
search_paths: &Vec<T>,
|
PrintingDepartment { part1: 0, part2: 0 }
|
||||||
) -> 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())
|
|
||||||
}
|
|
||||||
|
|||||||
Reference in New Issue
Block a user