99 lines
2.5 KiB
Rust
99 lines
2.5 KiB
Rust
use sanitise_file_name;
|
|
use std::fs::File;
|
|
use std::io;
|
|
use std::io::BufRead;
|
|
use std::path;
|
|
use std::path::Path;
|
|
|
|
pub mod cafeteria;
|
|
pub mod gift_shop;
|
|
pub mod laboratories;
|
|
pub mod lobby;
|
|
pub mod movie_theater;
|
|
pub mod playground;
|
|
pub mod printing_department;
|
|
pub mod secret_entrance;
|
|
pub mod trash_compactor;
|
|
|
|
pub trait Solver {
|
|
const PUZZLE_INDEX: u8;
|
|
const PUZZLE_NAME: &'static str;
|
|
|
|
fn puzzle_index(&self) -> u8 {
|
|
Self::PUZZLE_INDEX
|
|
}
|
|
fn puzzle_name(&self) -> &'static str {
|
|
Self::PUZZLE_NAME
|
|
}
|
|
|
|
fn process_data<R: BufRead>(&self, reader: R) -> (u64, u64);
|
|
}
|
|
|
|
// The "../../data" and "../../../data" paths are useful for running the binary from
|
|
// "target/release/" directory with "data/" directory in package root or parent directory.
|
|
pub const DATA_PATHS: &'static [&'static str] =
|
|
&["./data", "../data", "../../data", "../../../data"];
|
|
|
|
pub fn run<S: Solver>(solver: S) {
|
|
println!(
|
|
"--- Day {}: {} ---",
|
|
solver.puzzle_index(),
|
|
solver.puzzle_name()
|
|
);
|
|
|
|
match run_solver(solver, &DATA_PATHS) {
|
|
Ok(result) => print_result(result),
|
|
Err(error) => eprintln!("{}", error),
|
|
}
|
|
}
|
|
|
|
pub fn run_solver<S: Solver>(solver: S, paths: &[&str]) -> Result<(u64, u64), String> {
|
|
let reader = read_data_file(input_filename(solver.puzzle_name()), paths)?;
|
|
Ok(solver.process_data(reader))
|
|
}
|
|
|
|
fn input_filename(puzzle_name: &str) -> String {
|
|
sanitise_file_name::sanitise(puzzle_name)
|
|
.to_lowercase()
|
|
.replace(" ", "_")
|
|
+ ".txt"
|
|
}
|
|
|
|
fn print_result(result: (u64, u64)) {
|
|
println!("Part 1: {:?}\nPart 2: {:?}\n", result.0, result.1);
|
|
}
|
|
|
|
fn read_data_file<T>(filename: String, search_paths: &[T]) -> Result<io::BufReader<File>, String>
|
|
where
|
|
T: AsRef<Path>,
|
|
{
|
|
for path in search_paths {
|
|
if let Ok(reader) = read_file(path.as_ref().join(&filename)) {
|
|
return Ok(reader);
|
|
}
|
|
}
|
|
|
|
let message = search_paths
|
|
.iter()
|
|
.filter_map(|p| {
|
|
path::absolute(p.as_ref().join(&filename))
|
|
.ok()
|
|
.and_then(|p| Some(p.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_file<T>(filename: T) -> io::Result<io::BufReader<File>>
|
|
where
|
|
T: AsRef<Path>,
|
|
{
|
|
let file = File::open(filename)?;
|
|
Ok(io::BufReader::new(file))
|
|
}
|