Compare commits
3 commits
4970f247f3
...
603ee1827d
Author | SHA1 | Date | |
---|---|---|---|
|
603ee1827d | ||
|
a3ce12a80b | ||
|
1d0154122b |
19 changed files with 512 additions and 162 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,6 +97,12 @@ 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"
|
||||||
|
@ -137,16 +143,6 @@ 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"
|
||||||
|
@ -159,7 +155,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",
|
"encode_unicode 0.3.6",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
"libc",
|
"libc",
|
||||||
"windows-sys",
|
"windows-sys",
|
||||||
|
@ -174,6 +170,27 @@ 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"
|
||||||
|
@ -196,12 +213,39 @@ 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"
|
||||||
|
@ -225,12 +269,29 @@ 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"
|
||||||
|
@ -249,12 +310,29 @@ 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"
|
||||||
|
@ -267,6 +345,16 @@ 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"
|
||||||
|
@ -285,6 +373,20 @@ 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"
|
||||||
|
@ -303,6 +405,17 @@ 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"
|
||||||
|
@ -344,6 +457,18 @@ 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"
|
||||||
|
@ -380,15 +505,6 @@ 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"
|
||||||
|
@ -406,6 +522,17 @@ 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"
|
||||||
|
@ -438,6 +565,12 @@ 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"
|
||||||
|
@ -451,24 +584,32 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
|
checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "vte"
|
name = "wasi"
|
||||||
version = "0.11.1"
|
version = "0.11.0+wasi-snapshot-preview1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f5022b5fbf9407086c180e9557be968742d839e68346af7792b8592489732197"
|
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "winapi"
|
||||||
|
version = "0.3.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"utf8parse",
|
"winapi-i686-pc-windows-gnu",
|
||||||
"vte_generate_state_changes",
|
"winapi-x86_64-pc-windows-gnu",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "vte_generate_state_changes"
|
name = "winapi-i686-pc-windows-gnu"
|
||||||
version = "0.1.2"
|
version = "0.4.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2e369bee1b05d510a7b4ed645f5faa90619e05437111783ea5848f28d97d3c2e"
|
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
[[package]]
|
||||||
"quote",
|
name = "winapi-x86_64-pc-windows-gnu"
|
||||||
]
|
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"
|
||||||
colonnade = "1.3.3"
|
prettytable-rs = "0.10.0"
|
||||||
|
|
|
@ -1,43 +1,52 @@
|
||||||
pub use benchmark_result::BenchmarkResult;
|
pub use conducted_benchmark::ConductedBenchmark;
|
||||||
pub use file_to_benchmark::FileToBenchmark;
|
pub use file_to_benchmark::FileToBenchmark;
|
||||||
|
|
||||||
mod benchmark_result;
|
use prettytable::Table;
|
||||||
|
|
||||||
|
mod conducted_benchmark;
|
||||||
mod file_to_benchmark;
|
mod file_to_benchmark;
|
||||||
|
mod row_builder;
|
||||||
mod row_building;
|
mod row_building;
|
||||||
|
|
||||||
use crate::{cli::BenchmarkCli, solving_given::solve_given, AppResult};
|
use crate::{
|
||||||
|
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};
|
||||||
|
|
||||||
fn calc_average(sum: Duration, nanos_count: u64) -> Duration {
|
pub type BenchmarkResult = Result<ConductedBenchmark, NoSolutionFound>;
|
||||||
let average_raw = sum.div_duration_f64(Duration::from_nanos(nanos_count));
|
|
||||||
Duration::from_nanos(average_raw.round() as u64)
|
pub fn execute_benchmark(args: &BenchmarkCli) -> AppResult<Table> {
|
||||||
}
|
|
||||||
pub fn execute_benchmark(args: &BenchmarkCli) -> AppResult<String> {
|
|
||||||
let loaded = load_benchmarks(args)?;
|
let loaded = load_benchmarks(args)?;
|
||||||
let benchmarked = loaded
|
|
||||||
.into_iter()
|
let benchmarked = loaded.into_iter().map(solve_and_keep_track_of_runtime);
|
||||||
.map(solve_and_keep_track_of_runtime)
|
|
||||||
.collect::<AppResult<Vec<BenchmarkResult>>>()?;
|
let mut sum: Duration = Duration::ZERO;
|
||||||
let sum: Duration = benchmarked.iter().map(|result| result.how_long()).sum();
|
let mut count: u64 = 0;
|
||||||
let average = calc_average(sum, benchmarked.len() as u64);
|
let after_header = row_building::create_rows_for_every_solutions(benchmarked, |to_add| {
|
||||||
let header = row_building::create_header();
|
sum += to_add;
|
||||||
let after_header = row_building::create_rows_for_every_solutions(benchmarked);
|
count += 1;
|
||||||
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(header)
|
.chain(row_building::create_header());
|
||||||
.collect();
|
for next_row in rows {
|
||||||
let lines = Colonnade::new(5, 100).unwrap().tabulate(table)?;
|
table.add_row(next_row);
|
||||||
|
}
|
||||||
|
|
||||||
Ok(lines.join("\n"))
|
Ok(table)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn solve_and_keep_track_of_runtime(
|
fn solve_and_keep_track_of_runtime(
|
||||||
(benchmark, content): (FileToBenchmark, String),
|
(benchmark, content): (FileToBenchmark, String),
|
||||||
) -> AppResult<BenchmarkResult> {
|
) -> Result<ConductedBenchmark, NoSolutionFound> {
|
||||||
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)?;
|
||||||
|
@ -45,15 +54,14 @@ fn solve_and_keep_track_of_runtime(
|
||||||
|
|
||||||
let how_long = after - before;
|
let how_long = after - before;
|
||||||
|
|
||||||
let result = BenchmarkResult::new(benchmark, actual_ouput, how_long);
|
let result = ConductedBenchmark::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)>> {
|
||||||
let benchmarks = args
|
args.files()
|
||||||
.files()
|
|
||||||
.iter()
|
.iter()
|
||||||
.map(|path| {
|
.flat_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\
|
||||||
|
@ -70,14 +78,9 @@ fn load_benchmarks(args: &BenchmarkCli) -> AppResult<Vec<(FileToBenchmark, Strin
|
||||||
error
|
error
|
||||||
)
|
)
|
||||||
})?;
|
})?;
|
||||||
Ok(parsed)
|
Ok::<_, AppError>(parsed)
|
||||||
})
|
})
|
||||||
.collect::<AppResult<Vec<Vec<FileToBenchmark>>>>()?
|
.flatten()
|
||||||
.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| {
|
||||||
|
@ -92,5 +95,10 @@ fn load_benchmarks(args: &BenchmarkCli) -> AppResult<Vec<(FileToBenchmark, Strin
|
||||||
})?;
|
})?;
|
||||||
Ok((benchmark, content))
|
Ok((benchmark, content))
|
||||||
})
|
})
|
||||||
.collect::<AppResult<Vec<(FileToBenchmark, String)>>>()
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
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,21 +1,25 @@
|
||||||
use std::time::Duration;
|
use std::{
|
||||||
|
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 BenchmarkResult {
|
pub struct ConductedBenchmark {
|
||||||
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 BenchmarkResult {
|
impl ConductedBenchmark {
|
||||||
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) = benchmarking.into();
|
let (day, task, expected_output, path_of_input) = 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 {
|
||||||
|
@ -27,6 +31,7 @@ impl BenchmarkResult {
|
||||||
how_long,
|
how_long,
|
||||||
maybe_different_actual_output,
|
maybe_different_actual_output,
|
||||||
expected_output,
|
expected_output,
|
||||||
|
path_of_input,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -63,4 +68,8 @@ impl BenchmarkResult {
|
||||||
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,9 +19,14 @@ pub struct FileToBenchmark {
|
||||||
expected_output: String,
|
expected_output: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<FileToBenchmark> for (GivenDay, GivenTask, String) {
|
impl From<FileToBenchmark> for (GivenDay, GivenTask, String, PathBuf) {
|
||||||
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,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
174
crates/cli/src/benchmarking/row_builder.rs
Normal file
174
crates/cli/src/benchmarking/row_builder.rs
Normal file
|
@ -0,0 +1,174 @@
|
||||||
|
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,54 +1,35 @@
|
||||||
|
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;
|
||||||
|
|
||||||
use super::BenchmarkResult;
|
pub fn create_header() -> SingleRow {
|
||||||
type MatrixReport = Vec<Vec<String>>;
|
std::iter::once(RowBuilder::header().into_row())
|
||||||
|
|
||||||
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) -> std::iter::Once<Vec<String>> {
|
pub fn create_sum_row(sum: Duration) -> SingleRow {
|
||||||
let passed_txt = BenchmarkResult::convert_duration_to_secs_and_mili_txt(sum);
|
std::iter::once(RowBuilder::total(sum).into_row())
|
||||||
std::iter::once(vec![
|
|
||||||
"Total".to_string(),
|
|
||||||
"Total".to_string(),
|
|
||||||
passed_txt,
|
|
||||||
"-".to_string(),
|
|
||||||
"-".to_string(),
|
|
||||||
])
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_average_row(average: Duration) -> std::iter::Once<Vec<String>> {
|
pub fn create_average_row(average: Duration) -> SingleRow {
|
||||||
let passed_txt = BenchmarkResult::convert_duration_to_secs_and_mili_txt(average);
|
std::iter::once(RowBuilder::average(average).into_row())
|
||||||
std::iter::once(vec![
|
|
||||||
"Average".to_string(),
|
|
||||||
"Average".to_string(),
|
|
||||||
passed_txt,
|
|
||||||
"-".to_string(),
|
|
||||||
"-".to_string(),
|
|
||||||
])
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_rows_for_every_solutions(loaded: Vec<BenchmarkResult>) -> MatrixReport {
|
pub fn create_rows_for_every_solutions(
|
||||||
|
loaded: impl IntoIterator<Item = BenchmarkResult>,
|
||||||
|
mut on_ok: impl FnMut(Duration),
|
||||||
|
) -> MatrixReport {
|
||||||
loaded
|
loaded
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|result| {
|
.map(|result| {
|
||||||
vec![
|
result
|
||||||
result.day().to_string(),
|
.inspect(|on_success| on_ok(on_success.how_long()))
|
||||||
result.task().to_string(),
|
.map(RowBuilder::from)
|
||||||
result.how_long_as_string(),
|
.unwrap_or_else(RowBuilder::from)
|
||||||
result.expected_output().to_string(),
|
|
||||||
result
|
|
||||||
.maybe_different_actual_output()
|
|
||||||
.map(|unowned| unowned.to_string())
|
|
||||||
.unwrap_or_else(|| result.expected_output().to_string()),
|
|
||||||
]
|
|
||||||
})
|
})
|
||||||
|
.map(RowBuilder::into_row)
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,2 +1,3 @@
|
||||||
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,3 +1,7 @@
|
||||||
|
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;
|
||||||
|
@ -6,3 +10,27 @@ 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,
|
||||||
AppResult,
|
AppOutput, 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) => {
|
||||||
println!("{}", found_solution);
|
found_solution.print_std_out();
|
||||||
ExitCode::SUCCESS
|
ExitCode::SUCCESS
|
||||||
}
|
}
|
||||||
Err(error) => {
|
Err(error) => {
|
||||||
|
@ -24,9 +24,13 @@ fn main() -> ExitCode {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_command(args: &AppCliArgs) -> AppResult<String> {
|
fn handle_command(args: &AppCliArgs) -> AppResult<AppOutput> {
|
||||||
match args.sub_command() {
|
match args.sub_command() {
|
||||||
AppCliSubcommands::Solve(to_solve) => solve_given_from_cli(to_solve),
|
AppCliSubcommands::Solve(to_solve) => {
|
||||||
AppCliSubcommands::Benchmark(benchmark) => execute_benchmark(benchmark),
|
solve_given_from_cli(to_solve).map(AppOutput::JustString)
|
||||||
|
}
|
||||||
|
AppCliSubcommands::Benchmark(benchmark) => {
|
||||||
|
execute_benchmark(benchmark).map(AppOutput::PrettyTable)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,16 +7,23 @@ use crate::{
|
||||||
AppResult,
|
AppResult,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn solve_given(given_day: GivenDay, given_task: GivenTask, content: &str) -> AppResult<String> {
|
pub fn solve_given(
|
||||||
|
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_else(|| CouldNotSolveError::DayNotFound(day))?;
|
.ok_or(NoSolutionFound::DayNotFound(given_day))?;
|
||||||
found_day
|
found_day
|
||||||
.get(task.saturating_sub(1) as usize)
|
.get(task.saturating_sub(1) as usize)
|
||||||
.ok_or_else(|| CouldNotSolveError::TaskNotFound { day, task })
|
.ok_or(NoSolutionFound::TaskNotFound {
|
||||||
|
day: given_day,
|
||||||
|
task: given_task,
|
||||||
|
})
|
||||||
}?;
|
}?;
|
||||||
|
|
||||||
let solved = (found_task)(content);
|
let solved = (found_task)(content);
|
||||||
|
@ -40,11 +47,17 @@ fn try_read_from_file_if_demanded(args: &CliSolutionToSolve) -> io::Result<Strin
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug, Error)]
|
||||||
enum CouldNotSolveError {
|
pub enum CouldNotSolveError {
|
||||||
#[error("There is no solution for the day {0}")]
|
#[error("{0}")]
|
||||||
DayNotFound(u32),
|
NotFound(#[from] NoSolutionFound),
|
||||||
#[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,12 +21,9 @@ 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 {
|
||||||
match next_mapping.map_point(current_seed) {
|
if let Some(found_mapping) = next_mapping.map_point(current_seed) {
|
||||||
Some(found_mapping) => {
|
current_seed = found_mapping;
|
||||||
current_seed = found_mapping;
|
break;
|
||||||
break;
|
|
||||||
}
|
|
||||||
None => (),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -119,7 +116,6 @@ 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,5 +1,3 @@
|
||||||
use std::usize;
|
|
||||||
|
|
||||||
mod parsing;
|
mod parsing;
|
||||||
mod race_record;
|
mod race_record;
|
||||||
|
|
||||||
|
@ -11,12 +9,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);
|
||||||
|
|
||||||
|
@ -29,7 +27,6 @@ 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
|
||||||
.into_iter()
|
.iter()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.map(|(index, hand)| {
|
.map(|(index, hand)| {
|
||||||
let rank = index.saturating_add(1);
|
let rank = index.saturating_add(1);
|
||||||
|
|
|
@ -2,7 +2,6 @@ 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, usize};
|
use std::str::FromStr;
|
||||||
|
|
||||||
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 = *count + 1)
|
.and_modify(|count| *count += 1)
|
||||||
.or_insert(FIRST_ENCOUNTERED);
|
.or_insert(FIRST_ENCOUNTERED);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
let mut to_sort: Vec<usize> = count_of_same.into_iter().map(|(_, count)| count).collect();
|
let mut to_sort: Vec<usize> = count_of_same.into_values().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();
|
|
||||||
default_value
|
HandKind::default()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use std::{cmp::Ordering, collections::HashMap, ops::RangeInclusive, sync::LazyLock, usize};
|
use std::{cmp::Ordering, collections::HashMap, ops::RangeInclusive, sync::LazyLock};
|
||||||
|
|
||||||
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,17 +8,14 @@ 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
|
NUMBERS.map(|number| std::char::from_digit(number, 10).unwrap())
|
||||||
.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.into_iter().copied())
|
.chain(LETTERS.iter().copied())
|
||||||
.into_iter()
|
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.map(|(index, character)| (character, index))
|
.map(|(index, character)| (character, index))
|
||||||
.collect()
|
.collect()
|
||||||
|
@ -27,8 +24,7 @@ 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.into_iter().copied())
|
.chain(LETTERS_WITHOUT_JOKER.iter().copied())
|
||||||
.into_iter()
|
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.map(|(index, character)| (character, index))
|
.map(|(index, character)| (character, index))
|
||||||
.collect()
|
.collect()
|
||||||
|
@ -47,7 +43,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 || {
|
||||||
while let Some(next_line) = lines.next() {
|
for next_line in lines.by_ref() {
|
||||||
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,9 +23,7 @@ pub fn blocks_of_lines_seperated_by<'a>(
|
||||||
None
|
None
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
pub fn blocks_of_lines_seperated_by_empty_lines<'a>(
|
pub fn blocks_of_lines_seperated_by_empty_lines(input: &str) -> impl Iterator<Item = Vec<&str>> {
|
||||||
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