[TASK] Solved Day1 + added general architecture to run and benchmark all days

This commit is contained in:
2022-12-01 14:40:57 +01:00
parent 2f71827eb1
commit 6b17362556
12 changed files with 2568 additions and 16 deletions

18
.gitignore vendored
View File

@@ -1,16 +1,2 @@
# ---> Rust
# Generated by Cargo
# will have compiled files and executables
debug/
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
# MSVC Windows builds of rustc generate these, which store debugging information
*.pdb
/target
/.idea

View File

@@ -0,0 +1,19 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Run-aoc2022-bench" type="CargoCommandRunConfiguration" factoryName="Cargo Command">
<option name="command" value="run --package advent-of-code-2022-rust --bin advent-of-code-2022-rust --release -- -b" />
<option name="workingDirectory" value="file://$PROJECT_DIR$" />
<option name="channel" value="DEFAULT" />
<option name="requiredFeatures" value="true" />
<option name="allFeatures" value="false" />
<option name="emulateTerminal" value="false" />
<option name="withSudo" value="false" />
<option name="buildTarget" value="REMOTE" />
<option name="backtrace" value="NO" />
<envs />
<option name="isRedirectInput" value="false" />
<option name="redirectInputPath" value="" />
<method v="2">
<option name="CARGO.BUILD_TASK_PROVIDER" enabled="true" />
</method>
</configuration>
</component>

49
Cargo.lock generated Normal file
View File

@@ -0,0 +1,49 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "advent-of-code-2022-rust"
version = "0.1.0"
dependencies = [
"lazy_static",
"regex",
]
[[package]]
name = "aho-corasick"
version = "0.7.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cc936419f96fa211c1b9166887b38e5e40b19958e5b895be7c1f93adec7071ac"
dependencies = [
"memchr",
]
[[package]]
name = "lazy_static"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]]
name = "memchr"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
[[package]]
name = "regex"
version = "1.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e076559ef8e241f2ae3479e36f97bd5741c0330689e217ad51ce2c76808b868a"
dependencies = [
"aho-corasick",
"memchr",
"regex-syntax",
]
[[package]]
name = "regex-syntax"
version = "0.6.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848"

11
Cargo.toml Normal file
View File

@@ -0,0 +1,11 @@
[package]
name = "advent-of-code-2022-rust"
version = "0.1.0"
authors = ["Bas Dado <bas@basdado.com>"]
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
regex = "1"
lazy_static = "1.4.0"

2259
input/day1.txt Normal file

File diff suppressed because it is too large Load Diff

14
input/day1_example.txt Normal file
View File

@@ -0,0 +1,14 @@
1000
2000
3000
4000
5000
6000
7000
8000
9000
10000

38
src/day1.rs Normal file
View File

@@ -0,0 +1,38 @@
use std::cmp::Reverse;
use crate::day_solver::{DaySolver};
use super::util;
pub struct Day1 {
elfs: Vec<Vec<u64>>
}
impl Day1 {
pub fn create() -> Self {
// let lines = util::read_file("input/day1_example.txt");
let lines = util::read_file("input/day1.txt");
// Parse the input into a nice data structure
let elfs = lines.split(|s| s.is_empty())
.map(|s| s.iter().map(|i| i.parse::<u64>().unwrap()).collect::<Vec<u64>>())
.collect();
return Day1 { elfs }
}
}
impl DaySolver for Day1 {
fn solve_part1(&mut self) -> String {
return self.elfs.iter().map(|e| e.iter().sum::<u64>()).max().unwrap().to_string();
}
fn solve_part2(&mut self) -> String {
let mut calories_per_elf: Vec<u64> = self.elfs.iter().map(|e| e.iter().sum()).collect();
calories_per_elf.sort_by_key(|&c| Reverse(c));
let part2 = calories_per_elf.iter().take(3).sum::<u64>();
return part2.to_string()
}
}

31
src/day2.rs Normal file
View File

