Compare commits

..

No commits in common. "331faaa44d69da6b3156ad1cd2eb2f9787f9f2b7" and "64f87d035e5c524b454c14e4001b76ac6c1a9a31" have entirely different histories.

58 changed files with 247 additions and 1523 deletions

129
Cargo.lock generated
View file

@ -6,15 +6,12 @@ version = 3
name = "advent_of_code_2023"
version = "0.1.0"
dependencies = [
"anyhow",
"clap",
"colonnade",
"derive_more",
"env_logger",
"insta",
"log",
"ron",
"serde",
"solutions_advent_of_code_2023",
"regex",
"thiserror",
]
@ -76,32 +73,11 @@ dependencies = [
"windows-sys",
]
[[package]]
name = "anyhow"
version = "1.0.86"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da"
[[package]]
name = "base64"
version = "0.21.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567"
[[package]]
name = "bitflags"
version = "2.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de"
dependencies = [
"serde",
]
[[package]]
name = "clap"
version = "4.5.16"
version = "4.5.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed6719fffa43d0d87e5fd8caeab59be1554fb028cd30edc88fc4369b17971019"
checksum = "11d8838454fda655dafd3accb2b6e2bea645b9e4078abe84a22ceb947235c5cc"
dependencies = [
"clap_builder",
"clap_derive",
@ -137,16 +113,6 @@ version = "0.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
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]]
name = "colorchoice"
version = "1.0.2"
@ -263,9 +229,9 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
[[package]]
name = "libc"
version = "0.2.158"
version = "0.2.156"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439"
checksum = "a5f43f184355eefb8d17fc948dbecf6c13be3c141f20d834ae842193a448c72a"
[[package]]
name = "linked-hash-map"
@ -296,9 +262,9 @@ dependencies = [
[[package]]
name = "quote"
version = "1.0.37"
version = "1.0.36"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af"
checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7"
dependencies = [
"proc-macro2",
]
@ -332,63 +298,12 @@ version = "0.8.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b"
[[package]]
name = "ron"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b91f7eff05f748767f183df4320a63d6936e9c6107d97c9e6bdd9784f4289c94"
dependencies = [
"base64",
"bitflags",
"serde",
"serde_derive",
]
[[package]]
name = "serde"
version = "1.0.209"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "99fce0ffe7310761ca6bf9faf5115afbc19688edd00171d81b1bb1b116c63e09"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.209"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a5831b979fd7b5439637af1752d535ff49f4860c0f341d1baeb6faf0f4242170"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "similar"
version = "2.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1de1d4f81173b03af4c0cbed3c898f6bff5b870e4a7f5d6f4057d62a7a4b686e"
[[package]]
name = "solutions_advent_of_code_2023"
version = "0.1.0"
dependencies = [
"derive_more",
"insta",
"regex",
"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]]
name = "strsim"
version = "0.11.1"
@ -397,9 +312,9 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
[[package]]
name = "syn"
version = "2.0.76"
version = "2.0.74"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "578e081a14e0cefc3279b0472138c513f37b41a08d5a3cca9b6e4e8ceb6cd525"
checksum = "1fceb41e3d546d0bd83421d3409b1460cc7444cd389341a4c880fe7a042cb3d7"
dependencies = [
"proc-macro2",
"quote",
@ -440,9 +355,9 @@ checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202"
[[package]]
name = "unicode-xid"
version = "0.2.5"
version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "229730647fbc343e3a80e463c1db7f78f3855d3f3739bee0dda773c9a037c90a"
checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c"
[[package]]
name = "utf8parse"
@ -450,26 +365,6 @@ version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
[[package]]
name = "vte"
version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f5022b5fbf9407086c180e9557be968742d839e68346af7792b8592489732197"
dependencies = [
"utf8parse",
"vte_generate_state_changes",
]
[[package]]
name = "vte_generate_state_changes"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2e369bee1b05d510a7b4ed645f5faa90619e05437111783ea5848f28d97d3c2e"
dependencies = [
"proc-macro2",
"quote",
]
[[package]]
name = "windows-sys"
version = "0.52.0"

View file

@ -1,9 +1,15 @@
[workspace]
resolver = "2"
members = ["crates/cli", "crates/solutions"]
[package]
name = "advent_of_code_2023"
version = "0.1.0"
edition = "2021"
default-members = ["crates/cli"]
[workspace.dependencies]
[dependencies]
derive_more = { version = "1", features = ["full"] }
regex = "1.10.6"
clap = { version = "4.5.15", features = ["derive"] }
env_logger = "0.11.5"
log = "0.4.22"
thiserror = "1.0.63"
[dev-dependencies]
insta = "1.39.0"

17
LICENSE
View file

@ -1,17 +0,0 @@
Copyright 2024 BoolPurist
Permission is hereby granted, free of charge,
to any person obtaining a copy of this software and
associated documentation files (the “Software”), to deal in the Software without restriction,
including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

5
TODO.md Normal file
View file

@ -0,0 +1,5 @@
# TODO
- Add MIT license
- Seperate solution into own library crate
- Implment subcommand to execute puzzle input files and print out how every long every one takes

439
crates/cli/Cargo.lock generated
View file

@ -1,439 +0,0 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "advent_of_code_2023"
version = "0.1.0"
dependencies = [
"clap",
"derive_more",
"env_logger",
"insta",
"log",
"regex",
"thiserror",
]
[[package]]
name = "aho-corasick"
version = "1.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
dependencies = [
"memchr",
]
[[package]]
name = "anstream"
version = "0.6.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "64e15c1ab1f89faffbf04a634d5e1962e9074f2741eef6d97f3c4e322426d526"
dependencies = [
"anstyle",
"anstyle-parse",
"anstyle-query",
"anstyle-wincon",
"colorchoice",
"is_terminal_polyfill",
"utf8parse",
]
[[package]]
name = "anstyle"
version = "1.0.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1"
[[package]]
name = "anstyle-parse"
version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eb47de1e80c2b463c735db5b217a0ddc39d612e7ac9e2e96a5aed1f57616c1cb"
dependencies = [
"utf8parse",
]
[[package]]
name = "anstyle-query"
version = "1.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6d36fc52c7f6c869915e99412912f22093507da8d9e942ceaf66fe4b7c14422a"
dependencies = [
"windows-sys",
]
[[package]]
name = "anstyle-wincon"
version = "3.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5bf74e1b6e971609db8ca7a9ce79fd5768ab6ae46441c572e46cf596f59e57f8"
dependencies = [
"anstyle",
"windows-sys",
]
[[package]]
name = "clap"
version = "4.5.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "11d8838454fda655dafd3accb2b6e2bea645b9e4078abe84a22ceb947235c5cc"
dependencies = [
"clap_builder",
"clap_derive",
]
[[package]]
name = "clap_builder"
version = "4.5.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "216aec2b177652e3846684cbfe25c9964d18ec45234f0f5da5157b207ed1aab6"
dependencies = [
"anstream",
"anstyle",
"clap_lex",
"strsim",
]
[[package]]
name = "clap_derive"
version = "4.5.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "501d359d5f3dcaf6ecdeee48833ae73ec6e42723a1e52419c79abf9507eec0a0"
dependencies = [
"heck",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "clap_lex"
version = "0.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97"
[[package]]
name = "colorchoice"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0"
[[package]]
name = "console"
version = "0.15.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0e1f83fc076bd6dd27517eacdf25fef6c4dfe5f1d7448bafaaf3a26f13b5e4eb"
dependencies = [
"encode_unicode",
"lazy_static",
"libc",
"windows-sys",
]
[[package]]
name = "convert_case"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec182b0ca2f35d8fc196cf3404988fd8b8c739a4d270ff118a398feb0cbec1ca"
dependencies = [
"unicode-segmentation",
]
[[package]]
name = "derive_more"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4a9b99b9cbbe49445b21764dc0625032a89b145a2642e67603e1c936f5458d05"
dependencies = [
"derive_more-impl",
]
[[package]]
name = "derive_more-impl"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cb7330aeadfbe296029522e6c40f315320aba36fc43a5b3632f3795348f3bd22"
dependencies = [
"convert_case",
"proc-macro2",
"quote",
"syn",
"unicode-xid",
]
[[package]]
name = "encode_unicode"
version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f"
[[package]]
name = "env_filter"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4f2c92ceda6ceec50f43169f9ee8424fe2db276791afde7b2cd8bc084cb376ab"
dependencies = [
"log",
"regex",
]
[[package]]
name = "env_logger"
version = "0.11.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e13fa619b91fb2381732789fc5de83b45675e882f66623b7d8cb4f643017018d"
dependencies = [
"anstream",
"anstyle",
"env_filter",
"humantime",
"log",
]
[[package]]
name = "heck"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
[[package]]
name = "humantime"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
[[package]]
name = "insta"
version = "1.39.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "810ae6042d48e2c9e9215043563a58a80b877bc863228a74cf10c49d4620a6f5"
dependencies = [
"console",
"lazy_static",
"linked-hash-map",
"similar",
]
[[package]]
name = "is_terminal_polyfill"
version = "1.70.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf"
[[package]]
name = "lazy_static"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
[[package]]
name = "libc"
version = "0.2.156"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a5f43f184355eefb8d17fc948dbecf6c13be3c141f20d834ae842193a448c72a"
[[package]]
name = "linked-hash-map"
version = "0.5.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f"
[[package]]
name = "log"
version = "0.4.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
[[package]]
name = "memchr"
version = "2.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
[[package]]
name = "proc-macro2"
version = "1.0.86"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.36"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7"
dependencies = [
"proc-macro2",
]
[[package]]
name = "regex"
version = "1.10.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619"
dependencies = [
"aho-corasick",
"memchr",
"regex-automata",
"regex-syntax",
]
[[package]]
name = "regex-automata"
version = "0.4.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df"
dependencies = [
"aho-corasick",
"memchr",
"regex-syntax",
]
[[package]]
name = "regex-syntax"
version = "0.8.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b"
[[package]]
name = "similar"
version = "2.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1de1d4f81173b03af4c0cbed3c898f6bff5b870e4a7f5d6f4057d62a7a4b686e"
[[package]]
name = "strsim"
version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
[[package]]
name = "syn"
version = "2.0.74"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1fceb41e3d546d0bd83421d3409b1460cc7444cd389341a4c880fe7a042cb3d7"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "thiserror"
version = "1.0.63"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "1.0.63"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "unicode-ident"
version = "1.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
[[package]]
name = "unicode-segmentation"
version = "1.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202"
[[package]]
name = "unicode-xid"
version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c"
[[package]]
name = "utf8parse"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
[[package]]
name = "windows-sys"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
dependencies = [
"windows-targets",
]
[[package]]
name = "windows-targets"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
dependencies = [
"windows_aarch64_gnullvm",
"windows_aarch64_msvc",
"windows_i686_gnu",
"windows_i686_gnullvm",
"windows_i686_msvc",
"windows_x86_64_gnu",
"windows_x86_64_gnullvm",
"windows_x86_64_msvc",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
[[package]]
name = "windows_aarch64_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
[[package]]
name = "windows_i686_gnu"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
[[package]]
name = "windows_i686_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
[[package]]
name = "windows_i686_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
[[package]]
name = "windows_x86_64_gnu"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
[[package]]
name = "windows_x86_64_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"

View file

@ -1,18 +0,0 @@
[package]
name = "advent_of_code_2023"
version = "0.1.0"
edition = "2021"
[dependencies]
solutions_advent_of_code_2023 = { path = "../solutions" }
derive_more = { workspace = true }
thiserror = { workspace = true }
serde = { version = "1.0.209", features = ["derive"] }
clap = { version = "4.5.15", features = ["derive"] }
env_logger = "0.11.5"
log = "0.4.22"
anyhow = "1.0.86"
ron = "0.8.1"
colonnade = "1.3.3"

View file

@ -1,96 +0,0 @@
pub use benchmark_result::BenchmarkResult;
pub use file_to_benchmark::FileToBenchmark;
mod benchmark_result;
mod file_to_benchmark;
mod row_building;
use crate::{cli::BenchmarkCli, solving_given::solve_given, AppResult};
use anyhow::anyhow;
use colonnade::Colonnade;
use std::time::{Duration, Instant};
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)
}
pub fn execute_benchmark(args: &BenchmarkCli) -> AppResult<String> {
let loaded = load_benchmarks(args)?;
let benchmarked = loaded
.into_iter()
.map(solve_and_keep_track_of_runtime)
.collect::<AppResult<Vec<BenchmarkResult>>>()?;
let sum: Duration = benchmarked.iter().map(|result| result.how_long()).sum();
let average = calc_average(sum, benchmarked.len() as u64);
let header = row_building::create_header();
let after_header = row_building::create_rows_for_every_solutions(benchmarked);
let table: Vec<Vec<String>> = after_header
.into_iter()
.chain(row_building::create_sum_row(sum))
.chain(row_building::create_average_row(average))
.chain(header)
.collect();
let lines = Colonnade::new(5, 100).unwrap().tabulate(table)?;
Ok(lines.join("\n"))
}
fn solve_and_keep_track_of_runtime(
(benchmark, content): (FileToBenchmark, String),
) -> AppResult<BenchmarkResult> {
let (day, task) = (benchmark.given_day(), benchmark.given_task());
let before = Instant::now();
let actual_ouput = solve_given(day, task, &content)?;
let after = Instant::now();
let how_long = after - before;
let result = BenchmarkResult::new(benchmark, actual_ouput, how_long);
Ok(result)
}
fn load_benchmarks(args: &BenchmarkCli) -> AppResult<Vec<(FileToBenchmark, String)>> {
let benchmarks = args
.files()
.iter()
.map(|path| {
let content = std::fs::read_to_string(path).map_err(|error| {
anyhow!(
"Could not read benchmark file at {:?}\n\
Details: {}",
path,
error
)
})?;
let parsed: Vec<FileToBenchmark> = ron::from_str(&content).map_err(|error| {
anyhow!(
"Content of benchmark file at ({:?}) is in an invalid ron format\n\
Details of invalid format: {}",
path,
error
)
})?;
Ok(parsed)
})
.collect::<AppResult<Vec<Vec<FileToBenchmark>>>>()?
.into_iter()
.flatten();
benchmarks
.into_iter()
.map(|benchmark| {
let where_to_look = benchmark.where_to_look();
let content = std::fs::read_to_string(where_to_look).map_err(|error| {
anyhow!(
"Could not read puzzle input file at {:?} for day {} and task {}\n\
Details: {}",
where_to_look,
benchmark.given_day(),
benchmark.given_task(),
error
)
})?;
Ok((benchmark, content))
})
.collect::<AppResult<Vec<(FileToBenchmark, String)>>>()
}

View file

@ -1,66 +0,0 @@
use std::time::Duration;
use crate::cli::{GivenDay, GivenTask};
use super::FileToBenchmark;
#[derive(Debug)]
pub struct BenchmarkResult {
task: GivenTask,
day: GivenDay,
how_long: Duration,
maybe_different_actual_output: Option<String>,
expected_output: String,
}
impl BenchmarkResult {
pub fn new(benchmarking: FileToBenchmark, actual_ouput: String, how_long: Duration) -> Self {
let (day, task, expected_output) = benchmarking.into();
let maybe_different_actual_output = if actual_ouput == expected_output {
None
} else {
Some(actual_ouput)
};
Self {
task,
day,
how_long,
maybe_different_actual_output,
expected_output,
}
}
pub fn matched_with_expected_output(&self) -> bool {
self.maybe_different_actual_output().is_none()
}
pub fn task(&self) -> GivenTask {
self.task
}
pub fn day(&self) -> GivenDay {
self.day
}
pub fn how_long_as_string(&self) -> String {
Self::convert_duration_to_secs_and_mili_txt(self.how_long)
}
pub fn maybe_different_actual_output(&self) -> Option<&str> {
self.maybe_different_actual_output.as_deref()
}
pub fn expected_output(&self) -> &str {
&self.expected_output
}
pub fn how_long(&self) -> Duration {
self.how_long
}
pub fn convert_duration_to_secs_and_mili_txt(how_long: Duration) -> String {
let secs = how_long.as_secs();
let mili_secs = how_long.as_nanos() % 1_000_000_000;
format!("{}:{}", secs, mili_secs)
}
}

View file

@ -1,71 +0,0 @@
use std::{
io,
path::{Path, PathBuf},
str::FromStr,
};
use derive_more::derive::Debug;
use ron::de::SpannedError;
use serde::{Deserialize, Serialize};
use crate::cli::{GivenDay, GivenTask};
use thiserror::Error;
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
pub struct FileToBenchmark {
given_day: GivenDay,
given_task: GivenTask,
where_to_look: PathBuf,
expected_output: String,
}
impl From<FileToBenchmark> for (GivenDay, GivenTask, String) {
fn from(val: FileToBenchmark) -> Self {
(val.given_day, val.given_task, val.expected_output)
}
}
impl FromStr for FileToBenchmark {
type Err = CouldNotReadFileToBenchmark;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let path = PathBuf::from(s);
let content = std::fs::read_to_string(&path).map_err(|error| {
if error.kind() == io::ErrorKind::NotFound {
CouldNotReadFileToBenchmark::NotFound(s.to_owned())
} else {
error.into()
}
})?;
let parsed_content = ron::from_str(&content)?;
Ok(parsed_content)
}
}
#[derive(Debug, Error)]
pub enum CouldNotReadFileToBenchmark {
#[error("There is not file at {0:?}")]
NotFound(String),
#[error("Coud not read file at.\nDetails: {0}")]
IoError(#[from] io::Error),
#[error("File content is not in the correct format. Details: {0}")]
InvalidRon(#[from] SpannedError),
}
impl FileToBenchmark {
pub fn given_day(&self) -> GivenDay {
self.given_day
}
pub fn given_task(&self) -> GivenTask {
self.given_task
}
pub fn where_to_look(&self) -> &Path {
&self.where_to_look
}
pub fn expected_output(&self) -> &str {
&self.expected_output
}
}

View file

@ -1,54 +0,0 @@
use std::time::Duration;
use super::BenchmarkResult;
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) -> std::iter::Once<Vec<String>> {
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) -> std::iter::Once<Vec<String>> {
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(loaded: Vec<BenchmarkResult>) -> MatrixReport {
loaded
.into_iter()
.map(|result| {
vec![
result.day().to_string(),
result.task().to_string(),
result.how_long_as_string(),
result.expected_output().to_string(),
result
.maybe_different_actual_output()
.map(|unowned| unowned.to_string())
.unwrap_or_else(|| result.expected_output().to_string()),
]
})
.collect()
}

View file

@ -1,29 +0,0 @@
pub use benchmark_cli::BenchmarkCli;
use clap::{Parser, Subcommand};
pub use cli_solution_to_solve::CliSolutionToSolve;
pub use given_day::GivenDay;
pub use given_task::GivenTask;
mod benchmark_cli;
mod cli_solution_to_solve;
mod given_day;
mod given_task;
#[derive(Debug, Subcommand)]
pub enum AppCliSubcommands {
Solve(CliSolutionToSolve),
Benchmark(BenchmarkCli),
}
#[derive(Debug, Parser)]
pub struct AppCliArgs {
#[command(subcommand)]
sub_command: AppCliSubcommands,
}
impl AppCliArgs {
pub fn sub_command(&self) -> &AppCliSubcommands {
&self.sub_command
}
}

View file

@ -1,14 +0,0 @@
use std::path::PathBuf;
use clap::Parser;
#[derive(Debug, Parser)]
pub struct BenchmarkCli {
files: Vec<PathBuf>,
}
impl BenchmarkCli {
pub fn files(&self) -> &[PathBuf] {
&self.files
}
}

View file

@ -1,8 +0,0 @@
pub mod benchmarking;
pub mod cli;
pub mod constants;
pub mod solutions;
pub mod solving_given;
pub type AppError = anyhow::Error;
pub type AppResult<T = ()> = anyhow::Result<T>;

View file

@ -1,32 +0,0 @@
use std::process::ExitCode;
use advent_of_code_2023::{
benchmarking::execute_benchmark,
cli::{AppCliArgs, AppCliSubcommands},
solving_given::solve_given_from_cli,
AppResult,
};
use clap::Parser;
fn main() -> ExitCode {
let args = AppCliArgs::parse();
env_logger::init();
let solution = handle_command(&args);
match solution {
Ok(found_solution) => {
println!("{}", found_solution);
ExitCode::SUCCESS
}
Err(error) => {
eprintln!("{}", error);
ExitCode::FAILURE
}
}
}
fn handle_command(args: &AppCliArgs) -> AppResult<String> {
match args.sub_command() {
AppCliSubcommands::Solve(to_solve) => solve_given_from_cli(to_solve),
AppCliSubcommands::Benchmark(benchmark) => execute_benchmark(benchmark),
}
}

View file

@ -1,50 +0,0 @@
use std::{fs, io, path::Path};
use thiserror::Error;
use crate::{
cli::{CliSolutionToSolve, GivenDay, GivenTask},
solutions::ALL_SOLUTIONS,
AppResult,
};
pub fn solve_given(given_day: GivenDay, given_task: GivenTask, content: &str) -> AppResult<String> {
let found_task = {
let day: u32 = given_day.into();
let task: u32 = given_task.into();
let found_day = ALL_SOLUTIONS
.get(day.saturating_sub(1) as usize)
.ok_or_else(|| CouldNotSolveError::DayNotFound(day))?;
found_day
.get(task.saturating_sub(1) as usize)
.ok_or_else(|| CouldNotSolveError::TaskNotFound { day, task })
}?;
let solved = (found_task)(content);
Ok(solved)
}
pub fn solve_given_from_cli(args: &CliSolutionToSolve) -> AppResult<String> {
let puzzel_input = try_read_from_file_if_demanded(args)?;
let output = solve_given(args.day(), args.task(), &puzzel_input)?;
Ok(output)
}
fn try_read_from_file_if_demanded(args: &CliSolutionToSolve) -> io::Result<String> {
let content = if args.read_as_file() {
let path = Path::new(args.input());
fs::read_to_string(path)?
} else {
args.input().to_string()
};
Ok(content)
}
#[derive(Debug, Error)]
enum CouldNotSolveError {
#[error("There is no solution for the day {0}")]
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}")]
CouldNotReadFromFile(#[from] io::Error),
}

View file

@ -1,15 +0,0 @@
[package]
name = "solutions_advent_of_code_2023"
version = "0.1.0"
edition = "2021"
[dependencies]
derive_more = { workspace = true }
thiserror = { workspace = true }
regex = "1.10.6"
[dev-dependencies]
insta = "1.39.0"

View file

@ -1,172 +0,0 @@
---
source: crates/solutions/src/day5/parsing.rs
expression: actual
---
(
[
79,
14,
55,
13,
],
[
[
ItemMapping {
source_range: SeedRange {
start: 98,
end: 99,
},
target: 50,
range: 2,
},
ItemMapping {
source_range: SeedRange {
start: 50,
end: 97,
},
target: 52,
range: 48,
},
],
[
ItemMapping {
source_range: SeedRange {
start: 15,
end: 51,
},
target: 0,
range: 37,
},
ItemMapping {
source_range: SeedRange {
start: 52,
end: 53,
},
target: 37,
range: 2,
},
ItemMapping {
source_range: SeedRange {
start: 0,
end: 14,
},
target: 39,
range: 15,
},
],
[
ItemMapping {
source_range: SeedRange {
start: 53,
end: 60,
},
target: 49,
range: 8,
},
ItemMapping {
source_range: SeedRange {
start: 11,
end: 52,
},
target: 0,
range: 42,
},
ItemMapping {
source_range: SeedRange {
start: 0,
end: 6,
},
target: 42,
range: 7,
},
ItemMapping {
source_range: SeedRange {
start: 7,
end: 10,
},
target: 57,
range: 4,
},
],
[
ItemMapping {
source_range: SeedRange {
start: 18,
end: 24,
},
target: 88,
range: 7,
},
ItemMapping {
source_range: SeedRange {
start: 25,
end: 94,
},
target: 18,
range: 70,
},
],
[
ItemMapping {
source_range: SeedRange {
start: 77,
end: 99,
},
target: 45,
range: 23,
},
ItemMapping {
source_range: SeedRange {
start: 45,
end: 63,
},
target: 81,
range: 19,
},
ItemMapping {
source_range: SeedRange {
start: 64,
end: 76,
},
target: 68,
range: 13,
},
],
[
ItemMapping {
source_range: SeedRange {
start: 69,
end: 69,
},
target: 0,
range: 1,
},
ItemMapping {
source_range: SeedRange {
start: 0,
end: 68,
},
target: 1,
range: 69,
},
],
[
ItemMapping {
source_range: SeedRange {
start: 56,
end: 92,
},
target: 60,
range: 37,
},
ItemMapping {
source_range: SeedRange {
start: 93,
end: 96,
},
target: 56,
range: 4,
},
],
],
)

View file

@ -1,51 +0,0 @@
---
source: crates/solutions/src/day7/categorized_hand/joker_ordered.rs
expression: input
---
[
JokerOrdered(
CategorizedHand {
kind: OnePair,
rest: DealtHand {
hand: "32T3K",
bid: 765,
},
},
),
JokerOrdered(
CategorizedHand {
kind: TwoPair,
rest: DealtHand {
hand: "KK677",
bid: 28,
},
},
),
JokerOrdered(
CategorizedHand {
kind: Four,
rest: DealtHand {
hand: "T55J5",
bid: 684,
},
},
),
JokerOrdered(
CategorizedHand {
kind: Four,
rest: DealtHand {
hand: "QQQJA",
bid: 483,
},
},
),
JokerOrdered(
CategorizedHand {
kind: Four,
rest: DealtHand {
hand: "KTJJT",
bid: 220,
},
},
),
]

View file

@ -1,41 +0,0 @@
---
source: crates/solutions/src/day7/categorized_hand.rs
expression: input
---
[
CategorizedHand {
kind: OnePair,
rest: DealtHand {
hand: "32T3K",
bid: 765,
},
},
CategorizedHand {
kind: TwoPair,
rest: DealtHand {
hand: "KTJJT",
bid: 220,
},
},
CategorizedHand {
kind: TwoPair,
rest: DealtHand {
hand: "KK677",
bid: 28,
},
},
CategorizedHand {
kind: Three,
rest: DealtHand {
hand: "T55J5",
bid: 684,
},
},
CategorizedHand {
kind: Three,
rest: DealtHand {
hand: "QQQJA",
bid: 483,
},
},
]

View file

@ -1,66 +0,0 @@
---
source: crates/solutions/src/day7/second_ordering.rs
expression: ordered
---
[
(
'J',
0,
),
(
'0',
1,
),
(
'1',
2,
),
(
'2',
3,
),
(
'3',
4,
),
(
'4',
5,
),
(
'5',
6,
),
(
'6',
7,
),
(
'7',
8,
),
(
'8',
9,
),
(
'9',
10,
),
(
'T',
11,
),
(
'Q',
12,
),
(
'K',
13,
),
(
'A',
14,
),
]

View file

@ -1,4 +0,0 @@
pub mod day5;
pub mod day6;
pub mod day7;
mod utils;

View file

@ -1 +0,0 @@
pub(crate) mod parsing;

View file

@ -1,38 +0,0 @@
[
(
given_day: GivenDay(5),
given_task: GivenTask(2),
where_to_look: "file_input/day5_example.txt",
expected_output: "42",
),
(
given_day: GivenDay(5),
given_task: GivenTask(1),
where_to_look: "file_input/day5_example.txt",
expected_output: "42",
),
(
given_day: GivenDay(6),
given_task: GivenTask(1),
where_to_look: "file_input/day6_example.txt",
expected_output: "42",
),
(
given_day: GivenDay(6),
given_task: GivenTask(2),
where_to_look: "file_input/day6_example.txt",
expected_output: "42",
),
(
given_day: GivenDay(7),
given_task: GivenTask(1),
where_to_look: "file_input/day7_example.txt",
expected_output: "42",
),
(
given_day: GivenDay(7),
given_task: GivenTask(2),
where_to_look: "file_input/day7_example.txt",
expected_output: "42",
),
]

View file

@ -1,38 +0,0 @@
[
(
given_day: GivenDay(5),
given_task: GivenTask(2),
where_to_look: "real_puzzel_input/day5_real.txt",
expected_output: "42",
),
(
given_day: GivenDay(5),
given_task: GivenTask(1),
where_to_look: "real_puzzel_input/day5_real.txt",
expected_output: "42",
),
(
given_day: GivenDay(6),
given_task: GivenTask(1),
where_to_look: "real_puzzel_input/day6_real.txt",
expected_output: "42",
),
(
given_day: GivenDay(6),
given_task: GivenTask(2),
where_to_look: "real_puzzel_input/day6_real.txt",
expected_output: "42",
),
(
given_day: GivenDay(7),
given_task: GivenTask(1),
where_to_look: "real_puzzel_input/day7_real.txt",
expected_output: "42",
),
(
given_day: GivenDay(7),
given_task: GivenTask(2),
where_to_look: "real_puzzel_input/day7_real.txt",
expected_output: "42",
),
]

View file

@ -1,9 +1,12 @@
use clap::Parser;
mod given_day;
mod given_task;
use super::{GivenDay, GivenTask};
pub use given_day::GivenDay;
pub use given_task::GivenTask;
#[derive(Debug, Parser)]
pub struct CliSolutionToSolve {
pub struct AppCliArguments {
#[arg(short, long)]
day: GivenDay,
#[arg(short, long)]
@ -13,7 +16,7 @@ pub struct CliSolutionToSolve {
input: String,
}
impl CliSolutionToSolve {
impl AppCliArguments {
pub fn day(&self) -> GivenDay {
self.day
}

View file

@ -1,7 +1,6 @@
use std::{str::FromStr, sync::Arc};
use derive_more::derive::{Display, Into};
use serde::{Deserialize, Serialize};
use derive_more::derive::Into;
use thiserror::Error;
use crate::constants;
@ -17,15 +16,15 @@ pub enum InvalidGivenDayError {
InvalidRange(u32),
}
#[derive(Debug, Copy, Clone, Into, PartialEq, Eq, Serialize, Deserialize, Display)]
#[derive(Debug, Copy, Clone, Into, PartialEq, Eq)]
pub struct GivenDay(u32);
impl GivenDay {
pub fn new(value: u32) -> Result<Self, InvalidGivenDayError> {
if (1..=constants::MAX_DAY).contains(&value) {
Ok(Self(value))
} else {
if value < 1 || value > constants::MAX_DAY {
Err(InvalidGivenDayError::InvalidRange(value))
} else {
Ok(Self(value))
}
}
}

View file

@ -1,7 +1,6 @@
use std::{str::FromStr, sync::Arc};
use derive_more::derive::{Display, Into};
use serde::{Deserialize, Serialize};
use derive_more::derive::Into;
use thiserror::Error;
use crate::constants;
@ -19,15 +18,15 @@ pub enum InvalidGivenTaskError {
InvalidRange(u32),
}
#[derive(Debug, Copy, Into, Clone, PartialEq, Eq, Serialize, Deserialize, Display)]
#[derive(Debug, Copy, Into, Clone, PartialEq, Eq)]
pub struct GivenTask(u32);
impl GivenTask {
pub fn new(value: u32) -> Result<Self, InvalidGivenTaskError> {
if (1..=constants::MAX_TASK).contains(&value) {
Ok(Self(value))
} else {
if value < 1 || value > constants::MAX_TASK {
Err(InvalidGivenTaskError::InvalidRange(value))
} else {
Ok(Self(value))
}
}
}

70
src/iterations.rs Normal file
View file

@ -0,0 +1,70 @@
pub trait AdventIterator: Iterator {
fn into_chunks<const N: usize>(self) -> impl Iterator<Item = Chunk<N, Self::Item>>
where
Self: Sized,
{
in_chunks::<N, Self::Item>(self)
}
}
impl<I> AdventIterator for I where I: Iterator {}
#[derive(Debug, PartialEq, Eq)]
pub enum Chunk<const N: usize, T> {
Next([T; N]),
Rest(Vec<T>),
}
pub fn in_chunks<const N: usize, T>(
mut iterator: impl Iterator<Item = T>,
) -> impl Iterator<Item = Chunk<N, T>> {
let mut buffer = Vec::new();
let mut done = false;
std::iter::from_fn(move || {
if done {
return None;
}
for _ in 0..N {
match iterator.next() {
Some(to_push) => buffer.push(to_push),
None => {
done = true;
return if buffer.is_empty() {
None
} else {
Some(Chunk::Rest(std::mem::take(&mut buffer)))
};
}
}
}
let array: [T; N] = std::mem::take(&mut buffer)
.try_into()
.unwrap_or_else(|_| panic!("Buffer must have the same size as the N ({})", N));
Some(Chunk::Next(array))
})
}
#[cfg(test)]
mod testing {
use crate::iterations::{in_chunks, Chunk};
#[test]
fn should_split_chunks() {
fn assert_case<const N: usize>(input: Vec<u32>, expected: Vec<Chunk<N, u32>>) {
let actual: Vec<Chunk<N, u32>> = in_chunks::<N, u32>(input.into_iter()).collect();
assert_eq!(expected, actual);
}
assert_case::<2>(vec![2], vec![Chunk::Rest(vec![2])]);
assert_case::<2>(vec![], vec![]);
assert_case::<2>(vec![2, 2], vec![Chunk::Next([2, 2])]);
assert_case::<2>(
vec![1, 2, 3],
vec![Chunk::Next([1, 2]), Chunk::Rest(vec![3])],
);
assert_case::<1>(
vec![1, 2, 3],
vec![Chunk::Next([1]), Chunk::Next([2]), Chunk::Next([3])],
);
}
}

6
src/lib.rs Normal file
View file

@ -0,0 +1,6 @@
pub mod cli;
pub mod constants;
pub mod iterations;
pub mod parsing_utils;
pub mod sequences;
pub mod solutions;

62
src/main.rs Normal file
View file

@ -0,0 +1,62 @@
use std::{fs, io, path::Path, process::ExitCode};
use advent_of_code_2023::{cli::AppCliArguments, solutions};
use clap::Parser;
use thiserror::Error;
fn main() -> ExitCode {
let args = AppCliArguments::parse();
env_logger::init();
let solution = solve_given(&args);
match solution {
Ok(found_solution) => {
println!("{}", found_solution);
ExitCode::SUCCESS
}
Err(error) => {
eprintln!("{}", error);
ExitCode::FAILURE
}
}
}
fn solve_given(args: &AppCliArguments) -> Result<String, CouldNotSolveError> {
let all_solutions = solutions::create_solutions();
let found_task = {
let day: u32 = args.day().into();
let task: u32 = args.task().into();
let found_day = all_solutions
.get(day.saturating_sub(1) as usize)
.ok_or_else(|| CouldNotSolveError::DayNotFound(day))?;
found_day
.get(task.saturating_sub(1) as usize)
.ok_or_else(|| CouldNotSolveError::TaskNotFound { day, task })
}?;
let puzzel_input = try_read_from_file_if_demanded(args)?;
let solved = (found_task)(&puzzel_input);
Ok(solved)
}
fn try_read_from_file_if_demanded(args: &AppCliArguments) -> io::Result<String> {
let content = if args.read_as_file() {
let path = Path::new(args.input());
let input_as_file = fs::read_to_string(path)?;
input_as_file
} else {
args.input().to_string()
};
Ok(content)
}
#[derive(Debug, Error)]
enum CouldNotSolveError {
#[error("There is no solution for the day {0}")]
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}")]
CouldNotReadFromFile(#[from] io::Error),
}

26
src/sequences.rs Normal file
View file

@ -0,0 +1,26 @@
pub fn is_sorted<T>(shoube_be_sorted: &[T]) -> bool
where
T: PartialOrd + Ord + Clone + PartialEq + Eq,
{
let mut sorted: Vec<T> = shoube_be_sorted.into_iter().cloned().collect();
sorted.sort();
sorted.as_slice().eq(shoube_be_sorted)
}
#[cfg(test)]
mod testing {
#[test]
fn should_detect_if_is_sorted() {
fn assert_case(input: &[u32], expected: bool) {
let actual = super::is_sorted(input);
assert_eq!(expected, actual, "Input {:#?}", input);
}
assert_case(&[1, 2], true);
assert_case(&[2, 1, 2], false);
assert_case(&[2, 1], false);
assert_case(&[1], true);
assert_case(&[], true);
}
}

View file

@ -1,12 +1,8 @@
use std::sync::LazyLock;
pub mod day5;
pub mod day6;
pub mod day7;
use solutions_advent_of_code_2023::day5;
use solutions_advent_of_code_2023::day6;
use solutions_advent_of_code_2023::day7;
pub type SolutionMatrix = Vec<Vec<fn(&str) -> String>>;
pub static ALL_SOLUTIONS: LazyLock<SolutionMatrix> = LazyLock::new(|| create_solutions());
fn create_solutions() -> SolutionMatrix {
pub fn create_solutions() -> Vec<Vec<fn(&str) -> String>> {
vec![
vec![not_implemented_yet, not_implemented_yet],
vec![not_implemented_yet, not_implemented_yet],

View file

@ -136,7 +136,7 @@ fn combine_single_to_ranges_for_seeds(single_seeds: &[UnsignedNumber]) -> Vec<Se
mod testing {
use std::str::FromStr;
use crate::day5::{
use crate::solutions::day5::{
combine_single_to_ranges_for_seeds, item_mapping::ItemMapping, parsing,
seed_range::SeedRange, simulate_one_round_on_one_seed_range, solve_task_2,
};

View file

@ -152,7 +152,7 @@ impl FromStr for ItemMapping {
#[cfg(test)]
mod testing {
use crate::day5::{
use crate::solutions::day5::{
item_mapping::{InvalidStrItemMapping, ItemMapping, MappedRange},
seed_range::SeedRange,
UnsignedNumber,

View file

@ -1,9 +1,9 @@
use crate::utils::parsing;
use crate::parsing_utils;
use super::{item_mapping::ItemMapping, UnsignedNumber};
pub fn parse(input: &str) -> (Vec<UnsignedNumber>, Vec<Vec<ItemMapping>>) {
let mut blocks = parsing::blocks_of_lines_seperated_by_empty_lines(input);
let mut blocks = parsing_utils::blocks_of_lines_seperated_by_empty_lines(input);
let seeds = {
let first_block = blocks.next().unwrap();
let first_line = first_block.first().unwrap();

View file

@ -1,5 +1,3 @@
use std::usize;
mod parsing;
mod race_record;
@ -18,34 +16,11 @@ pub fn solve_task_1(input: &str) -> String {
}
pub fn solve_task_2(input: &str) -> String {
let parsed = parsing::parsing_part_2(input);
let time_to_beat = parsed.time();
assert!(time_to_beat > 1, "Race time must be at least 2");
const FIRST_AND_LAST_CYCLE_DO_NOT_MOVE: NumericValue = 2;
const HALF_AT_OR_OVER_PEAK: NumericValue = 2;
let range: NumericValue =
(parsed.time() - FIRST_AND_LAST_CYCLE_DO_NOT_MOVE) / HALF_AT_OR_OVER_PEAK;
const FIRST_CYCLE_NO_DISTANCE: usize = 1;
for (index, next_distance) in all_rounds_of_durations(parsed.time())
let how_many_times_won = all_rounds_of_durations(parsed.time())
.into_iter()
.enumerate()
.skip(FIRST_CYCLE_NO_DISTANCE)
{
if next_distance > parsed.reached_distance() {
const EVEN_TIME_TO_BEAT_LEADS_UNEVEN_PICK: NumericValue = 1;
let one_offset = if time_to_beat % 2 == 0 {
EVEN_TIME_TO_BEAT_LEADS_UNEVEN_PICK
} else {
0
};
let lower_than_distance_over_pick = (index as NumericValue) - 1;
let both_halves = (range - lower_than_distance_over_pick) * 2;
let how_many_times_won = both_halves + one_offset;
return how_many_times_won.to_string();
}
}
unreachable!();
.filter(|&distance| distance > parsed.reached_distance())
.count() as NumericValue;
how_many_times_won.to_string()
}
fn all_rounds_of_durations(duration: NumericValue) -> Vec<NumericValue> {
@ -69,7 +44,7 @@ fn simuluate_reached_distance_at(
#[cfg(test)]
mod testing {
use crate::day6::{simuluate_reached_distance_at, solve_task_2, NumericValue};
use crate::solutions::day6::{simuluate_reached_distance_at, solve_task_2, NumericValue};
use super::solve_task_1;

View file

@ -41,7 +41,7 @@ pub fn parsing_part_2(input: &str) -> RaceRecord {
#[cfg(test)]
mod testing {
use crate::day6::race_record::RaceRecord;
use crate::solutions::day6::race_record::RaceRecord;
#[test]
fn should_parse() {

View file

@ -1,12 +1,12 @@
use crate::day7::dealt_hand::DealtHand;
use categorized_hand::{CategorizedHand, JokerOrdered};
use crate::solutions::day7::dealt_hand::DealtHand;
mod categorized_hand;
mod dealt_hand;
mod hand_kind;
mod hello;
mod parsing;
mod second_ordering;
mod hello;
pub fn solve_task_1(input: &str) -> String {
let parsed = parsing::parse_input(input);
@ -22,7 +22,7 @@ pub fn solve_task_1(input: &str) -> String {
pub fn solve_task_2(input: &str) -> String {
const JOKER: char = 'J';
let parsed = parsing::parse_input(input);
let sorted_and_categorized = categorize_and_sort_with_a_joker(parsed, JOKER);
let sorted_and_categorized= categorize_and_sort_with_a_joker(parsed, JOKER);
let total_winning = calc_total_winning(&sorted_and_categorized);
total_winning.to_string()
}

View file

@ -1,7 +1,7 @@
mod joker_ordered;
pub use joker_ordered::JokerOrdered;
use crate::day7::second_ordering;
use crate::solutions::day7::second_ordering;
use std::usize;
use super::{dealt_hand::DealtHand, hand_kind::HandKind, second_ordering::StrengthOfSymbols};
@ -39,12 +39,8 @@ fn hand_cmp(
) -> std::cmp::Ordering {
match left.kind.cmp(&right.kind) {
std::cmp::Ordering::Equal => {
assert_eq!(
left.kind, right.kind,
"If ordering is equal then the hand kind must be the same too\n\
left kind: ({:?}) and right kind: ({:?})",
left.kind, right.kind
);
assert_eq!(left.kind, right.kind, "If ordering is equal then the hand kind must be the same too\n\
left kind: ({:?}) and right kind: ({:?})", left.kind, right.kind);
second_ordering::compare_along_str(
left.rest().hand(),
right.rest().hand(),
@ -52,12 +48,8 @@ fn hand_cmp(
)
}
not_equal_ordering => {
assert_ne!(
left.kind, right.kind,
"If ordering is not equal then the hand kind must not be the same either\n\
left kind: ({:?}) and right kind: ({:?})",
left.kind, right.kind
);
assert_ne!(left.kind, right.kind, "If ordering is not equal then the hand kind must not be the same either\n\
left kind: ({:?}) and right kind: ({:?})", left.kind, right.kind);
not_equal_ordering
}
}
@ -86,7 +78,7 @@ impl From<(DealtHand, char)> for CategorizedHand {
mod testing {
use std::cmp::Ordering;
use crate::day7::{categorized_hand::CategorizedHand, dealt_hand::DealtHand};
use crate::solutions::day7::{categorized_hand::CategorizedHand, dealt_hand::DealtHand};
#[test]
fn compare_correctly_by_kind_and_second_ordering() {

View file

@ -1,6 +1,6 @@
use derive_more::derive::Into;
use crate::day7::second_ordering;
use crate::solutions::day7::second_ordering;
use super::{hand_cmp, CategorizedHand};
@ -32,7 +32,7 @@ impl PartialOrd for JokerOrdered {
mod testing {
use std::cmp::Ordering;
use crate::day7::{
use crate::solutions::day7::{
categorized_hand::{CategorizedHand, JokerOrdered},
dealt_hand::DealtHand,
second_ordering::{self, JOKER},

View file

@ -58,7 +58,7 @@ impl FromStr for DealtHand {
#[cfg(test)]
mod testing {
use crate::day7::dealt_hand::{DealtHand, InvalidStrDealtHand};
use crate::solutions::day7::dealt_hand::{DealtHand, InvalidStrDealtHand};
#[test]
fn parse_str() {

View file

@ -1,5 +1,6 @@
use std::{cmp::Reverse, collections::HashMap};
use log::warn;
use non_zero_count::NonZeroCount;
mod non_zero_count;
@ -120,14 +121,16 @@ fn choose_kind_from(to_choose_from: &[usize]) -> HandKind {
}
calc_kind(&to_choose_from).unwrap_or_else(|| {
warn!("Got hand ({:?}) with less than 2 cards", &to_choose_from);
let default_value = HandKind::default();
warn!("Default kind ({:?}) is assumed", default_value);
default_value
})
}
#[cfg(test)]
mod testing {
use crate::day7::{
use crate::solutions::day7::{
categorized_hand::CategorizedHand, dealt_hand::DealtHand, hand_kind::HandKind,
};

View file

@ -6,7 +6,7 @@ pub fn parse_input(input: &str) -> Vec<DealtHand> {
#[cfg(test)]
mod testing {
use crate::day7::{dealt_hand::DealtHand, TEST_INPUT};
use crate::solutions::day7::{dealt_hand::DealtHand, TEST_INPUT};
#[test]
fn parse() {

View file

@ -1,5 +1,7 @@
use std::{cmp::Ordering, collections::HashMap, ops::RangeInclusive, sync::LazyLock, usize};
use log::warn;
pub const JOKER: char = 'J';
static LETTERS_WITHOUT_JOKER: &[char] = &['T', 'Q', 'K', 'A'];
static LETTERS: &[char] = &['T', 'J', 'Q', 'K', 'A'];
@ -55,6 +57,11 @@ pub fn compare_along_str(
}
}
let (left_len, right_len) = (left.len(), right.len());
warn!(
"Left and right seem to have no difference in strength\n\
Now comparing via lenght ({}) ({}). By same length, lefte wins !",
left_len, right_len
);
left_len.cmp(&right_len)
}