diff --git a/.gitignore b/.gitignore index e5c7e98..023c586 100644 --- a/.gitignore +++ b/.gitignore @@ -56,3 +56,6 @@ docs/_build/ # PyBuilder target/ *.swp + +# Rust lock +*.lock diff --git a/2021/Cargo.toml b/2021/Cargo.toml new file mode 100644 index 0000000..c49400f --- /dev/null +++ b/2021/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "aoc-2021" +version = "0.1.0" +edition = "2021" + + +[dependencies] +clap = "3.0.0-beta.5" diff --git a/2021/src/day01.rs b/2021/src/day01.rs new file mode 100644 index 0000000..1a26a6a --- /dev/null +++ b/2021/src/day01.rs @@ -0,0 +1,10 @@ +use crate::Solution; + +#[derive(Default)] +pub struct Day01; + +impl Solution for Day01 { + fn part1(&mut self, _input: &mut dyn std::io::Read) -> String { + todo!() + } +} diff --git a/2021/src/lib.rs b/2021/src/lib.rs new file mode 100644 index 0000000..016638d --- /dev/null +++ b/2021/src/lib.rs @@ -0,0 +1,29 @@ +use std::io::Read; + +mod day01; + +pub trait Solution { + fn part1(&mut self, input: &mut dyn Read) -> String; + + fn part2(&mut self, _input: &mut dyn Read) -> String { + unimplemented!("Still working on part 1"); + } +} + +pub fn get_implementation(day: usize) -> Box { + match day { + 1 => Box::new(day01::Day01::default()), + _ => panic!("Unsupported day {}", day), + } +} + +#[cfg(test)] +fn test_implementation(mut day: impl Solution, part: u8, mut input: &[u8], answer: impl ToString) { + let result = match part { + 1 => day.part1(&mut input), + 2 => day.part2(&mut input), + _ => panic!("Invalid part: {}", part), + }; + + assert_eq!(answer.to_string(), result); +} diff --git a/2021/src/main.rs b/2021/src/main.rs new file mode 100644 index 0000000..4d775b1 --- /dev/null +++ b/2021/src/main.rs @@ -0,0 +1,52 @@ +use std::fs::File; +use std::io::Read; +use std::num::NonZeroUsize; +use std::path::PathBuf; +use std::time::Instant; + +use clap::Parser; + +use aoc_2021::get_implementation; + +/// Advent of Code 2021 runner +#[derive(Parser)] +struct Opts { + /// Which day to run + day: NonZeroUsize, + + /// Print time taken + #[clap(short, long)] + time: bool, + + /// Run part 2 instead of part 1 + #[clap(short = '2', long)] + part2: bool, + + /// Read input from the given file instead of stdin + #[clap(short, long)] + input: Option, +} + +fn main() { + let opts: Opts = Opts::parse(); + + let mut implementation = get_implementation(opts.day.get()); + let mut input: Box = if let Some(input) = opts.input { + Box::new(File::open(&input).expect("Failed to open input")) + } else { + Box::new(std::io::stdin()) + }; + + let begin = Instant::now(); + let result = if opts.part2 { + implementation.part2(&mut input) + } else { + implementation.part1(&mut input) + }; + + if opts.time { + eprintln!("Execution time: {:?}", Instant::now().duration_since(begin)); + } + + println!("{}", result); +}