@@ -0,0 +1,31 @@
use std::cmp::Reverse;
use crate::day_solver::DaySolver;
use super::util;
pub struct Day2 {
}
impl Day2 {
pub fn create() -> Self {
// let lines = util::read_file("input/dayX_example.txt");
let lines = util::read_file("input/dayX.txt");
// Put the input into the day struct
return Day2 {}
}
}
impl DaySolver for Day2 {
fn solve_part1(&mut self) -> String {
return 0.to_string();
}
fn solve_part2(&mut self) -> String {
return 0.to_string();
}
}

29
src/dayX.rs Normal file
View File

@@ -0,0 +1,29 @@
use crate::day_solver::DaySolver;
use super::util;
pub struct DayX {
}
impl DayX {
pub fn create() -> Self {
// let lines = util::read_file("input/dayX_example.txt");
let lines = util::read_file("input/dayX.txt");
// Put the input into the day struct
return Day2 {}
}
}
impl DaySolver for DayX {
fn solve_part1(&mut self) -> String {
return 0.to_string();
}
fn solve_part2(&mut self) -> String {
return 0.to_string();
}
}

6
src/day_solver.rs Normal file
View File

@@ -0,0 +1,6 @@
pub trait DaySolver {
// fn create() -> Self;
fn solve_part1(&mut self) -> String;
fn solve_part2(&mut self) -> String;
}

97
src/main.rs Normal file
View File

@@ -0,0 +1,97 @@
use std::time::Instant;
use crate::day1::Day1;
use crate::day2::Day2;
use crate::day_solver::DaySolver;
#[macro_use] extern crate lazy_static;
mod util;
mod day1;
mod day_solver;
mod day2;
const MAX_DAY: u8 = 1;
const BENCHMARK_AMOUNT: u32 = 100;
fn build_day_solver(day: u8) -> Option<Box<dyn DaySolver>> {
match day {
1 => Some(Box::new(Day1::create())),
2 => Some(Box::new(Day2::create())),
_ => None
}
}
fn solve(day: u8, silent: bool) {
let solver = build_day_solver(day);
match solver {
Some(mut s) => {
let part1 = s.solve_part1();
if !silent {
println!("Day {} Part 1: {}", day, part1);
}
let part2 = s.solve_part2();
if !silent {
println!("Day {} Part 1: {}", day, part2);
}
},
None => println!("This day is not yet implemented")
}
}
fn main() {
let args: Vec<String> = std::env::args().collect();
let day_arg_idx = args.iter().position(|a| a == "-d");
let single_day = day_arg_idx.is_some();
let day = if single_day { args[day_arg_idx.unwrap() + 1].parse::<u8>().unwrap() } else { 0 };
let benchmark = args.contains(&String::from("--bench")) || args.contains(&String::from("-b"));
let mut bench_results: Vec<u128> = Vec::new();
// This is essentially the warmup for the benchmark:
run_once(single_day, day, false, &mut bench_results);
let first_run_time = bench_results[0];
if benchmark {
// Ignore the warmup run in the rest of the benchmark:
bench_results.clear();
for _ in 0..BENCHMARK_AMOUNT {
run_once(single_day, day, true,&mut bench_results);
}
}
let avg_runtime: u128 = bench_results.iter().sum::<u128>() / (bench_results.len() as u128);
println!("Executed {} rounds; Execution took {} μs {}", BENCHMARK_AMOUNT, avg_runtime, if benchmark { "on average" } else { "" });
if benchmark {
bench_results.sort();
println!("Min: {} μs, Max: {} μs, Median: {} μs",
bench_results[0],
bench_results[bench_results.len() - 1],
bench_results[bench_results.len() / 2]
);
println!("First time took {} μs", first_run_time);
}
}
fn run_once(single_day: bool, day: u8, silent: bool, bench_results: &mut Vec<u128>) {
let now = Instant::now();
if single_day {
solve(day, silent);
} else {
solve_all(silent);
}
bench_results.push(now.elapsed().as_micros());
}
fn solve_all(silent: bool) {
for day in 1..(MAX_DAY + 1) {
solve(day, silent);
}
}

13
src/util.rs Normal file
View File

@@ -0,0 +1,13 @@
use std::fs;
pub fn read_file(filename: &str) -> Vec<String> {
let contents = fs::read_to_string(filename)
.expect("Couldn't read file!");
let mut res: Vec<String> = Vec::new();
contents.lines().for_each(|l| res.push(String::from(l)));
res
}