garnet/rust/main.rs

63 lines
2.1 KiB
Rust

mod puzzle;
mod puzzles;
use crate::puzzle::Puzzle;
use puzzles::day1;
use puzzles::day2;
use puzzles::day3;
use puzzles::day4;
use std::fs;
use std::time::{Duration, Instant};
const PUZZLES: [&dyn SomePuzzle; 4] = [&day1::PUZZLE, &day2::PUZZLE, &day3::PUZZLE, &day4::PUZZLE];
fn main() {
[false, true].iter().for_each(|is_real_data| {
let t = if *is_real_data { "real" } else { "examples" };
println!("{}", t);
PUZZLES.into_iter().for_each(|puzzle| {
println!(" {}", puzzle.number());
let input = fs::read_to_string(format!("../inputs/{}/{}", t, puzzle.number()))
.expect("no input file");
puzzle.with_parts(&input, &|n, run| {
let expected =
fs::read_to_string(format!("../outputs/{}/{}/{}", t, puzzle.number(), n))
.expect("no golden file");
let expected = expected.trim_end();
let start = Instant::now();
let output = run();
let elapsed = start.elapsed();
println!(
" {}: {}",
n,
if expected == output {
let duration = if elapsed > Duration::from_millis(10) {
format!(" ({:?})", elapsed)
} else {
"".to_owned()
};
"OK".to_owned() + &duration
} else {
format!("expected {}, got {}", expected, output)
}
);
});
});
})
}
pub trait SomePuzzle {
fn number(&self) -> u32;
fn with_parts(&self, input: &str, f: &dyn Fn(usize, &dyn Fn() -> String));
}
impl<Input, const N: usize> SomePuzzle for Puzzle<Input, { N }> {
fn number(&self) -> u32 {
self.number
}
fn with_parts(&self, s: &str, f: &dyn Fn(usize, &dyn Fn() -> String)) {
let input = (self.parser)(s);
for (i, p) in self.parts.iter().enumerate() {
f(i + 1, &|| p(&input));
}
}
}