use std::io; use std::io::{BufRead, BufReader, Error, ErrorKind, Read}; use std::fs::File; use std::process::exit; use argparse::{ArgumentParser, StoreTrue, Store}; mod benchmark; mod day1; mod day2; mod day3; mod day4; mod day5; mod day6; mod day7; mod day8; mod day9; mod day10; mod day11; mod day12; mod day13; mod day14; mod day15; mod day16; mod day17; mod day18; mod day19; mod day20; static NUM_DAYS: i32 = 20; fn day_switch(day: i32, reader: T) -> io::Result<(String, String)> { match day { 1 => day1::main(reader), 2 => day2::main(reader), 3 => day3::main(reader), 4 => day4::main(reader), 5 => day5::main(reader), 6 => day6::main(reader), 7 => day7::main(reader), 8 => day8::main(reader), 9 => day9::main(reader), 10 => day10::main(reader), 11 => day11::main(reader), 12 => day12::main(reader), 13 => day13::main(reader), 14 => day14::main(reader), 15 => day15::main(reader), 16 => day16::main(reader), 17 => day17::main(reader), 18 => day18::main(reader), 19 => day19::main(reader), 20 => day20::main(reader), _ => Err(Error::new(ErrorKind::Other, "Invalid day")) } } fn file_for_day(day: i32) -> io::Result> { match File::open(format!("input/{}.txt", day)) { Ok(f) => Ok(BufReader::new(f)), Err(_) => Err(Error::new(ErrorKind::Other, format!("No input file for day {}", day))) } } fn benchmark_day(day: i32) -> io::Result { let mut input = Vec::new(); file_for_day(day)?.read_to_end(&mut input)?; let res = benchmark::benchmark(|| day_switch(day, BufReader::new(&input[..])).unwrap()); println!("Day {}: {}", day, res); Ok(res.duration) } fn benchmark_all_days() -> io::Result<()> { let mut total = 0.0; for day in 1..NUM_DAYS + 1 { total += benchmark_day(day)?; } println!("Total: {} secs", total); Ok(()) } struct Options { use_stdin: bool, bench: bool, } fn run_day(day: i32, opts: &Options) -> io::Result<()> { let (part1, part2) = if opts.bench { benchmark_day(day)?; return Ok(()) } else if opts.use_stdin { day_switch(day, BufReader::new(io::stdin()))? } else { day_switch(day, file_for_day(day)?)? }; println!("{}", part1); println!("{}", part2); Ok(()) } fn run_all_days(opts: &Options) -> io::Result<()> { if opts.bench { assert!(!opts.use_stdin); benchmark_all_days() } else { for day in 1..NUM_DAYS + 1 { run_day(day, &opts)?; } Ok(()) } } fn error_handler(func: F) -> io::Result<()> where F: Fn() -> io::Result<()> { match func() { Ok(()) => Ok(()), Err(err) => { if err.kind() == ErrorKind::Other { println!("Error: {}", err); exit(1) } else { Err(err) } } } } fn main() -> io::Result<()> { let mut day_string = String::new(); let mut options = Options { use_stdin: false, bench: false, }; { let mut parser = ArgumentParser::new(); parser.set_description("AOC 2018 solutions by Tom Smeding"); parser.refer(&mut options.use_stdin) .add_option(&["-s", "--stdin"], StoreTrue, "Read from stdin"); parser.refer(&mut options.bench) .add_option(&["-b", "--bench"], StoreTrue, "Benchmark the given days"); parser.refer(&mut day_string) .add_argument("day", Store, "Day to execute"); parser.parse_args_or_exit(); } error_handler(|| if day_string.len() == 0 { run_all_days(&options) } else { match day_string.parse::() { Ok(day) => run_day(day, &options), Err(_) => { println!("Invalid day argument"); exit(1) } } } ) }