[WIP] Day 1
This commit is contained in:
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
/target
|
||||
8
.idea/.gitignore
generated
vendored
Normal file
8
.idea/.gitignore
generated
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
# Editor-based HTTP Client requests
|
||||
/httpRequests/
|
||||
# Datasource local storage ignored files
|
||||
/dataSources/
|
||||
/dataSources.local.xml
|
||||
11
.idea/advent-of-code-2023-rust.iml
generated
Normal file
11
.idea/advent-of-code-2023-rust.iml
generated
Normal file
@@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="EMPTY_MODULE" version="4">
|
||||
<component name="NewModuleRootManager">
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/target" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
||||
8
.idea/modules.xml
generated
Normal file
8
.idea/modules.xml
generated
Normal file
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/advent-of-code-2023-rust.iml" filepath="$PROJECT_DIR$/.idea/advent-of-code-2023-rust.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
||||
6
.idea/vcs.xml
generated
Normal file
6
.idea/vcs.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
||||
92
Cargo.lock
generated
Normal file
92
Cargo.lock
generated
Normal file
@@ -0,0 +1,92 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "advent-of-code-2023-rust"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"num",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
||||
|
||||
[[package]]
|
||||
name = "num"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b05180d69e3da0e530ba2a1dae5110317e49e3b7f3d41be227dc5f92e49ee7af"
|
||||
dependencies = [
|
||||
"num-bigint",
|
||||
"num-complex",
|
||||
"num-integer",
|
||||
"num-iter",
|
||||
"num-rational",
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-bigint"
|
||||
version = "0.4.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "608e7659b5c3d7cba262d894801b9ec9d00de989e8a82bd4bef91d08da45cdc0"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"num-integer",
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-complex"
|
||||
version = "0.4.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1ba157ca0885411de85d6ca030ba7e2a83a28636056c7c699b07c8b6f7383214"
|
||||
dependencies = [
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-integer"
|
||||
version = "0.1.45"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-iter"
|
||||
version = "0.1.43"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7d03e6c028c5dc5cac6e2dec0efda81fc887605bb3d884578bb6d6bf7514e252"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"num-integer",
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-rational"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"num-bigint",
|
||||
"num-integer",
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
version = "0.2.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
9
Cargo.toml
Normal file
9
Cargo.toml
Normal file
@@ -0,0 +1,9 @@
|
||||
[package]
|
||||
name = "advent-of-code-2023-rust"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
num = "0.4"
|
||||
1000
input/day1.txt
Normal file
1000
input/day1.txt
Normal file
File diff suppressed because it is too large
Load Diff
4
input/day1_example.txt
Normal file
4
input/day1_example.txt
Normal file
@@ -0,0 +1,4 @@
|
||||
1abc2
|
||||
pqr3stu8vwx
|
||||
a1b2c3d4e5f
|
||||
treb7uchet
|
||||
7
input/day1_example2.txt
Normal file
7
input/day1_example2.txt
Normal file
@@ -0,0 +1,7 @@
|
||||
two1nine
|
||||
eightwothree
|
||||
abcone2threexyz
|
||||
xtwone3four
|
||||
4nineeightseven2
|
||||
zoneight234
|
||||
7pqrstsixteen
|
||||
54
src/day1.rs
Normal file
54
src/day1.rs
Normal file
@@ -0,0 +1,54 @@
|
||||
use crate::day_solver::DaySolver;
|
||||
|
||||
use super::util;
|
||||
|
||||
pub struct Day1 {
|
||||
lines: Vec<String>
|
||||
}
|
||||
|
||||
impl Day1 {
|
||||
|
||||
pub fn create() -> Self {
|
||||
let lines = util::read_file("input/day1_example2.txt");
|
||||
// let lines = util::read_file("input/dayX.txt");
|
||||
|
||||
// Put the input into the day struct
|
||||
return Day1 {
|
||||
lines
|
||||
}
|
||||
}
|
||||
|
||||
fn solve(lines: &Vec<String>) -> u32 {
|
||||
lines.iter()
|
||||
.map(|l| {
|
||||
let nrs: Vec<u8> = l.chars()
|
||||
.filter(|c| c.is_numeric())
|
||||
.map(|c| (c as u8) - ('0' as u8))
|
||||
.collect();
|
||||
u32::from(nrs.first().unwrap().to_owned()) * 10 + u32::from(nrs.last().unwrap().to_owned())
|
||||
}).sum::<u32>()
|
||||
}
|
||||
}
|
||||
|
||||
impl DaySolver for Day1 {
|
||||
|
||||
|
||||
fn solve_part1(&mut self) -> String {
|
||||
return Self::solve(&self.lines).to_string()
|
||||
}
|
||||
|
||||
fn solve_part2(&mut self) -> String {
|
||||
return Self::solve(&self.lines.iter().map(
|
||||
|l| l
|
||||
.replace("one", "1")
|
||||
.replace("two", "2")
|
||||
.replace("three", "3")
|
||||
.replace("four", "4")
|
||||
.replace("five", "5")
|
||||
.replace("six", "6")
|
||||
.replace("seven", "7")
|
||||
.replace("eight", "8")
|
||||
.replace("nine", "9")
|
||||
).collect()).to_string()
|
||||
}
|
||||
}
|
||||
29
src/dayX.rs
Normal file
29
src/dayX.rs
Normal 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 DayX {}
|
||||
}
|
||||
}
|
||||
|
||||
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
6
src/day_solver.rs
Normal file
@@ -0,0 +1,6 @@
|
||||
|
||||
pub trait DaySolver {
|
||||
// fn create() -> Self;
|
||||
fn solve_part1(&mut self) -> String;
|
||||
fn solve_part2(&mut self) -> String;
|
||||
}
|
||||
158
src/main.rs
Normal file
158
src/main.rs
Normal file
@@ -0,0 +1,158 @@
|
||||
extern crate core;
|
||||
|
||||
use std::time::Instant;
|
||||
use crate::day1::Day1;
|
||||
use crate::day_solver::DaySolver;
|
||||
|
||||
mod util;
|
||||
mod day1;
|
||||
mod day_solver;
|
||||
|
||||
const MAX_DAY: u8 = 1;
|
||||
const DEFAULT_BENCHMARK_AMOUNT: u32 = 100;
|
||||
|
||||
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_arg_idx_option = args.iter().position(|a| a == "--bench").or(
|
||||
args.iter().position(|a| a == "-b"));
|
||||
|
||||
let benchmark = benchmark_arg_idx_option.is_some();
|
||||
let bench_amount: u32 = if let Some(benchmark_arg_idx) = benchmark_arg_idx_option {
|
||||
args.get(benchmark_arg_idx + 1)
|
||||
.map_or(DEFAULT_BENCHMARK_AMOUNT, |r| r.parse::<u32>().unwrap_or(DEFAULT_BENCHMARK_AMOUNT))
|
||||
} else {
|
||||
DEFAULT_BENCHMARK_AMOUNT
|
||||
};
|
||||
|
||||
let mut bench_results: Vec<AocBenchResult> = Vec::new();
|
||||
|
||||
// This is essentially the warmup for the benchmark:
|
||||
run_once(single_day, day, false, &mut bench_results);
|
||||
let first_run_bench = bench_results[0].to_owned();
|
||||
|
||||
let (_, total_time) = bench(||
|
||||
if benchmark {
|
||||
// Ignore the warmup run in the rest of the benchmark:
|
||||
bench_results.clear();
|
||||
|
||||
for _ in 0..bench_amount {
|
||||
run_once(single_day, day, true, &mut bench_results);
|
||||
}
|
||||
});
|
||||
|
||||
if benchmark {
|
||||
|
||||
println!("Executed {} rounds in {:.3} s ({} μs, or {} μs on average per round)", bench_results.len(), total_time as f64 / 1000000f64, total_time, total_time / bench_amount as u128);
|
||||
print_bench_result(&bench_results, |b| b.total, "Execution");
|
||||
print_bench_result(&bench_results, |b| b.init, "Initialization");
|
||||
print_bench_result(&bench_results, |b| b.part1, "Part 1");
|
||||
print_bench_result(&bench_results, |b| b.part2, "Part 2");
|
||||
print_bench_result(&bench_results, |b| b.part1 + b.part2, "Part 1 & 2 together");
|
||||
|
||||
println!("First time took {} μs (init {} μs, part 1: {} μs, part 2: {} μs)", first_run_bench.total, first_run_bench.init, first_run_bench.part1, first_run_bench.part2);
|
||||
|
||||
} else {
|
||||
println!("Execution took {} μs (init {} μs, part 1: {} μs, part 2: {} μs)", first_run_bench.total, first_run_bench.init, first_run_bench.part1, first_run_bench.part2);
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
struct AocBenchResult {
|
||||
init: u128,
|
||||
part1: u128,
|
||||
part2: u128,
|
||||
total: u128
|
||||
}
|
||||
|
||||
fn build_day_solver(day: u8) -> Option<Box<dyn DaySolver>> {
|
||||
match day {
|
||||
1 => Some(Box::new(Day1::create())),
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
|
||||
fn solve(day: u8, silent: bool) -> AocBenchResult {
|
||||
|
||||
let now = Instant::now();
|
||||
let (solver, init_time) = bench(|| build_day_solver(day));
|
||||
|
||||
let part1_time: u128;
|
||||
let part2_time: u128;
|
||||
match solver {
|
||||
Some(mut s) => {
|
||||
|
||||
// let(part1, pt1_time) = bench(|| s.solve_part1());
|
||||
// part1_time = pt1_time;
|
||||
//
|
||||
// if !silent {
|
||||
// println!("Day {} Part 1: {}", day, part1);
|
||||
// }
|
||||
part1_time = 0;
|
||||
let (part2, pt2_time) = bench(|| s.solve_part2());
|
||||
part2_time = pt2_time;
|
||||
if !silent {
|
||||
println!("Day {} Part 2: {}", day, part2);
|
||||
}
|
||||
},
|
||||
None => panic!("This day is not yet implemented")
|
||||
}
|
||||
|
||||
return AocBenchResult{
|
||||
init: init_time,
|
||||
part1: part1_time,
|
||||
part2: part2_time,
|
||||
total: now.elapsed().as_micros()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
fn print_bench_result<F>(bench_results: &Vec<AocBenchResult>, f: F, bench_part_description: &str)
|
||||
where
|
||||
F: FnMut(&AocBenchResult) -> u128 {
|
||||
|
||||
let mut benches: Vec<u128> = bench_results.iter().map(f).collect();
|
||||
benches.sort();
|
||||
let avg_runtime: u128 = benches.iter().sum::<u128>() / (bench_results.len() as u128);
|
||||
|
||||
println!("{} took {} μs {} (Min: {} μs, Max: {} μs, Median: {} μs)", bench_part_description, avg_runtime, if bench_results.len() > 1 { "on average"} else {""},
|
||||
benches[0], benches[benches.len() - 1], benches[benches.len() / 2])
|
||||
}
|
||||
|
||||
fn run_once(single_day: bool, day: u8, silent: bool, bench_results: &mut Vec<AocBenchResult>) {
|
||||
|
||||
|
||||
let bench_result = if single_day {
|
||||
solve(day, silent)
|
||||
} else {
|
||||
solve_all(silent)
|
||||
};
|
||||
bench_results.push(bench_result);
|
||||
}
|
||||
|
||||
fn solve_all(silent: bool) -> AocBenchResult {
|
||||
let mut bench_results = Vec::new();
|
||||
for day in 1..(MAX_DAY + 1) {
|
||||
bench_results.push(solve(day, silent));
|
||||
}
|
||||
return AocBenchResult {
|
||||
init: bench_results.iter().map(|t| t.init).sum(),
|
||||
part1: bench_results.iter().map(|t| t.part1).sum(),
|
||||
part2: bench_results.iter().map(|t| t.part2).sum(),
|
||||
total: bench_results.iter().map(|t| t.total).sum(),
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fn bench<F, K>(mut f: F) -> (K, u128)
|
||||
where F: FnMut() -> K {
|
||||
let now = Instant::now();
|
||||
let res = f();
|
||||
(res, now.elapsed().as_micros())
|
||||
}
|
||||
103
src/util.rs
Normal file
103
src/util.rs
Normal file
@@ -0,0 +1,103 @@
|
||||
use std::fs;
|
||||
use std::fmt::Display;
|
||||
|
||||
use num::Integer;
|
||||
|
||||
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
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Grid<T> {
|
||||
pub(crate) width: usize,
|
||||
pub(crate) data: Vec<T>
|
||||
}
|
||||
|
||||
impl<T: Clone + Sized> Grid<T> {
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn set_row(&mut self, y: usize, v: T) {
|
||||
// let range = &mut self.data[x * self.width..(x+1) * self.width];
|
||||
for i in self.width * y..self.width * (y + 1) {
|
||||
self.data[i] = v.to_owned();
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn set_col(&mut self, x: usize, v: T) {
|
||||
for y in 0..self.height() {
|
||||
let idx = self.idx(&x, &y);
|
||||
self.data[idx] = v.to_owned();
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn idx(&self, x: &usize, y: &usize) -> usize {
|
||||
y * self.width + x
|
||||
}
|
||||
|
||||
pub(crate) fn height(&self) -> usize {
|
||||
self.data.len() / self.width
|
||||
}
|
||||
|
||||
pub(crate) fn get(&self, x: &usize, y: &usize) -> &T {
|
||||
let idx = self.idx(x, y);
|
||||
&self.data[idx]
|
||||
}
|
||||
|
||||
pub fn set(&mut self, x: &usize, y: &usize, v: T) {
|
||||
let idx = self.idx(x, y);
|
||||
self.data[idx] = v;
|
||||
}
|
||||
}
|
||||
|
||||
impl <T: Display + Clone + Sized> Grid<T> {
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn print(&self) {
|
||||
|
||||
self.print_range(0, self.width, 0, self.height());
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn print_range(&self, from_x: usize, to_x: usize, from_y: usize, to_y: usize) {
|
||||
|
||||
for y in from_y.max(0)..to_y.min(self.height()) {
|
||||
for x in from_x.max(0)..to_x.min(self.width) {
|
||||
print!("{}", self.get(&x, &y))
|
||||
}
|
||||
println!();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub struct Coord<T> where T: Sized {
|
||||
pub x: T,
|
||||
pub y: T
|
||||
}
|
||||
|
||||
|
||||
#[allow(dead_code)]
|
||||
impl<T> Coord<T> where T: Sized {
|
||||
pub(crate) fn new(x: T, y: T) -> Self {
|
||||
Coord { x, y }
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
impl <T> Coord<T> where T: Integer + Copy {
|
||||
pub fn manhattan_dist(&self, other: &Coord<T>) -> T {
|
||||
self.x.max(other.x).sub(self.x.min(other.x)) + self.y.max(other.y).sub(self.y.min(other.y))
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user