Initial skeleton code for 2020

This commit is contained in:
2020-11-28 23:43:15 +01:00
parent 9726769253
commit cbbee3a01f
7 changed files with 222 additions and 0 deletions

77
2020/src/common.rs Normal file
View File

@@ -0,0 +1,77 @@
use std::collections::HashMap;
use std::fmt::Debug;
use std::hash::Hash;
use std::io::BufRead;
use std::io::BufReader;
use std::io::Read;
use std::iter::FromIterator;
use std::str::FromStr;
/// Read input line by line and try to parse it into some collection.
pub fn from_lines<I, T, E>(input: &mut dyn Read) -> T
where
I: FromStr<Err = E>,
E: Debug,
T: FromIterator<I>,
{
let reader = BufReader::new(input);
reader
.lines()
.map(|line| line.unwrap().parse::<I>().unwrap())
.collect()
}
/// Parse the entire input into a single variable
pub fn read_single_input<T>(input: &mut dyn Read) -> T
where
T: FromStr,
<T as FromStr>::Err: Debug,
{
let mut buf = String::new();
input.read_to_string(&mut buf).unwrap();
buf.trim().parse().unwrap()
}
/// An interface to count elements in particular categories.
pub trait GroupingCount {
/// The type of the categories under inspection
type Type;
/// Count the occurrence of all possible values.
///
/// This method will return a map from a value to its occurrence rate.
fn grouping_count(&mut self) -> HashMap<Self::Type, usize>;
}
impl<T> GroupingCount for T
where
T: Iterator,
T::Item: Eq + Hash,
{
type Type = T::Item;
fn grouping_count(&mut self) -> HashMap<Self::Type, usize> {
let mut counts = HashMap::new();
for element in self {
*counts.entry(element).or_insert(0) += 1;
}
counts
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_grouping_count() {
let result = [1, 1, 2, 2, 3, 1].iter().grouping_count();
assert_eq!(3, result[&1]);
assert_eq!(2, result[&2]);
assert_eq!(1, result[&3]);
}
}

40
2020/src/day01.rs Normal file
View File

@@ -0,0 +1,40 @@
use std::io::Read;
use crate::common::from_lines;
use crate::Solution;
#[derive(Default)]
pub struct Day01;
fn fuel_required(weight: u32) -> u32 {
(weight / 3).saturating_sub(2)
}
fn recursive_fuel(mut weight: u32) -> u32 {
let mut required = 0;
while weight > 0 {
weight = fuel_required(weight);
required += weight
}
required
}
impl Solution for Day01 {
fn part1(&mut self, input: &mut dyn Read) -> String {
let weights: Vec<u32> = from_lines(input);
let fuel_required: u32 = weights.into_iter().map(fuel_required).sum();
fuel_required.to_string()
}
fn part2(&mut self, input: &mut dyn Read) -> String {
let weights: Vec<u32> = from_lines(input);
let fuel_required: u32 = weights.into_iter().map(recursive_fuel).sum();
fuel_required.to_string()
}
}

19
2020/src/lib.rs Normal file
View File

@@ -0,0 +1,19 @@
use std::io::Read;
mod common;
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<dyn Solution> {
match day {
1 => Box::new(day01::Day01::default()),
_ => panic!("Unsupported day {}", day),
}
}

52
2020/src/main.rs Normal file
View File

@@ -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::Clap;
use aoc_2020::get_implementation;
/// Advent of Code 2020 runner
#[derive(Clap)]
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<PathBuf>,
}
fn main() {
let opts: Opts = Opts::parse();
let mut implementation = get_implementation(opts.day.get());
let mut input: Box<dyn Read> = 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);
}