--- /dev/null
+# Generated by Cargo
+# will have compiled files and executables
+/target/
+
+# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
+# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html
+Cargo.lock
+
+# These are backup files generated by rustfmt
+**/*.rs.bk
--- /dev/null
+[package]
+name = "advent_of_code_2021"
+version = "0.1.0"
+authors = ["Greg Burri <greg.burri@gmail.com>"]
+edition = "2018"
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
+itertools = "0.10"
+threadpool = "1.8"
+regex = "1"
+num = "0.4"
+num_enum = "0.5"
\ No newline at end of file
--- /dev/null
+# AdventOfCode2021
+
+https://adventofcode.com/2021
+
+
+# Running tests
+
+Example for day 1 tests:
+
+~~~
+cargo test day01 -- --nocapture
+~~~
+
+All tests:
+
+~~~
+cargo test -- --nocapture
+~~~
+
+
+# Running a day code
+
+~~~
+cargo run -- n
+~~~
+
+Where 'n' is a number from 1 to 25
--- /dev/null
+use std::fs;
+use std::path::Path;
+use std::str::FromStr;
+
+pub fn read_list_of_numbers<P, T>(file: P, sep: &str) -> Vec<T>
+where
+ P: AsRef<Path>,
+ T: FromStr,
+ T::Err: std::fmt::Debug
+
+{
+ fs::read_to_string(file).unwrap().split(sep).map(|line| line.trim().parse::<T>().unwrap()).collect()
+}
\ No newline at end of file
--- /dev/null
+pub fn count_number_of_decreased_values(report: &[i32], window_size: usize) -> i32 {
+ let mut n = 0;
+
+ let sum = |i: usize| -> i32 {
+ let mut s = 0;
+ for j in i..i+window_size {
+ s += report[j];
+ }
+ s
+ };
+
+ for i in 0..report.len() - window_size {
+ if sum(i+1) > sum(i) {
+ n += 1;
+ }
+ }
+ n
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn part1() {
+ let sea_floor_report = [ 199, 200, 208, 210, 200, 207, 240, 269, 260, 263 ];
+ assert_eq!(count_number_of_decreased_values(&sea_floor_report, 1), 7);
+ }
+
+ #[test]
+ fn part2() {
+ let sea_floor_report = [ 199, 200, 208, 210, 200, 207, 240, 269, 260, 263 ];
+ assert_eq!(count_number_of_decreased_values(&sea_floor_report, 3), 5);
+ }
+}
\ No newline at end of file
--- /dev/null
+use std::env;
+use std::time::Instant;
+
+mod common;
+mod day01;
+
+fn day01() -> String {
+ let report = common::read_list_of_numbers("data/day01.input", "\n");
+ format!("part1: {}, part2: {}", day01::count_number_of_decreased_values(&report, 1), day01::count_number_of_decreased_values(&report, 3))
+}
+
+fn format_micros(t: u128) -> String {
+ if t < 10_000 {
+ format!("{} μs", t)
+ } else if t < 10_000_000u128 {
+ format!("{} ms", t / 1_000u128)
+ } else {
+ format!("{} s", t / 1_000_000u128)
+ }
+}
+
+fn do_day(days: &[fn() -> String], day: usize) {
+ let now = Instant::now();
+ println!("Result of day {:02}: {} (time: {})", day, days[day - 1](), format_micros(now.elapsed().as_micros()));
+}
+
+fn main() {
+ println!("https://adventofcode.com/2021");
+
+ let days: Vec<fn() -> String> = vec!(
+ day01,
+ );
+
+ let args: Vec<String> = env::args().skip(1).collect();
+
+ // No argument -> execute all day problems.
+ if args.is_empty() {
+ let now = Instant::now();
+ for i in 1 ..= days.len() {
+ do_day(&days, i)
+ }
+ println!("Time to execute all days: {}", format_micros(now.elapsed().as_micros()));
+ } else {
+ for arg in args {
+ match arg.parse::<usize>() {
+ Ok(day) if day >= 1 && day <= days.len() =>
+ do_day(&days, day),
+ Ok(day) =>
+ println!("Unknown day: {}", day),
+ Err(error) =>
+ println!("Unable to parse day number: \"{}\", error: {}", arg, error)
+ }
+ }
+ }
+}