Compare commits
No commits in common. "603ee1827d494a83ef86851e27b49f6320db9fdf" and "4970f247f3d1c63e274abcc4345b3ea03964d52e" have entirely different histories.
603ee1827d
...
4970f247f3
19 changed files with 162 additions and 512 deletions
207
Cargo.lock
generated
207
Cargo.lock
generated
|
@ -8,10 +8,10 @@ version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"clap",
|
"clap",
|
||||||
|
"colonnade",
|
||||||
"derive_more",
|
"derive_more",
|
||||||
"env_logger",
|
"env_logger",
|
||||||
"log",
|
"log",
|
||||||
"prettytable-rs",
|
|
||||||
"ron",
|
"ron",
|
||||||
"serde",
|
"serde",
|
||||||
"solutions_advent_of_code_2023",
|
"solutions_advent_of_code_2023",
|
||||||
|
@ -97,12 +97,6 @@ dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "cfg-if"
|
|
||||||
version = "1.0.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap"
|
name = "clap"
|
||||||
version = "4.5.16"
|
version = "4.5.16"
|
||||||
|
@ -143,6 +137,16 @@ version = "0.7.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97"
|
checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "colonnade"
|
||||||
|
version = "1.3.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "833230a1f610c0f3418a80b03c387be9de15b1172b3785b702961ead07e3e475"
|
||||||
|
dependencies = [
|
||||||
|
"strip-ansi-escapes",
|
||||||
|
"unicode-segmentation",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "colorchoice"
|
name = "colorchoice"
|
||||||
version = "1.0.2"
|
version = "1.0.2"
|
||||||
|
@ -155,7 +159,7 @@ version = "0.15.8"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0e1f83fc076bd6dd27517eacdf25fef6c4dfe5f1d7448bafaaf3a26f13b5e4eb"
|
checksum = "0e1f83fc076bd6dd27517eacdf25fef6c4dfe5f1d7448bafaaf3a26f13b5e4eb"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"encode_unicode 0.3.6",
|
"encode_unicode",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
"libc",
|
"libc",
|
||||||
"windows-sys",
|
"windows-sys",
|
||||||
|
@ -170,27 +174,6 @@ dependencies = [
|
||||||
"unicode-segmentation",
|
"unicode-segmentation",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "csv"
|
|
||||||
version = "1.3.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "ac574ff4d437a7b5ad237ef331c17ccca63c46479e5b5453eb8e10bb99a759fe"
|
|
||||||
dependencies = [
|
|
||||||
"csv-core",
|
|
||||||
"itoa",
|
|
||||||
"ryu",
|
|
||||||
"serde",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "csv-core"
|
|
||||||
version = "0.1.11"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "5efa2b3d7902f4b634a20cae3c9c4e6209dc4779feb6863329607560143efa70"
|
|
||||||
dependencies = [
|
|
||||||
"memchr",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "derive_more"
|
name = "derive_more"
|
||||||
version = "1.0.0"
|
version = "1.0.0"
|
||||||
|
@ -213,39 +196,12 @@ dependencies = [
|
||||||
"unicode-xid",
|
"unicode-xid",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "dirs-next"
|
|
||||||
version = "2.0.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1"
|
|
||||||
dependencies = [
|
|
||||||
"cfg-if",
|
|
||||||
"dirs-sys-next",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "dirs-sys-next"
|
|
||||||
version = "0.1.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d"
|
|
||||||
dependencies = [
|
|
||||||
"libc",
|
|
||||||
"redox_users",
|
|
||||||
"winapi",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "encode_unicode"
|
name = "encode_unicode"
|
||||||
version = "0.3.6"
|
version = "0.3.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f"
|
checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "encode_unicode"
|
|
||||||
version = "1.0.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "env_filter"
|
name = "env_filter"
|
||||||
version = "0.1.2"
|
version = "0.1.2"
|
||||||
|
@ -269,29 +225,12 @@ dependencies = [
|
||||||
"log",
|
"log",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "getrandom"
|
|
||||||
version = "0.2.15"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7"
|
|
||||||
dependencies = [
|
|
||||||
"cfg-if",
|
|
||||||
"libc",
|
|
||||||
"wasi",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "heck"
|
name = "heck"
|
||||||
version = "0.5.0"
|
version = "0.5.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
|
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "hermit-abi"
|
|
||||||
version = "0.4.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "humantime"
|
name = "humantime"
|
||||||
version = "2.1.0"
|
version = "2.1.0"
|
||||||
|
@ -310,29 +249,12 @@ dependencies = [
|
||||||
"similar",
|
"similar",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "is-terminal"
|
|
||||||
version = "0.4.13"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "261f68e344040fbd0edea105bef17c66edf46f984ddb1115b775ce31be948f4b"
|
|
||||||
dependencies = [
|
|
||||||
"hermit-abi",
|
|
||||||
"libc",
|
|
||||||
"windows-sys",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "is_terminal_polyfill"
|
name = "is_terminal_polyfill"
|
||||||
version = "1.70.1"
|
version = "1.70.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf"
|
checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "itoa"
|
|
||||||
version = "1.0.11"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lazy_static"
|
name = "lazy_static"
|
||||||
version = "1.5.0"
|
version = "1.5.0"
|
||||||
|
@ -345,16 +267,6 @@ version = "0.2.158"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439"
|
checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "libredox"
|
|
||||||
version = "0.1.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d"
|
|
||||||
dependencies = [
|
|
||||||
"bitflags",
|
|
||||||
"libc",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "linked-hash-map"
|
name = "linked-hash-map"
|
||||||
version = "0.5.6"
|
version = "0.5.6"
|
||||||
|
@ -373,20 +285,6 @@ version = "2.7.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
|
checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "prettytable-rs"
|
|
||||||
version = "0.10.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "eea25e07510aa6ab6547308ebe3c036016d162b8da920dbb079e3ba8acf3d95a"
|
|
||||||
dependencies = [
|
|
||||||
"csv",
|
|
||||||
"encode_unicode 1.0.0",
|
|
||||||
"is-terminal",
|
|
||||||
"lazy_static",
|
|
||||||
"term",
|
|
||||||
"unicode-width",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro2"
|
name = "proc-macro2"
|
||||||
version = "1.0.86"
|
version = "1.0.86"
|
||||||
|
@ -405,17 +303,6 @@ dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "redox_users"
|
|
||||||
version = "0.4.6"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43"
|
|
||||||
dependencies = [
|
|
||||||
"getrandom",
|
|
||||||
"libredox",
|
|
||||||
"thiserror",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "regex"
|
name = "regex"
|
||||||
version = "1.10.6"
|
version = "1.10.6"
|
||||||
|
@ -457,18 +344,6 @@ dependencies = [
|
||||||
"serde_derive",
|
"serde_derive",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "rustversion"
|
|
||||||
version = "1.0.17"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "ryu"
|
|
||||||
version = "1.0.18"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde"
|
name = "serde"
|
||||||
version = "1.0.209"
|
version = "1.0.209"
|
||||||
|
@ -505,6 +380,15 @@ dependencies = [
|
||||||
"thiserror",
|
"thiserror",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "strip-ansi-escapes"
|
||||||
|
version = "0.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "55ff8ef943b384c414f54aefa961dd2bd853add74ec75e7ac74cf91dba62bcfa"
|
||||||
|
dependencies = [
|
||||||
|
"vte",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "strsim"
|
name = "strsim"
|
||||||
version = "0.11.1"
|
version = "0.11.1"
|
||||||
|
@ -522,17 +406,6 @@ dependencies = [
|
||||||
"unicode-ident",
|
"unicode-ident",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "term"
|
|
||||||
version = "0.7.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "c59df8ac95d96ff9bede18eb7300b0fda5e5d8d90960e76f8e14ae765eedbf1f"
|
|
||||||
dependencies = [
|
|
||||||
"dirs-next",
|
|
||||||
"rustversion",
|
|
||||||
"winapi",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "thiserror"
|
name = "thiserror"
|
||||||
version = "1.0.63"
|
version = "1.0.63"
|
||||||
|
@ -565,12 +438,6 @@ version = "1.11.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202"
|
checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "unicode-width"
|
|
||||||
version = "0.1.13"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "0336d538f7abc86d282a4189614dfaa90810dfc2c6f6427eaf88e16311dd225d"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-xid"
|
name = "unicode-xid"
|
||||||
version = "0.2.5"
|
version = "0.2.5"
|
||||||
|
@ -584,32 +451,24 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
|
checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasi"
|
name = "vte"
|
||||||
version = "0.11.0+wasi-snapshot-preview1"
|
version = "0.11.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
checksum = "f5022b5fbf9407086c180e9557be968742d839e68346af7792b8592489732197"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "winapi"
|
|
||||||
version = "0.3.9"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"winapi-i686-pc-windows-gnu",
|
"utf8parse",
|
||||||
"winapi-x86_64-pc-windows-gnu",
|
"vte_generate_state_changes",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "winapi-i686-pc-windows-gnu"
|
name = "vte_generate_state_changes"
|
||||||
version = "0.4.0"
|
version = "0.1.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
checksum = "2e369bee1b05d510a7b4ed645f5faa90619e05437111783ea5848f28d97d3c2e"
|
||||||
|
dependencies = [
|
||||||
[[package]]
|
"proc-macro2",
|
||||||
name = "winapi-x86_64-pc-windows-gnu"
|
"quote",
|
||||||
version = "0.4.0"
|
]
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows-sys"
|
name = "windows-sys"
|
||||||
|
|
|
@ -15,4 +15,4 @@ env_logger = "0.11.5"
|
||||||
log = "0.4.22"
|
log = "0.4.22"
|
||||||
anyhow = "1.0.86"
|
anyhow = "1.0.86"
|
||||||
ron = "0.8.1"
|
ron = "0.8.1"
|
||||||
prettytable-rs = "0.10.0"
|
colonnade = "1.3.3"
|
||||||
|
|
|
@ -1,52 +1,43 @@
|
||||||
pub use conducted_benchmark::ConductedBenchmark;
|
pub use benchmark_result::BenchmarkResult;
|
||||||
pub use file_to_benchmark::FileToBenchmark;
|
pub use file_to_benchmark::FileToBenchmark;
|
||||||
|
|
||||||
use prettytable::Table;
|
mod benchmark_result;
|
||||||
|
|
||||||
mod conducted_benchmark;
|
|
||||||
mod file_to_benchmark;
|
mod file_to_benchmark;
|
||||||
mod row_builder;
|
|
||||||
mod row_building;
|
mod row_building;
|
||||||
|
|
||||||
use crate::{
|
use crate::{cli::BenchmarkCli, solving_given::solve_given, AppResult};
|
||||||
cli::BenchmarkCli,
|
|
||||||
solving_given::{solve_given, NoSolutionFound},
|
|
||||||
AppError, AppResult,
|
|
||||||
};
|
|
||||||
use anyhow::anyhow;
|
use anyhow::anyhow;
|
||||||
|
use colonnade::Colonnade;
|
||||||
use std::time::{Duration, Instant};
|
use std::time::{Duration, Instant};
|
||||||
|
|
||||||
pub type BenchmarkResult = Result<ConductedBenchmark, NoSolutionFound>;
|
fn calc_average(sum: Duration, nanos_count: u64) -> Duration {
|
||||||
|
let average_raw = sum.div_duration_f64(Duration::from_nanos(nanos_count));
|
||||||
pub fn execute_benchmark(args: &BenchmarkCli) -> AppResult<Table> {
|
Duration::from_nanos(average_raw.round() as u64)
|
||||||
|
}
|
||||||
|
pub fn execute_benchmark(args: &BenchmarkCli) -> AppResult<String> {
|
||||||
let loaded = load_benchmarks(args)?;
|
let loaded = load_benchmarks(args)?;
|
||||||
|
let benchmarked = loaded
|
||||||
let benchmarked = loaded.into_iter().map(solve_and_keep_track_of_runtime);
|
.into_iter()
|
||||||
|
.map(solve_and_keep_track_of_runtime)
|
||||||
let mut sum: Duration = Duration::ZERO;
|
.collect::<AppResult<Vec<BenchmarkResult>>>()?;
|
||||||
let mut count: u64 = 0;
|
let sum: Duration = benchmarked.iter().map(|result| result.how_long()).sum();
|
||||||
let after_header = row_building::create_rows_for_every_solutions(benchmarked, |to_add| {
|
let average = calc_average(sum, benchmarked.len() as u64);
|
||||||
sum += to_add;
|
let header = row_building::create_header();
|
||||||
count += 1;
|
let after_header = row_building::create_rows_for_every_solutions(benchmarked);
|
||||||
});
|
let table: Vec<Vec<String>> = after_header
|
||||||
let average = calc_average(sum, count);
|
|
||||||
|
|
||||||
let mut table = Table::new();
|
|
||||||
let rows = after_header
|
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.chain(row_building::create_sum_row(sum))
|
.chain(row_building::create_sum_row(sum))
|
||||||
.chain(row_building::create_average_row(average))
|
.chain(row_building::create_average_row(average))
|
||||||
.chain(row_building::create_header());
|
.chain(header)
|
||||||
for next_row in rows {
|
.collect();
|
||||||
table.add_row(next_row);
|
let lines = Colonnade::new(5, 100).unwrap().tabulate(table)?;
|
||||||
}
|
|
||||||
|
|
||||||
Ok(table)
|
Ok(lines.join("\n"))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn solve_and_keep_track_of_runtime(
|
fn solve_and_keep_track_of_runtime(
|
||||||
(benchmark, content): (FileToBenchmark, String),
|
(benchmark, content): (FileToBenchmark, String),
|
||||||
) -> Result<ConductedBenchmark, NoSolutionFound> {
|
) -> AppResult<BenchmarkResult> {
|
||||||
let (day, task) = (benchmark.given_day(), benchmark.given_task());
|
let (day, task) = (benchmark.given_day(), benchmark.given_task());
|
||||||
let before = Instant::now();
|
let before = Instant::now();
|
||||||
let actual_ouput = solve_given(day, task, &content)?;
|
let actual_ouput = solve_given(day, task, &content)?;
|
||||||
|
@ -54,14 +45,15 @@ fn solve_and_keep_track_of_runtime(
|
||||||
|
|
||||||
let how_long = after - before;
|
let how_long = after - before;
|
||||||
|
|
||||||
let result = ConductedBenchmark::new(benchmark, actual_ouput, how_long);
|
let result = BenchmarkResult::new(benchmark, actual_ouput, how_long);
|
||||||
Ok(result)
|
Ok(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn load_benchmarks(args: &BenchmarkCli) -> AppResult<Vec<(FileToBenchmark, String)>> {
|
fn load_benchmarks(args: &BenchmarkCli) -> AppResult<Vec<(FileToBenchmark, String)>> {
|
||||||
args.files()
|
let benchmarks = args
|
||||||
|
.files()
|
||||||
.iter()
|
.iter()
|
||||||
.flat_map(|path| {
|
.map(|path| {
|
||||||
let content = std::fs::read_to_string(path).map_err(|error| {
|
let content = std::fs::read_to_string(path).map_err(|error| {
|
||||||
anyhow!(
|
anyhow!(
|
||||||
"Could not read benchmark file at {:?}\n\
|
"Could not read benchmark file at {:?}\n\
|
||||||
|
@ -78,9 +70,14 @@ fn load_benchmarks(args: &BenchmarkCli) -> AppResult<Vec<(FileToBenchmark, Strin
|
||||||
error
|
error
|
||||||
)
|
)
|
||||||
})?;
|
})?;
|
||||||
Ok::<_, AppError>(parsed)
|
Ok(parsed)
|
||||||
})
|
})
|
||||||
.flatten()
|
.collect::<AppResult<Vec<Vec<FileToBenchmark>>>>()?
|
||||||
|
.into_iter()
|
||||||
|
.flatten();
|
||||||
|
|
||||||
|
benchmarks
|
||||||
|
.into_iter()
|
||||||
.map(|benchmark| {
|
.map(|benchmark| {
|
||||||
let where_to_look = benchmark.where_to_look();
|
let where_to_look = benchmark.where_to_look();
|
||||||
let content = std::fs::read_to_string(where_to_look).map_err(|error| {
|
let content = std::fs::read_to_string(where_to_look).map_err(|error| {
|
||||||
|
@ -95,10 +92,5 @@ fn load_benchmarks(args: &BenchmarkCli) -> AppResult<Vec<(FileToBenchmark, Strin
|
||||||
})?;
|
})?;
|
||||||
Ok((benchmark, content))
|
Ok((benchmark, content))
|
||||||
})
|
})
|
||||||
.collect()
|
.collect::<AppResult<Vec<(FileToBenchmark, String)>>>()
|
||||||
}
|
|
||||||
|
|
||||||
fn calc_average(sum: Duration, nanos_count: u64) -> Duration {
|
|
||||||
let average_raw = sum.div_duration_f64(Duration::from_nanos(nanos_count));
|
|
||||||
Duration::from_nanos(average_raw.round() as u64)
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,25 +1,21 @@
|
||||||
use std::{
|
use std::time::Duration;
|
||||||
path::{Path, PathBuf},
|
|
||||||
time::Duration,
|
|
||||||
};
|
|
||||||
|
|
||||||
use crate::cli::{GivenDay, GivenTask};
|
use crate::cli::{GivenDay, GivenTask};
|
||||||
|
|
||||||
use super::FileToBenchmark;
|
use super::FileToBenchmark;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct ConductedBenchmark {
|
pub struct BenchmarkResult {
|
||||||
task: GivenTask,
|
task: GivenTask,
|
||||||
day: GivenDay,
|
day: GivenDay,
|
||||||
how_long: Duration,
|
how_long: Duration,
|
||||||
maybe_different_actual_output: Option<String>,
|
maybe_different_actual_output: Option<String>,
|
||||||
expected_output: String,
|
expected_output: String,
|
||||||
path_of_input: PathBuf,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ConductedBenchmark {
|
impl BenchmarkResult {
|
||||||
pub fn new(benchmarking: FileToBenchmark, actual_ouput: String, how_long: Duration) -> Self {
|
pub fn new(benchmarking: FileToBenchmark, actual_ouput: String, how_long: Duration) -> Self {
|
||||||
let (day, task, expected_output, path_of_input) = benchmarking.into();
|
let (day, task, expected_output) = benchmarking.into();
|
||||||
let maybe_different_actual_output = if actual_ouput == expected_output {
|
let maybe_different_actual_output = if actual_ouput == expected_output {
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
|
@ -31,7 +27,6 @@ impl ConductedBenchmark {
|
||||||
how_long,
|
how_long,
|
||||||
maybe_different_actual_output,
|
maybe_different_actual_output,
|
||||||
expected_output,
|
expected_output,
|
||||||
path_of_input,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -68,8 +63,4 @@ impl ConductedBenchmark {
|
||||||
let mili_secs = how_long.as_nanos() % 1_000_000_000;
|
let mili_secs = how_long.as_nanos() % 1_000_000_000;
|
||||||
format!("{}:{}", secs, mili_secs)
|
format!("{}:{}", secs, mili_secs)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn path_of_input(&self) -> &Path {
|
|
||||||
&self.path_of_input
|
|
||||||
}
|
|
||||||
}
|
}
|
|
@ -19,14 +19,9 @@ pub struct FileToBenchmark {
|
||||||
expected_output: String,
|
expected_output: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<FileToBenchmark> for (GivenDay, GivenTask, String, PathBuf) {
|
impl From<FileToBenchmark> for (GivenDay, GivenTask, String) {
|
||||||
fn from(val: FileToBenchmark) -> Self {
|
fn from(val: FileToBenchmark) -> Self {
|
||||||
(
|
(val.given_day, val.given_task, val.expected_output)
|
||||||
val.given_day,
|
|
||||||
val.given_task,
|
|
||||||
val.expected_output,
|
|
||||||
val.where_to_look,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,174 +0,0 @@
|
||||||
use std::{borrow::Cow, path::PathBuf, time::Duration};
|
|
||||||
|
|
||||||
const AVERAGE: &str = "Average";
|
|
||||||
const TOTAL: &str = "total";
|
|
||||||
|
|
||||||
use prettytable::{color, Row};
|
|
||||||
|
|
||||||
use crate::{
|
|
||||||
benchmarking::ConductedBenchmark,
|
|
||||||
cli::{GivenDay, GivenTask},
|
|
||||||
constants,
|
|
||||||
solving_given::NoSolutionFound,
|
|
||||||
};
|
|
||||||
|
|
||||||
type OptionalContent = Option<Cow<'static, str>>;
|
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
|
||||||
pub struct RowBuilder {
|
|
||||||
day: OptionalContent,
|
|
||||||
task: OptionalContent,
|
|
||||||
taken_time: OptionalContent,
|
|
||||||
actual_result: OptionalContent,
|
|
||||||
expected_result: OptionalContent,
|
|
||||||
path_to_input: OptionalContent,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<NoSolutionFound> for RowBuilder {
|
|
||||||
fn from(value: NoSolutionFound) -> Self {
|
|
||||||
match value {
|
|
||||||
NoSolutionFound::DayNotFound(day) => Self::no_day_found(day),
|
|
||||||
NoSolutionFound::TaskNotFound { day, task } => Self::no_task_found(day, task),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<ConductedBenchmark> for RowBuilder {
|
|
||||||
fn from(value: ConductedBenchmark) -> Self {
|
|
||||||
Self::new(
|
|
||||||
value.day(),
|
|
||||||
value.task(),
|
|
||||||
value.how_long(),
|
|
||||||
value
|
|
||||||
.maybe_different_actual_output()
|
|
||||||
.map(ToString::to_string)
|
|
||||||
.unwrap_or_default(),
|
|
||||||
value.expected_output().to_string(),
|
|
||||||
value.path_of_input().to_path_buf(),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fn into_borrowed_cell(some_thing: &'static str) -> OptionalContent {
|
|
||||||
Some(Cow::Borrowed(some_thing))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn into_owned_cell(some_thing: impl ToString) -> OptionalContent {
|
|
||||||
Some(Cow::Owned(some_thing.to_string()))
|
|
||||||
}
|
|
||||||
fn into_owned_cell_with<T>(some_thing: T, on_convert: impl Fn(T) -> String) -> OptionalContent {
|
|
||||||
Some(Cow::Owned(on_convert(some_thing)))
|
|
||||||
}
|
|
||||||
impl RowBuilder {
|
|
||||||
pub fn new(
|
|
||||||
day: GivenDay,
|
|
||||||
task: GivenTask,
|
|
||||||
taken_time: Duration,
|
|
||||||
actual_result: String,
|
|
||||||
expected_result: String,
|
|
||||||
path: PathBuf,
|
|
||||||
) -> Self {
|
|
||||||
Self {
|
|
||||||
day: into_owned_cell(day),
|
|
||||||
task: into_owned_cell(task),
|
|
||||||
taken_time: into_owned_cell_with(
|
|
||||||
taken_time,
|
|
||||||
ConductedBenchmark::convert_duration_to_secs_and_mili_txt,
|
|
||||||
),
|
|
||||||
actual_result: into_owned_cell(actual_result),
|
|
||||||
expected_result: into_owned_cell(expected_result),
|
|
||||||
path_to_input: into_owned_cell_with(path, |path| path.to_string_lossy().to_string()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn no_day_found(wrong_day: GivenDay) -> Self {
|
|
||||||
let day = into_owned_cell_with(wrong_day, |to_convert| {
|
|
||||||
format!("Solution found for day {}", to_convert)
|
|
||||||
});
|
|
||||||
Self {
|
|
||||||
day,
|
|
||||||
..Default::default()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn no_task_found(right_day: GivenDay, wrong_task: GivenTask) -> Self {
|
|
||||||
let day = into_owned_cell(right_day);
|
|
||||||
let task = into_owned_cell_with(wrong_task, |to_convert| {
|
|
||||||
format!("No solution found for task {}", to_convert)
|
|
||||||
});
|
|
||||||
Self {
|
|
||||||
day,
|
|
||||||
task,
|
|
||||||
..Default::default()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn header() -> Self {
|
|
||||||
Self {
|
|
||||||
day: into_borrowed_cell("Day"),
|
|
||||||
task: into_borrowed_cell("Task"),
|
|
||||||
taken_time: into_borrowed_cell("How long (Seconds:Nano)"),
|
|
||||||
actual_result: into_borrowed_cell("Actual"),
|
|
||||||
expected_result: into_borrowed_cell("Expected"),
|
|
||||||
path_to_input: into_borrowed_cell("Used input file"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn average(average: Duration) -> Self {
|
|
||||||
Self::new_aggreate(AVERAGE, average)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn total(total: Duration) -> Self {
|
|
||||||
Self::new_aggreate(TOTAL, total)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn this_or_placeholder(value: OptionalContent) -> prettytable::Cell {
|
|
||||||
let value = value.unwrap_or(Cow::Borrowed(constants::PLACEHOLDER_IN_BENCHMARK_REPORTS));
|
|
||||||
prettytable::Cell::new(&value)
|
|
||||||
}
|
|
||||||
fn color_red_if_non_static_value(actual_result: OptionalContent) -> prettytable::Cell {
|
|
||||||
let has_different_acutual_than_expected_and_is_no_label = actual_result
|
|
||||||
.as_ref()
|
|
||||||
.is_some_and(|might_be_borrow| matches!(might_be_borrow, Cow::Owned(_)));
|
|
||||||
let tmp = Self::this_or_placeholder(actual_result);
|
|
||||||
if has_different_acutual_than_expected_and_is_no_label {
|
|
||||||
tmp.with_style(prettytable::Attr::ForegroundColor(color::RED))
|
|
||||||
} else {
|
|
||||||
tmp
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pub fn into_row(self) -> Row {
|
|
||||||
let might_colored_red_actual = Self::color_red_if_non_static_value(self.actual_result);
|
|
||||||
|
|
||||||
let (day, task, taken_time, actual_result, expected_result, path) = (
|
|
||||||
Self::this_or_placeholder(self.day),
|
|
||||||
Self::this_or_placeholder(self.task),
|
|
||||||
Self::this_or_placeholder(self.taken_time),
|
|
||||||
might_colored_red_actual,
|
|
||||||
Self::this_or_placeholder(self.expected_result),
|
|
||||||
Self::this_or_placeholder(self.path_to_input),
|
|
||||||
);
|
|
||||||
|
|
||||||
prettytable::Row::new(vec![
|
|
||||||
day,
|
|
||||||
task,
|
|
||||||
taken_time,
|
|
||||||
actual_result,
|
|
||||||
expected_result,
|
|
||||||
path,
|
|
||||||
])
|
|
||||||
}
|
|
||||||
|
|
||||||
fn new_aggreate(label: &str, aggregate: Duration) -> Self {
|
|
||||||
let (day, task) = (into_owned_cell(label), into_owned_cell(label));
|
|
||||||
let taken_time = into_owned_cell_with(
|
|
||||||
aggregate,
|
|
||||||
ConductedBenchmark::convert_duration_to_secs_and_mili_txt,
|
|
||||||
);
|
|
||||||
Self {
|
|
||||||
day,
|
|
||||||
task,
|
|
||||||
taken_time,
|
|
||||||
..Default::default()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,35 +1,54 @@
|
||||||
pub type MatrixReport = Vec<Row>;
|
|
||||||
pub type SingleRow = std::iter::Once<Row>;
|
|
||||||
|
|
||||||
use prettytable::Row;
|
|
||||||
|
|
||||||
use super::{row_builder::RowBuilder, BenchmarkResult};
|
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
pub fn create_header() -> SingleRow {
|
use super::BenchmarkResult;
|
||||||
std::iter::once(RowBuilder::header().into_row())
|
type MatrixReport = Vec<Vec<String>>;
|
||||||
|
|
||||||
|
pub fn create_header() -> std::iter::Once<Vec<String>> {
|
||||||
|
std::iter::once(vec![
|
||||||
|
"Day".to_string(),
|
||||||
|
"Task".to_string(),
|
||||||
|
"How long (Seconds:Mili)".to_string(),
|
||||||
|
"Expected".to_string(),
|
||||||
|
"Actual".to_string(),
|
||||||
|
])
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_sum_row(sum: Duration) -> SingleRow {
|
pub fn create_sum_row(sum: Duration) -> std::iter::Once<Vec<String>> {
|
||||||
std::iter::once(RowBuilder::total(sum).into_row())
|
let passed_txt = BenchmarkResult::convert_duration_to_secs_and_mili_txt(sum);
|
||||||
|
std::iter::once(vec![
|
||||||
|
"Total".to_string(),
|
||||||
|
"Total".to_string(),
|
||||||
|
passed_txt,
|
||||||
|
"-".to_string(),
|
||||||
|
"-".to_string(),
|
||||||
|
])
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_average_row(average: Duration) -> SingleRow {
|
pub fn create_average_row(average: Duration) -> std::iter::Once<Vec<String>> {
|
||||||
std::iter::once(RowBuilder::average(average).into_row())
|
let passed_txt = BenchmarkResult::convert_duration_to_secs_and_mili_txt(average);
|
||||||
|
std::iter::once(vec![
|
||||||
|
"Average".to_string(),
|
||||||
|
"Average".to_string(),
|
||||||
|
passed_txt,
|
||||||
|
"-".to_string(),
|
||||||
|
"-".to_string(),
|
||||||
|
])
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_rows_for_every_solutions(
|
pub fn create_rows_for_every_solutions(loaded: Vec<BenchmarkResult>) -> MatrixReport {
|
||||||
loaded: impl IntoIterator<Item = BenchmarkResult>,
|
|
||||||
mut on_ok: impl FnMut(Duration),
|
|
||||||
) -> MatrixReport {
|
|
||||||
loaded
|
loaded
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|result| {
|
.map(|result| {
|
||||||
|
vec![
|
||||||
|
result.day().to_string(),
|
||||||
|
result.task().to_string(),
|
||||||
|
result.how_long_as_string(),
|
||||||
|
result.expected_output().to_string(),
|
||||||
result
|
result
|
||||||
.inspect(|on_success| on_ok(on_success.how_long()))
|
.maybe_different_actual_output()
|
||||||
.map(RowBuilder::from)
|
.map(|unowned| unowned.to_string())
|
||||||
.unwrap_or_else(RowBuilder::from)
|
.unwrap_or_else(|| result.expected_output().to_string()),
|
||||||
|
]
|
||||||
})
|
})
|
||||||
.map(RowBuilder::into_row)
|
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,2 @@
|
||||||
pub const MAX_DAY: u32 = 25;
|
pub const MAX_DAY: u32 = 25;
|
||||||
pub const MAX_TASK: u32 = 2;
|
pub const MAX_TASK: u32 = 2;
|
||||||
pub const PLACEHOLDER_IN_BENCHMARK_REPORTS: &str = "-";
|
|
||||||
|
|
|
@ -1,7 +1,3 @@
|
||||||
use std::fmt::Display;
|
|
||||||
|
|
||||||
use prettytable::Table;
|
|
||||||
|
|
||||||
pub mod benchmarking;
|
pub mod benchmarking;
|
||||||
pub mod cli;
|
pub mod cli;
|
||||||
pub mod constants;
|
pub mod constants;
|
||||||
|
@ -10,27 +6,3 @@ pub mod solving_given;
|
||||||
|
|
||||||
pub type AppError = anyhow::Error;
|
pub type AppError = anyhow::Error;
|
||||||
pub type AppResult<T = ()> = anyhow::Result<T>;
|
pub type AppResult<T = ()> = anyhow::Result<T>;
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub enum AppOutput {
|
|
||||||
JustString(String),
|
|
||||||
PrettyTable(Table),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl AppOutput {
|
|
||||||
pub fn print_std_out(&self) {
|
|
||||||
match self {
|
|
||||||
AppOutput::JustString(string) => println!("{}", string),
|
|
||||||
AppOutput::PrettyTable(table) => table.printstd(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for AppOutput {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
match self {
|
|
||||||
AppOutput::JustString(string) => f.write_str(string),
|
|
||||||
AppOutput::PrettyTable(table) => f.write_str(&table.to_string()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -4,7 +4,7 @@ use advent_of_code_2023::{
|
||||||
benchmarking::execute_benchmark,
|
benchmarking::execute_benchmark,
|
||||||
cli::{AppCliArgs, AppCliSubcommands},
|
cli::{AppCliArgs, AppCliSubcommands},
|
||||||
solving_given::solve_given_from_cli,
|
solving_given::solve_given_from_cli,
|
||||||
AppOutput, AppResult,
|
AppResult,
|
||||||
};
|
};
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
|
|
||||||
|
@ -14,7 +14,7 @@ fn main() -> ExitCode {
|
||||||
let solution = handle_command(&args);
|
let solution = handle_command(&args);
|
||||||
match solution {
|
match solution {
|
||||||
Ok(found_solution) => {
|
Ok(found_solution) => {
|
||||||
found_solution.print_std_out();
|
println!("{}", found_solution);
|
||||||
ExitCode::SUCCESS
|
ExitCode::SUCCESS
|
||||||
}
|
}
|
||||||
Err(error) => {
|
Err(error) => {
|
||||||
|
@ -24,13 +24,9 @@ fn main() -> ExitCode {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_command(args: &AppCliArgs) -> AppResult<AppOutput> {
|
fn handle_command(args: &AppCliArgs) -> AppResult<String> {
|
||||||
match args.sub_command() {
|
match args.sub_command() {
|
||||||
AppCliSubcommands::Solve(to_solve) => {
|
AppCliSubcommands::Solve(to_solve) => solve_given_from_cli(to_solve),
|
||||||
solve_given_from_cli(to_solve).map(AppOutput::JustString)
|
AppCliSubcommands::Benchmark(benchmark) => execute_benchmark(benchmark),
|
||||||
}
|
|
||||||
AppCliSubcommands::Benchmark(benchmark) => {
|
|
||||||
execute_benchmark(benchmark).map(AppOutput::PrettyTable)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,23 +7,16 @@ use crate::{
|
||||||
AppResult,
|
AppResult,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn solve_given(
|
pub fn solve_given(given_day: GivenDay, given_task: GivenTask, content: &str) -> AppResult<String> {
|
||||||
given_day: GivenDay,
|
|
||||||
given_task: GivenTask,
|
|
||||||
content: &str,
|
|
||||||
) -> Result<String, NoSolutionFound> {
|
|
||||||
let found_task = {
|
let found_task = {
|
||||||
let day: u32 = given_day.into();
|
let day: u32 = given_day.into();
|
||||||
let task: u32 = given_task.into();
|
let task: u32 = given_task.into();
|
||||||
let found_day = ALL_SOLUTIONS
|
let found_day = ALL_SOLUTIONS
|
||||||
.get(day.saturating_sub(1) as usize)
|
.get(day.saturating_sub(1) as usize)
|
||||||
.ok_or(NoSolutionFound::DayNotFound(given_day))?;
|
.ok_or_else(|| CouldNotSolveError::DayNotFound(day))?;
|
||||||
found_day
|
found_day
|
||||||
.get(task.saturating_sub(1) as usize)
|
.get(task.saturating_sub(1) as usize)
|
||||||
.ok_or(NoSolutionFound::TaskNotFound {
|
.ok_or_else(|| CouldNotSolveError::TaskNotFound { day, task })
|
||||||
day: given_day,
|
|
||||||
task: given_task,
|
|
||||||
})
|
|
||||||
}?;
|
}?;
|
||||||
|
|
||||||
let solved = (found_task)(content);
|
let solved = (found_task)(content);
|
||||||
|
@ -47,17 +40,11 @@ fn try_read_from_file_if_demanded(args: &CliSolutionToSolve) -> io::Result<Strin
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug, Error)]
|
||||||
pub enum CouldNotSolveError {
|
enum CouldNotSolveError {
|
||||||
#[error("{0}")]
|
#[error("There is no solution for the day {0}")]
|
||||||
NotFound(#[from] NoSolutionFound),
|
DayNotFound(u32),
|
||||||
|
#[error("There is not solution for task {task} under the day {day}")]
|
||||||
|
TaskNotFound { day: u32, task: u32 },
|
||||||
#[error("Could not read puzzel input from the given file\n {0}")]
|
#[error("Could not read puzzel input from the given file\n {0}")]
|
||||||
CouldNotReadFromFile(#[from] io::Error),
|
CouldNotReadFromFile(#[from] io::Error),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Error)]
|
|
||||||
pub enum NoSolutionFound {
|
|
||||||
#[error("There is no solution for the day {0}")]
|
|
||||||
DayNotFound(GivenDay),
|
|
||||||
#[error("There is not solution for task {task} under the day {day}")]
|
|
||||||
TaskNotFound { day: GivenDay, task: GivenTask },
|
|
||||||
}
|
|
||||||
|
|
|
@ -21,10 +21,13 @@ fn min_location_from_given_single_seeds(
|
||||||
let mut current_seed = *next_seed;
|
let mut current_seed = *next_seed;
|
||||||
for next_layer in layers {
|
for next_layer in layers {
|
||||||
for next_mapping in next_layer {
|
for next_mapping in next_layer {
|
||||||
if let Some(found_mapping) = next_mapping.map_point(current_seed) {
|
match next_mapping.map_point(current_seed) {
|
||||||
|
Some(found_mapping) => {
|
||||||
current_seed = found_mapping;
|
current_seed = found_mapping;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
None => (),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
min = current_seed.min(min);
|
min = current_seed.min(min);
|
||||||
|
@ -116,6 +119,7 @@ fn combine_single_to_ranges_for_seeds(single_seeds: &[UnsignedNumber]) -> Vec<Se
|
||||||
assert!(single_seeds.len() % 2 == 0);
|
assert!(single_seeds.len() % 2 == 0);
|
||||||
single_seeds
|
single_seeds
|
||||||
.chunks(2)
|
.chunks(2)
|
||||||
|
.into_iter()
|
||||||
.map(|array| match array {
|
.map(|array| match array {
|
||||||
[start, end] => {
|
[start, end] => {
|
||||||
let start = *start;
|
let start = *start;
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
use std::usize;
|
||||||
|
|
||||||
mod parsing;
|
mod parsing;
|
||||||
mod race_record;
|
mod race_record;
|
||||||
|
|
||||||
|
@ -9,12 +11,12 @@ pub fn solve_task_1(input: &str) -> String {
|
||||||
|
|
||||||
for next_record in parsed {
|
for next_record in parsed {
|
||||||
how_many_times_won *= all_rounds_of_durations(next_record.time())
|
how_many_times_won *= all_rounds_of_durations(next_record.time())
|
||||||
|
.into_iter()
|
||||||
.filter(|&distance| distance > next_record.reached_distance())
|
.filter(|&distance| distance > next_record.reached_distance())
|
||||||
.count() as NumericValue;
|
.count() as NumericValue;
|
||||||
}
|
}
|
||||||
how_many_times_won.to_string()
|
how_many_times_won.to_string()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn solve_task_2(input: &str) -> String {
|
pub fn solve_task_2(input: &str) -> String {
|
||||||
let parsed = parsing::parsing_part_2(input);
|
let parsed = parsing::parsing_part_2(input);
|
||||||
|
|
||||||
|
@ -27,6 +29,7 @@ pub fn solve_task_2(input: &str) -> String {
|
||||||
|
|
||||||
const FIRST_CYCLE_NO_DISTANCE: usize = 1;
|
const FIRST_CYCLE_NO_DISTANCE: usize = 1;
|
||||||
for (index, next_distance) in all_rounds_of_durations(parsed.time())
|
for (index, next_distance) in all_rounds_of_durations(parsed.time())
|
||||||
|
.into_iter()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.skip(FIRST_CYCLE_NO_DISTANCE)
|
.skip(FIRST_CYCLE_NO_DISTANCE)
|
||||||
{
|
{
|
||||||
|
|
|
@ -43,7 +43,7 @@ fn categorize_and_sort_with_a_joker(parsed: Vec<DealtHand>, joker: char) -> Vec<
|
||||||
|
|
||||||
fn calc_total_winning(sorted: &[CategorizedHand]) -> usize {
|
fn calc_total_winning(sorted: &[CategorizedHand]) -> usize {
|
||||||
sorted
|
sorted
|
||||||
.iter()
|
.into_iter()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.map(|(index, hand)| {
|
.map(|(index, hand)| {
|
||||||
let rank = index.saturating_add(1);
|
let rank = index.saturating_add(1);
|
||||||
|
|
|
@ -2,6 +2,7 @@ mod joker_ordered;
|
||||||
pub use joker_ordered::JokerOrdered;
|
pub use joker_ordered::JokerOrdered;
|
||||||
|
|
||||||
use crate::day7::second_ordering;
|
use crate::day7::second_ordering;
|
||||||
|
use std::usize;
|
||||||
|
|
||||||
use super::{dealt_hand::DealtHand, hand_kind::HandKind, second_ordering::StrengthOfSymbols};
|
use super::{dealt_hand::DealtHand, hand_kind::HandKind, second_ordering::StrengthOfSymbols};
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use std::str::FromStr;
|
use std::{str::FromStr, usize};
|
||||||
|
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
|
|
|
@ -42,7 +42,7 @@ impl From<(&'_ str, char)> for HandKind {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let duplicated_counted = calc_duplicate_counted(characters, |next| next != joker_char);
|
let duplicated_counted = calc_duplicate_counted(&characters, |next| next != joker_char);
|
||||||
|
|
||||||
let mut current_kind = choose_kind_from(&duplicated_counted);
|
let mut current_kind = choose_kind_from(&duplicated_counted);
|
||||||
let mut joker_count = get_joker_count(joker_char, characters);
|
let mut joker_count = get_joker_count(joker_char, characters);
|
||||||
|
@ -61,7 +61,7 @@ impl From<(&'_ str, char)> for HandKind {
|
||||||
|
|
||||||
impl From<&'_ str> for HandKind {
|
impl From<&'_ str> for HandKind {
|
||||||
fn from(value: &'_ str) -> Self {
|
fn from(value: &'_ str) -> Self {
|
||||||
let duplicated_counted = calc_duplicate_counted(value, |_| true);
|
let duplicated_counted = calc_duplicate_counted(&value, |_| true);
|
||||||
choose_kind_from(&duplicated_counted)
|
choose_kind_from(&duplicated_counted)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -78,13 +78,13 @@ fn calc_duplicate_counted(
|
||||||
if on_consider_next_char(next_char) {
|
if on_consider_next_char(next_char) {
|
||||||
count_of_same
|
count_of_same
|
||||||
.entry(next_char)
|
.entry(next_char)
|
||||||
.and_modify(|count| *count += 1)
|
.and_modify(|count| *count = *count + 1)
|
||||||
.or_insert(FIRST_ENCOUNTERED);
|
.or_insert(FIRST_ENCOUNTERED);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
let mut to_sort: Vec<usize> = count_of_same.into_values().collect();
|
let mut to_sort: Vec<usize> = count_of_same.into_iter().map(|(_, count)| count).collect();
|
||||||
to_sort.sort_by_key(|&count| Reverse(count));
|
to_sort.sort_by_key(|&count| Reverse(count));
|
||||||
to_sort
|
to_sort
|
||||||
}
|
}
|
||||||
|
@ -119,9 +119,9 @@ fn choose_kind_from(to_choose_from: &[usize]) -> HandKind {
|
||||||
Some(kind)
|
Some(kind)
|
||||||
}
|
}
|
||||||
|
|
||||||
calc_kind(to_choose_from).unwrap_or_else(|| {
|
calc_kind(&to_choose_from).unwrap_or_else(|| {
|
||||||
|
let default_value = HandKind::default();
|
||||||
HandKind::default()
|
default_value
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use std::{cmp::Ordering, collections::HashMap, ops::RangeInclusive, sync::LazyLock};
|
use std::{cmp::Ordering, collections::HashMap, ops::RangeInclusive, sync::LazyLock, usize};
|
||||||
|
|
||||||
pub const JOKER: char = 'J';
|
pub const JOKER: char = 'J';
|
||||||
static LETTERS_WITHOUT_JOKER: &[char] = &['T', 'Q', 'K', 'A'];
|
static LETTERS_WITHOUT_JOKER: &[char] = &['T', 'Q', 'K', 'A'];
|
||||||
|
@ -8,14 +8,17 @@ const NUMBERS: RangeInclusive<u32> = 0..=9;
|
||||||
pub type StrengthOfSymbols = HashMap<char, usize>;
|
pub type StrengthOfSymbols = HashMap<char, usize>;
|
||||||
|
|
||||||
fn numbers_in_chars() -> impl Iterator<Item = char> {
|
fn numbers_in_chars() -> impl Iterator<Item = char> {
|
||||||
NUMBERS.map(|number| std::char::from_digit(number, 10).unwrap())
|
NUMBERS
|
||||||
|
.into_iter()
|
||||||
|
.map(|number| std::char::from_digit(number, 10).unwrap())
|
||||||
}
|
}
|
||||||
|
|
||||||
//A hand consists of five cards labeled one of A, K, Q, J, T, 9, 8, 7, 6, 5, 4, 3, or 2.
|
//A hand consists of five cards labeled one of A, K, Q, J, T, 9, 8, 7, 6, 5, 4, 3, or 2.
|
||||||
//The relative strength of each card follows this order, where A is the highest and 2 is the lowest.
|
//The relative strength of each card follows this order, where A is the highest and 2 is the lowest.
|
||||||
pub static LABEL_ORDERING: LazyLock<StrengthOfSymbols> = LazyLock::new(|| {
|
pub static LABEL_ORDERING: LazyLock<StrengthOfSymbols> = LazyLock::new(|| {
|
||||||
numbers_in_chars()
|
numbers_in_chars()
|
||||||
.chain(LETTERS.iter().copied())
|
.chain(LETTERS.into_iter().copied())
|
||||||
|
.into_iter()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.map(|(index, character)| (character, index))
|
.map(|(index, character)| (character, index))
|
||||||
.collect()
|
.collect()
|
||||||
|
@ -24,7 +27,8 @@ pub static LABEL_ORDERING: LazyLock<StrengthOfSymbols> = LazyLock::new(|| {
|
||||||
pub static LABEL_ORDERING_WITH_JOKER: LazyLock<StrengthOfSymbols> = LazyLock::new(|| {
|
pub static LABEL_ORDERING_WITH_JOKER: LazyLock<StrengthOfSymbols> = LazyLock::new(|| {
|
||||||
std::iter::once(JOKER)
|
std::iter::once(JOKER)
|
||||||
.chain(numbers_in_chars())
|
.chain(numbers_in_chars())
|
||||||
.chain(LETTERS_WITHOUT_JOKER.iter().copied())
|
.chain(LETTERS_WITHOUT_JOKER.into_iter().copied())
|
||||||
|
.into_iter()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.map(|(index, character)| (character, index))
|
.map(|(index, character)| (character, index))
|
||||||
.collect()
|
.collect()
|
||||||
|
@ -43,7 +47,7 @@ pub fn compare_along_str(
|
||||||
.get(&right_char)
|
.get(&right_char)
|
||||||
.unwrap_or_else(|| panic!("right char ({}) is not valid", right_char));
|
.unwrap_or_else(|| panic!("right char ({}) is not valid", right_char));
|
||||||
|
|
||||||
let current_ordering = left_rank_value.cmp(right_rank_value);
|
let current_ordering = left_rank_value.cmp(&right_rank_value);
|
||||||
|
|
||||||
let found_difference = current_ordering != Ordering::Equal;
|
let found_difference = current_ordering != Ordering::Equal;
|
||||||
if found_difference {
|
if found_difference {
|
||||||
|
|
|
@ -5,7 +5,7 @@ pub fn blocks_of_lines_seperated_by<'a>(
|
||||||
let mut current_block = Vec::new();
|
let mut current_block = Vec::new();
|
||||||
let mut lines = input.lines();
|
let mut lines = input.lines();
|
||||||
std::iter::from_fn(move || {
|
std::iter::from_fn(move || {
|
||||||
for next_line in lines.by_ref() {
|
while let Some(next_line) = lines.next() {
|
||||||
if on_skip(next_line) {
|
if on_skip(next_line) {
|
||||||
if !current_block.is_empty() {
|
if !current_block.is_empty() {
|
||||||
let to_return = std::mem::take(&mut current_block);
|
let to_return = std::mem::take(&mut current_block);
|
||||||
|
@ -23,7 +23,9 @@ pub fn blocks_of_lines_seperated_by<'a>(
|
||||||
None
|
None
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
pub fn blocks_of_lines_seperated_by_empty_lines(input: &str) -> impl Iterator<Item = Vec<&str>> {
|
pub fn blocks_of_lines_seperated_by_empty_lines<'a>(
|
||||||
|
input: &'a str,
|
||||||
|
) -> impl Iterator<Item = Vec<&'a str>> {
|
||||||
blocks_of_lines_seperated_by(input, |line| line.trim().is_empty())
|
blocks_of_lines_seperated_by(input, |line| line.trim().is_empty())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue