mirror of
https://github.com/bertptrs/adventofcode.git
synced 2025-12-25 21:00:31 +01:00
Initial skeleton code for 2020
This commit is contained in:
2
2020/.gitignore
vendored
Normal file
2
2020/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
target/
|
||||||
|
Cargo.lock
|
||||||
8
2020/Cargo.toml
Normal file
8
2020/Cargo.toml
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
[package]
|
||||||
|
name = "aoc-2020"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = ["Bert Peters <bert@bertptrs.nl>"]
|
||||||
|
edition = "2018"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
clap = "3.0.0-beta.2"
|
||||||
24
2020/README.md
Normal file
24
2020/README.md
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
# Advent of Code 2020
|
||||||
|
|
||||||
|
This folder contains a runner script for Advent of Code 2020. This year, I'm
|
||||||
|
attempting to solve every problem once more in Rust.
|
||||||
|
|
||||||
|
```
|
||||||
|
aoc-2020
|
||||||
|
Advent of Code 2020 runner
|
||||||
|
|
||||||
|
USAGE:
|
||||||
|
aoc-2020 [FLAGS] [OPTIONS] <day>
|
||||||
|
|
||||||
|
ARGS:
|
||||||
|
<day> Which day to run
|
||||||
|
|
||||||
|
FLAGS:
|
||||||
|
-h, --help Prints help information
|
||||||
|
-2, --part2 Run part 2 instead of part 1
|
||||||
|
-t, --time Print time taken
|
||||||
|
-V, --version Prints version information
|
||||||
|
|
||||||
|
OPTIONS:
|
||||||
|
-i, --input <input> Read input from the given file instead of stdin
|
||||||
|
```
|
||||||
77
2020/src/common.rs
Normal file
77
2020/src/common.rs
Normal 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
40
2020/src/day01.rs
Normal 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
19
2020/src/lib.rs
Normal 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
52
2020/src/main.rs
Normal 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);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user