More benchmarking overcomplicated stuff
Truly putting that AP Stats knowledge to the test
This commit is contained in:
parent
78c41799e7
commit
a8ece7c6d8
5 changed files with 206 additions and 74 deletions
7
Cargo.lock
generated
7
Cargo.lock
generated
|
@ -38,6 +38,7 @@ version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"advent",
|
"advent",
|
||||||
"clap",
|
"clap",
|
||||||
|
"indoc",
|
||||||
"tokio",
|
"tokio",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -621,6 +622,12 @@ dependencies = [
|
||||||
"hashbrown",
|
"hashbrown",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "indoc"
|
||||||
|
version = "2.0.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1e186cfbae8084e513daff4240b4797e342f988cecda4fb6c939150f96315fd8"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ipnet"
|
name = "ipnet"
|
||||||
version = "2.9.0"
|
version = "2.9.0"
|
||||||
|
|
|
@ -6,4 +6,5 @@ edition = "2021"
|
||||||
[dependencies]
|
[dependencies]
|
||||||
clap = { version = "4.4.10", features = ["derive"] }
|
clap = { version = "4.4.10", features = ["derive"] }
|
||||||
tokio = { version = "1.34.0", features = ["macros", "rt-multi-thread"] }
|
tokio = { version = "1.34.0", features = ["macros", "rt-multi-thread"] }
|
||||||
advent = { path = "../lib" }
|
advent = { path = "../lib" }
|
||||||
|
indoc = "2.0.4"
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
mod utils;
|
||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
io::Write,
|
io::Write,
|
||||||
time::{Duration, Instant},
|
time::{Duration, Instant},
|
||||||
|
@ -5,6 +7,7 @@ use std::{
|
||||||
|
|
||||||
use advent::fetcher;
|
use advent::fetcher;
|
||||||
use clap::{Parser, Subcommand, ValueEnum};
|
use clap::{Parser, Subcommand, ValueEnum};
|
||||||
|
use indoc::printdoc;
|
||||||
|
|
||||||
#[derive(Parser)]
|
#[derive(Parser)]
|
||||||
#[command(author, version, about, long_about = None)]
|
#[command(author, version, about, long_about = None)]
|
||||||
|
@ -152,32 +155,32 @@ async fn main() {
|
||||||
}
|
}
|
||||||
timings.drain(..=(warmup as usize));
|
timings.drain(..=(warmup as usize));
|
||||||
let avg = (timings.iter().sum::<Duration>() / n).as_nanos();
|
let avg = (timings.iter().sum::<Duration>() / n).as_nanos();
|
||||||
let deviation = (((timings.iter().max().unwrap().as_nanos()
|
let max = timings.iter().max().unwrap().as_nanos();
|
||||||
- timings.iter().min().unwrap().as_nanos())
|
let min = timings.iter().min().unwrap().as_nanos();
|
||||||
.pow(2)
|
let deviation = (((max - min).pow(2) / 16) as f64).sqrt() as u128;
|
||||||
/ 16) as f64)
|
let range = max - min;
|
||||||
.sqrt() as u128;
|
let median = if timings.len() % 2 == 0 {
|
||||||
|
(timings[timings.len()/2-1]+timings[timings.len()/2]).as_nanos() as f64 / 2.0
|
||||||
let (avg, avg_units) = if avg >= 1000000000 {
|
|
||||||
(avg as f64 / 1000000000.0, "s")
|
|
||||||
} else if avg >= 1000000 {
|
|
||||||
(avg as f64 / 1000000.0, "ms")
|
|
||||||
} else if avg >= 1000 {
|
|
||||||
(avg as f64 / 1000.0, "µs")
|
|
||||||
} else {
|
} else {
|
||||||
(avg as f64, "ns")
|
timings[timings.len()/2].as_nanos() as f64
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let (avg, avg_units) = utils::unitify(avg as f64);
|
||||||
|
let (max, max_units) = utils::unitify(max as f64);
|
||||||
|
let (min, min_units) = utils::unitify(min as f64);
|
||||||
|
let (deviation, deviation_units) = utils::unitify(deviation as f64);
|
||||||
|
let (range, range_units) = utils::unitify(range as f64);
|
||||||
|
let (median, median_units) = utils::unitify(median as f64);
|
||||||
|
|
||||||
let (deviation, deviation_units) = if deviation >= 1000000000 {
|
printdoc! {"
|
||||||
(deviation as f64 / 1000000000.0, "s")
|
\rAverage timing: {avg}{avg_units}
|
||||||
} else if deviation >= 1000000 {
|
|
|
||||||
(deviation as f64 / 1000000.0, "ms")
|
|-- Std. Deviation: {deviation}{deviation_units}
|
||||||
} else if deviation >= 1000 {
|
|-- Min: {min}{min_units}
|
||||||
(deviation as f64 / 1000.0, "µs")
|
|-- Median: {median}{median_units}
|
||||||
} else {
|
|-- Max: {max}{max_units}
|
||||||
(deviation as f64, "ns")
|
|-- Range: {range}{range_units}
|
||||||
};
|
"}
|
||||||
println!("\nAverage timing: {avg}{avg_units} ± {deviation}{deviation_units}");
|
|
||||||
}
|
}
|
||||||
Subcommands::Input { day } => {
|
Subcommands::Input { day } => {
|
||||||
println!("{}", fetcher::fetch_input(auth, day).await);
|
println!("{}", fetcher::fetch_input(auth, day).await);
|
||||||
|
|
11
cli/src/utils.rs
Normal file
11
cli/src/utils.rs
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
pub fn unitify(num: f64) -> (f64, &'static str) {
|
||||||
|
if num >= 1000000000.0 {
|
||||||
|
(num / 1000000000.0, "s")
|
||||||
|
} else if num >= 1000000.0 {
|
||||||
|
(num / 1000000.0, "ms")
|
||||||
|
} else if num >= 1000.0 {
|
||||||
|
(num / 1000.0, "µs")
|
||||||
|
} else {
|
||||||
|
(num, "ns")
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,13 +4,13 @@ use crate::utils::Day;
|
||||||
|
|
||||||
pub struct Beam {
|
pub struct Beam {
|
||||||
pub position: Position,
|
pub position: Position,
|
||||||
pub direction: Direction
|
pub direction: Direction,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Eq, Debug, PartialOrd, Ord)]
|
#[derive(Clone, PartialEq, Eq, Debug, PartialOrd, Ord)]
|
||||||
pub struct Position {
|
pub struct Position {
|
||||||
pub x: usize,
|
pub x: usize,
|
||||||
pub y: usize
|
pub y: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Debug)]
|
#[derive(Clone, PartialEq, Debug)]
|
||||||
|
@ -18,7 +18,7 @@ pub enum Direction {
|
||||||
Up,
|
Up,
|
||||||
Down,
|
Down,
|
||||||
Right,
|
Right,
|
||||||
Left
|
Left,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
|
@ -28,22 +28,35 @@ pub struct Day16 {
|
||||||
|
|
||||||
impl Day for Day16 {
|
impl Day for Day16 {
|
||||||
fn part1(&mut self) -> String {
|
fn part1(&mut self) -> String {
|
||||||
let grid = self.input.lines().map(|l| l.chars().collect_vec()).collect_vec();
|
let grid = self
|
||||||
|
.input
|
||||||
|
.lines()
|
||||||
|
.map(|l| l.chars().collect_vec())
|
||||||
|
.collect_vec();
|
||||||
let mut heated = Vec::<(Position, Direction)>::new();
|
let mut heated = Vec::<(Position, Direction)>::new();
|
||||||
let mut beams = Vec::from(const { [Beam { position: Position { x: 0, y: 0 }, direction: Direction::Right }] });
|
let mut beams = Vec::from(
|
||||||
|
const {
|
||||||
|
[Beam {
|
||||||
|
position: Position { x: 0, y: 0 },
|
||||||
|
direction: Direction::Right,
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
while beams.len() > 0 {
|
while beams.len() > 0 {
|
||||||
|
|
||||||
// Step all beams
|
// Step all beams
|
||||||
for mut beam in std::mem::take(&mut beams).into_iter() {
|
for mut beam in std::mem::take(&mut beams).into_iter() {
|
||||||
let already_heated = heated.iter().filter(|(pos, dir)| pos == &beam.position && dir == &beam.direction).collect_vec();
|
let already_heated = heated
|
||||||
|
.iter()
|
||||||
|
.filter(|(pos, dir)| pos == &beam.position && dir == &beam.direction)
|
||||||
|
.collect_vec();
|
||||||
|
|
||||||
if already_heated.len() == 0 {
|
if already_heated.len() == 0 {
|
||||||
heated.push((beam.position.clone(), beam.direction.clone()));
|
heated.push((beam.position.clone(), beam.direction.clone()));
|
||||||
} else {
|
} else {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
match grid[beam.position.y][beam.position.x] {
|
match grid[beam.position.y][beam.position.x] {
|
||||||
'/' => match beam.direction {
|
'/' => match beam.direction {
|
||||||
Direction::Up => beam.direction = Direction::Right,
|
Direction::Up => beam.direction = Direction::Right,
|
||||||
|
@ -59,29 +72,63 @@ impl Day for Day16 {
|
||||||
},
|
},
|
||||||
'|' => match beam.direction {
|
'|' => match beam.direction {
|
||||||
Direction::Left | Direction::Right => {
|
Direction::Left | Direction::Right => {
|
||||||
if beam.position.y != 0 { beams.push(Beam { position: Position { x: beam.position.x, y: beam.position.y - 1 }, direction: Direction::Up }) }
|
if beam.position.y != 0 {
|
||||||
if beam.position.y != grid.len() - 1 { beams.push(Beam { position: Position { x: beam.position.x, y: beam.position.y + 1 }, direction: Direction::Down }) }
|
beams.push(Beam {
|
||||||
continue
|
position: Position {
|
||||||
},
|
x: beam.position.x,
|
||||||
_ => ()
|
y: beam.position.y - 1,
|
||||||
|
},
|
||||||
|
direction: Direction::Up,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
if beam.position.y != grid.len() - 1 {
|
||||||
|
beams.push(Beam {
|
||||||
|
position: Position {
|
||||||
|
x: beam.position.x,
|
||||||
|
y: beam.position.y + 1,
|
||||||
|
},
|
||||||
|
direction: Direction::Down,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
},
|
},
|
||||||
'-' => match beam.direction {
|
'-' => match beam.direction {
|
||||||
Direction::Up | Direction::Down => {
|
Direction::Up | Direction::Down => {
|
||||||
if beam.position.x != 0 { beams.push(Beam { position: Position { x: beam.position.x - 1, y: beam.position.y }, direction: Direction::Left }) }
|
if beam.position.x != 0 {
|
||||||
if beam.position.x != grid[0].len() - 1 { beams.push(Beam { position: Position { x: beam.position.x + 1, y: beam.position.y }, direction: Direction::Right }) }
|
beams.push(Beam {
|
||||||
continue
|
position: Position {
|
||||||
},
|
x: beam.position.x - 1,
|
||||||
_ => ()
|
y: beam.position.y,
|
||||||
|
},
|
||||||
|
direction: Direction::Left,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
if beam.position.x != grid[0].len() - 1 {
|
||||||
|
beams.push(Beam {
|
||||||
|
position: Position {
|
||||||
|
x: beam.position.x + 1,
|
||||||
|
y: beam.position.y,
|
||||||
|
},
|
||||||
|
direction: Direction::Right,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
},
|
},
|
||||||
_ => ()
|
_ => (),
|
||||||
}
|
}
|
||||||
|
|
||||||
match beam.direction {
|
match beam.direction {
|
||||||
Direction::Up if beam.position.y != 0 => beam.position.y -= 1,
|
Direction::Up if beam.position.y != 0 => beam.position.y -= 1,
|
||||||
Direction::Down if beam.position.y != grid.len() - 1 => beam.position.y += 1,
|
Direction::Down if beam.position.y != grid.len() - 1 => beam.position.y += 1,
|
||||||
Direction::Right if beam.position.x != grid[0].len() - 1 => beam.position.x += 1,
|
Direction::Right if beam.position.x != grid[0].len() - 1 => {
|
||||||
|
beam.position.x += 1
|
||||||
|
}
|
||||||
Direction::Left if beam.position.x != 0 => beam.position.x -= 1,
|
Direction::Left if beam.position.x != 0 => beam.position.x -= 1,
|
||||||
_ => continue // If it hit the wall, skull issue, don't add it back to the vec
|
_ => continue, // If it hit the wall, skull issue, don't add it back to the vec
|
||||||
}
|
}
|
||||||
|
|
||||||
beams.push(beam);
|
beams.push(beam);
|
||||||
|
@ -98,38 +145,58 @@ impl Day for Day16 {
|
||||||
// .join("\n")
|
// .join("\n")
|
||||||
// );
|
// );
|
||||||
|
|
||||||
heated.into_iter().map(|(pos, _)| pos).sorted().dedup().count().to_string()
|
heated
|
||||||
|
.into_iter()
|
||||||
|
.map(|(pos, _)| pos)
|
||||||
|
.sorted()
|
||||||
|
.dedup()
|
||||||
|
.count()
|
||||||
|
.to_string()
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO Don't do this the stupid way, use DP/caching lol
|
// TODO Don't do this the stupid way, use DP/caching lol
|
||||||
fn part2(&mut self) -> String {
|
fn part2(&mut self) -> String {
|
||||||
let grid = self.input.lines().map(|l| l.chars().collect_vec()).collect_vec();
|
let grid = self
|
||||||
|
.input
|
||||||
|
.lines()
|
||||||
|
.map(|l| l.chars().collect_vec())
|
||||||
|
.collect_vec();
|
||||||
let mut max = 0usize;
|
let mut max = 0usize;
|
||||||
|
|
||||||
for y in 0..grid.len() {
|
for y in 0..grid.len() {
|
||||||
for x in 0..grid[0].len() {
|
for x in 0..grid[0].len() {
|
||||||
let dir =
|
let dir = if x == 0 {
|
||||||
if x == 0 { Direction::Left }
|
Direction::Left
|
||||||
else if x == grid[0].len() - 1 { Direction::Right }
|
} else if x == grid[0].len() - 1 {
|
||||||
else if y == 0 { Direction::Down }
|
Direction::Right
|
||||||
else if y == grid.len() - 1 { Direction::Up }
|
} else if y == 0 {
|
||||||
else { continue };
|
Direction::Down
|
||||||
|
} else if y == grid.len() - 1 {
|
||||||
|
Direction::Up
|
||||||
|
} else {
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
|
||||||
let mut heated = Vec::<(Position, Direction)>::new();
|
let mut heated = Vec::<(Position, Direction)>::new();
|
||||||
let mut beams = Vec::from([Beam { position: Position { x, y }, direction: dir }]);
|
let mut beams = Vec::from([Beam {
|
||||||
|
position: Position { x, y },
|
||||||
|
direction: dir,
|
||||||
|
}]);
|
||||||
|
|
||||||
while beams.len() > 0 {
|
while beams.len() > 0 {
|
||||||
|
|
||||||
// Step all beams
|
// Step all beams
|
||||||
for mut beam in std::mem::take(&mut beams).into_iter() {
|
for mut beam in std::mem::take(&mut beams).into_iter() {
|
||||||
let already_heated = heated.iter().filter(|(pos, dir)| pos == &beam.position && dir == &beam.direction).collect_vec();
|
let already_heated = heated
|
||||||
|
.iter()
|
||||||
|
.filter(|(pos, dir)| pos == &beam.position && dir == &beam.direction)
|
||||||
|
.collect_vec();
|
||||||
|
|
||||||
if already_heated.len() == 0 {
|
if already_heated.len() == 0 {
|
||||||
heated.push((beam.position.clone(), beam.direction.clone()));
|
heated.push((beam.position.clone(), beam.direction.clone()));
|
||||||
} else {
|
} else {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
match grid[beam.position.y][beam.position.x] {
|
match grid[beam.position.y][beam.position.x] {
|
||||||
'/' => match beam.direction {
|
'/' => match beam.direction {
|
||||||
Direction::Up => beam.direction = Direction::Right,
|
Direction::Up => beam.direction = Direction::Right,
|
||||||
|
@ -145,29 +212,65 @@ impl Day for Day16 {
|
||||||
},
|
},
|
||||||
'|' => match beam.direction {
|
'|' => match beam.direction {
|
||||||
Direction::Left | Direction::Right => {
|
Direction::Left | Direction::Right => {
|
||||||
if beam.position.y != 0 { beams.push(Beam { position: Position { x: beam.position.x, y: beam.position.y - 1 }, direction: Direction::Up }) }
|
if beam.position.y != 0 {
|
||||||
if beam.position.y != grid.len() - 1 { beams.push(Beam { position: Position { x: beam.position.x, y: beam.position.y + 1 }, direction: Direction::Down }) }
|
beams.push(Beam {
|
||||||
continue
|
position: Position {
|
||||||
},
|
x: beam.position.x,
|
||||||
_ => ()
|
y: beam.position.y - 1,
|
||||||
|
},
|
||||||
|
direction: Direction::Up,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
if beam.position.y != grid.len() - 1 {
|
||||||
|
beams.push(Beam {
|
||||||
|
position: Position {
|
||||||
|
x: beam.position.x,
|
||||||
|
y: beam.position.y + 1,
|
||||||
|
},
|
||||||
|
direction: Direction::Down,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
},
|
},
|
||||||
'-' => match beam.direction {
|
'-' => match beam.direction {
|
||||||
Direction::Up | Direction::Down => {
|
Direction::Up | Direction::Down => {
|
||||||
if beam.position.x != 0 { beams.push(Beam { position: Position { x: beam.position.x - 1, y: beam.position.y }, direction: Direction::Left }) }
|
if beam.position.x != 0 {
|
||||||
if beam.position.x != grid[0].len() - 1 { beams.push(Beam { position: Position { x: beam.position.x + 1, y: beam.position.y }, direction: Direction::Right }) }
|
beams.push(Beam {
|
||||||
continue
|
position: Position {
|
||||||
},
|
x: beam.position.x - 1,
|
||||||
_ => ()
|
y: beam.position.y,
|
||||||
|
},
|
||||||
|
direction: Direction::Left,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
if beam.position.x != grid[0].len() - 1 {
|
||||||
|
beams.push(Beam {
|
||||||
|
position: Position {
|
||||||
|
x: beam.position.x + 1,
|
||||||
|
y: beam.position.y,
|
||||||
|
},
|
||||||
|
direction: Direction::Right,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
},
|
},
|
||||||
_ => ()
|
_ => (),
|
||||||
}
|
}
|
||||||
|
|
||||||
match beam.direction {
|
match beam.direction {
|
||||||
Direction::Up if beam.position.y != 0 => beam.position.y -= 1,
|
Direction::Up if beam.position.y != 0 => beam.position.y -= 1,
|
||||||
Direction::Down if beam.position.y != grid.len() - 1 => beam.position.y += 1,
|
Direction::Down if beam.position.y != grid.len() - 1 => {
|
||||||
Direction::Right if beam.position.x != grid[0].len() - 1 => beam.position.x += 1,
|
beam.position.y += 1
|
||||||
|
}
|
||||||
|
Direction::Right if beam.position.x != grid[0].len() - 1 => {
|
||||||
|
beam.position.x += 1
|
||||||
|
}
|
||||||
Direction::Left if beam.position.x != 0 => beam.position.x -= 1,
|
Direction::Left if beam.position.x != 0 => beam.position.x -= 1,
|
||||||
_ => continue // If it hit the wall, skull issue, don't add it back to the vec
|
_ => continue, // If it hit the wall, skull issue, don't add it back to the vec
|
||||||
}
|
}
|
||||||
|
|
||||||
beams.push(beam);
|
beams.push(beam);
|
||||||
|
@ -184,8 +287,15 @@ impl Day for Day16 {
|
||||||
// .join("\n")
|
// .join("\n")
|
||||||
// );
|
// );
|
||||||
|
|
||||||
let result = heated.into_iter().map(|(pos, _)| pos).sorted().dedup().count();
|
let result = heated
|
||||||
if max < result { max = result; }
|
.into_iter()
|
||||||
|
.map(|(pos, _)| pos)
|
||||||
|
.sorted()
|
||||||
|
.dedup()
|
||||||
|
.count();
|
||||||
|
if max < result {
|
||||||
|
max = result;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue