#![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 { read_input_file(path!("input" / format!("day{}.txt", day))) } #[cfg(test)] pub(crate) fn read_example(day: u8, part: u8) -> Vec { 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>(path: P) -> Vec { let f = File::open(path).expect("could not read input file"); let mut input = BufReader::new(f).lines().flatten().collect::>(); 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) -> String>; struct Day { n: u8, title: &'static str, p1: SolveFn, p2: SolveFn, } macro_rules! days { ( $($module:ident,)* ) => { $(mod $module;)* fn days() -> Vec { 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::().ok()) { let part = args .next() .and_then(|arg| arg.parse::().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}") } } }