From: Greg Burri Date: Tue, 10 Dec 2024 21:01:30 +0000 (+0100) Subject: Add the common code to run code for each day X-Git-Url: https://git.euphorik.ch/?a=commitdiff_plain;h=b9fa0908044042af2ca3dd66281b58afd289b4e4;p=advent_of_code_common.git Add the common code to run code for each day --- diff --git a/src/lib.rs b/src/lib.rs index e12f22f..164b6f3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,3 +1,92 @@ -pub fn a_function() { - println!("Hello there!"); +use std::{ + fs, + io::{BufRead, Read}, + time::Instant, +}; + +use clap::Parser; +use rayon::prelude::*; + +#[derive(Parser, Debug)] +#[command(author = "Greg Burri", version = "1.0", about = "Advent of Code 2024")] +struct Args { + #[arg(index(1), conflicts_with_all(["parallel"]))] + day: Option, + + /// Run all days in parallel. + #[arg(short, long)] + parallel: bool, + + /// Number of time each day is executed, the average time is displayed. + #[arg(short, long, default_value_t = 1)] + repeat: u32, +} + +pub fn run(days: Vec String>) { + let args = Args::parse(); + + match args.day { + Some(day) => { + if day >= 1 && day <= days.len() { + do_day(&days, day, args.repeat) + } else { + println!("Unknown day: {}", day) + } + } + // No argument -> execute all day problems. + None => { + let now = Instant::now(); + + if args.parallel { + (1..=days.len()) + .into_par_iter() + .for_each(|d| do_day(&days, d, args.repeat)); + } else { + (1..=days.len()).for_each(|d| do_day(&days, d, args.repeat)); + } + + println!( + "Time to execute all days: {}", + format_micros(now.elapsed().as_micros()) + ); + } + } +} + +fn do_day(days: &[fn(&mut dyn BufRead) -> String], day: usize, repeat: u32) { + let filepath = format!("data/day{:02}.input", day); + let mut f = fs::File::open(&filepath).unwrap_or_else(|error| { + println!( + "Cannot find file {}. Did you place the input files in the 'data' directory?\nError:{}", + filepath, error + ); + panic!(); + }); + + // We read the whole file to avoid measuring I/O time. + let mut buffer = Vec::new(); + f.read_to_end(&mut buffer).unwrap(); + + let now = Instant::now(); + for i in 0..repeat { + let result = days[day - 1](&mut buffer.as_slice()); + if i == repeat - 1 { + println!( + "Result of day {:02}: {} (time: {})", + day, + result, + format_micros(now.elapsed().as_micros() / repeat as u128) + ); + } + } +} + +fn format_micros(t: u128) -> String { + if t < 10_000 { + format!("{} μs", t) + } else if t < 10_000_000u128 { + format!("{:.2} ms", t as f64 / 1e3f64) + } else { + format!("{:.2} s", t as f64 / 1e6f64) + } }