adventofcode23/src/main.rs
2023-12-13 15:02:13 +01:00

125 lines
3 KiB
Rust

#![allow(dead_code, unused)]
mod util;
use std::{
fs::File,
io::{BufRead, BufReader},
path::Path,
time::Instant,
};
use once_cell::sync::Lazy;
use path_macro::path;
pub(crate) fn read_input(day: u8) -> Vec<String> {
read_input_file(path!("input" / format!("day{}.txt", day)))
}
#[cfg(test)]
pub(crate) fn read_example(day: u8, part: u8) -> Vec<String> {
if part > 1 {
let p2_file = path!("example" / format!("day{day}.{part}.txt"));
if p2_file.is_file() {
return read_input_file(p2_file);
}
}
read_input_file(path!("example" / format!("day{day}.txt")))
}
fn read_input_file<P: AsRef<Path>>(path: P) -> Vec<String> {
let f = File::open(path).expect("could not read input file");
let mut input = BufReader::new(f).lines().flatten().collect::<Vec<_>>();
if let Some(last) = input.last() {
if last.is_empty() {
input.pop();
}
}
input
}
fn get_result(day: &Day, part: u8) -> String {
let input = read_input(day.n);
if part == 2 {
(day.p2)(input)
} else {
(day.p1)(input)
}
}
type SolveFn = Box<dyn Fn(Vec<String>) -> String>;
struct Day {
n: u8,
title: &'static str,
p1: SolveFn,
p2: SolveFn,
}
macro_rules! days {
( $($module:ident,)* ) => {
$(mod $module;)*
fn days() -> Vec<Day> {
vec![
$(Day {
n: $module::DAY,
title: $module::TITLE,
p1: Box::new($module::part1),
p2: Box::new($module::part2),
},)*
]
}
};
}
days! {
day1,
day2,
day3,
day4,
day5,
day6,
day7,
day8,
day9,
day10,
day11,
day12,
day13,
}
fn main() {
let mut args = std::env::args();
args.next();
let days = days();
if let Some(day) = args.next().and_then(|a| a.parse::<u8>().ok()) {
let part = args
.next()
.and_then(|arg| arg.parse::<u8>().ok().map(|p| p.clamp(1, 2)))
.unwrap_or(1);
let dobj = days.iter().find(|d| d.n == day).expect("Day not found");
let res = get_result(dobj, part);
println!("✨The result for day {}/{:?} is✨", day, part);
println!("{}", res);
} else {
println!("Advent of Code 2023 | Part one | Part two");
println!("=============================|======================|======================");
for day in days {
let title = &day.title[..day.title.len().min(20)];
let t = Instant::now();
let res_a = get_result(&day, 1);
let res_a = format!("{res_a} ({}ms)", t.elapsed().as_millis());
print!("Day {:2}: {title:20} | {res_a:20}", day.n);
let t = Instant::now();
let res_b = get_result(&day, 2);
let res_b = format!("{res_b} ({}ms)", t.elapsed().as_millis());
println!(" | {res_b:20}")
}
}
}