making 2023 a generic aoc repo
This commit is contained in:
50
2023/.gitignore
vendored
Normal file
50
2023/.gitignore
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
# Generated by Cargo
|
||||
# will have compiled files and executables
|
||||
debug/
|
||||
target/
|
||||
|
||||
# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
|
||||
# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html
|
||||
#Cargo.lock
|
||||
|
||||
# These are backup files generated by rustfmt
|
||||
**/*.rs.bk
|
||||
|
||||
# MSVC Windows builds of rustc generate these, which store debugging information
|
||||
*.pdb
|
||||
|
||||
.vscode/*
|
||||
!.vscode/settings.json
|
||||
!.vscode/tasks.json
|
||||
!.vscode/launch.json
|
||||
!.vscode/extensions.json
|
||||
!.vscode/*.code-snippets
|
||||
|
||||
# Local History for Visual Studio Code
|
||||
.history/
|
||||
|
||||
# Built Visual Studio Code Extensions
|
||||
*.vsix
|
||||
|
||||
# Swap
|
||||
[._]*.s[a-v][a-z]
|
||||
!*.svg # comment out if you don't need vector files
|
||||
[._]*.sw[a-p]
|
||||
[._]s[a-rt-v][a-z]
|
||||
[._]ss[a-gi-z]
|
||||
[._]sw[a-p]
|
||||
|
||||
# Session
|
||||
Session.vim
|
||||
Sessionx.vim
|
||||
|
||||
# Temporary
|
||||
.netrwhist
|
||||
*~
|
||||
# Auto-generated tag files
|
||||
tags
|
||||
# Persistent undo
|
||||
[._]*.un~
|
||||
.vscode/settings.json
|
||||
|
||||
input.txt
|
||||
458
2023/Cargo.lock
generated
Normal file
458
2023/Cargo.lock
generated
Normal file
@@ -0,0 +1,458 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "aho-corasick"
|
||||
version = "1.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.75"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6"
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "day-1"
|
||||
version = "2023.0.0"
|
||||
dependencies = [
|
||||
"derive-getters",
|
||||
"error-stack",
|
||||
"itertools",
|
||||
"log",
|
||||
"nom",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "day-2"
|
||||
version = "2023.0.0"
|
||||
dependencies = [
|
||||
"itertools",
|
||||
"log",
|
||||
"nom",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "day-3"
|
||||
version = "2023.0.0"
|
||||
dependencies = [
|
||||
"itertools",
|
||||
"log",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "day-4"
|
||||
version = "2023.0.0"
|
||||
dependencies = [
|
||||
"itertools",
|
||||
"nom",
|
||||
"rstest",
|
||||
"rstest_reuse",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "day-5"
|
||||
version = "2023.0.0"
|
||||
dependencies = [
|
||||
"itertools",
|
||||
"nom",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "derive-getters"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7a2c35ab6e03642397cdda1dd58abbc05d418aef8e36297f336d5aba060fe8df"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "either"
|
||||
version = "1.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07"
|
||||
|
||||
[[package]]
|
||||
name = "error-stack"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "27a72baa257b5e0e2de241967bc5ee8f855d6072351042688621081d66b2a76b"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"rustc_version",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures"
|
||||
version = "0.3.29"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "da0290714b38af9b4a7b094b8a37086d1b4e61f2df9122c3cad2577669145335"
|
||||
dependencies = [
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
"futures-executor",
|
||||
"futures-io",
|
||||
"futures-sink",
|
||||
"futures-task",
|
||||
"futures-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-channel"
|
||||
version = "0.3.29"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ff4dd66668b557604244583e3e1e1eada8c5c2e96a6d0d6653ede395b78bbacb"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"futures-sink",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-core"
|
||||
version = "0.3.29"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "eb1d22c66e66d9d72e1758f0bd7d4fd0bee04cad842ee34587d68c07e45d088c"
|
||||
|
||||
[[package]]
|
||||
name = "futures-executor"
|
||||
version = "0.3.29"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0f4fb8693db0cf099eadcca0efe2a5a22e4550f98ed16aba6c48700da29597bc"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"futures-task",
|
||||
"futures-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-io"
|
||||
version = "0.3.29"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8bf34a163b5c4c52d0478a4d757da8fb65cabef42ba90515efee0f6f9fa45aaa"
|
||||
|
||||
[[package]]
|
||||
name = "futures-macro"
|
||||
version = "0.3.29"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "53b153fd91e4b0147f4aced87be237c98248656bb01050b96bf3ee89220a8ddb"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.39",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-sink"
|
||||
version = "0.3.29"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e36d3378ee38c2a36ad710c5d30c2911d752cb941c00c72dbabfb786a7970817"
|
||||
|
||||
[[package]]
|
||||
name = "futures-task"
|
||||
version = "0.3.29"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "efd193069b0ddadc69c46389b740bbccdd97203899b48d09c5f7969591d6bae2"
|
||||
|
||||
[[package]]
|
||||
name = "futures-timer"
|
||||
version = "3.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e64b03909df88034c26dc1547e8970b91f98bdb65165d6a4e9110d94263dbb2c"
|
||||
|
||||
[[package]]
|
||||
name = "futures-util"
|
||||
version = "0.3.29"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a19526d624e703a3179b3d322efec918b6246ea0fa51d41124525f00f1cc8104"
|
||||
dependencies = [
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
"futures-io",
|
||||
"futures-macro",
|
||||
"futures-sink",
|
||||
"futures-task",
|
||||
"memchr",
|
||||
"pin-project-lite",
|
||||
"pin-utils",
|
||||
"slab",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.2.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fe9006bed769170c11f845cf00c7c1e9092aeb3f268e007c3e760ac68008070f"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"wasi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "glob"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b"
|
||||
|
||||
[[package]]
|
||||
name = "itertools"
|
||||
version = "0.12.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "25db6b064527c5d482d0423354fcd07a89a2dfe07b67892e62411946db7f07b0"
|
||||
dependencies = [
|
||||
"either",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.150"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c"
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f"
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.6.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167"
|
||||
|
||||
[[package]]
|
||||
name = "minimal-lexical"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
|
||||
|
||||
[[package]]
|
||||
name = "nom"
|
||||
version = "7.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
"minimal-lexical",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pin-project-lite"
|
||||
version = "0.2.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58"
|
||||
|
||||
[[package]]
|
||||
name = "pin-utils"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
|
||||
|
||||
[[package]]
|
||||
name = "ppv-lite86"
|
||||
version = "0.2.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.70"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "39278fbbf5fb4f646ce651690877f89d1c5811a3d4acb27700c1cb3cdb78fd3b"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.33"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.8.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"rand_chacha",
|
||||
"rand_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_chacha"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
|
||||
dependencies = [
|
||||
"ppv-lite86",
|
||||
"rand_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_core"
|
||||
version = "0.6.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.10.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
"regex-automata",
|
||||
"regex-syntax",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-automata"
|
||||
version = "0.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
"regex-syntax",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-syntax"
|
||||
version = "0.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f"
|
||||
|
||||
[[package]]
|
||||
name = "relative-path"
|
||||
version = "1.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c707298afce11da2efef2f600116fa93ffa7a032b5d7b628aa17711ec81383ca"
|
||||
|
||||
[[package]]
|
||||
name = "rstest"
|
||||
version = "0.18.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "97eeab2f3c0a199bc4be135c36c924b6590b88c377d416494288c14f2db30199"
|
||||
dependencies = [
|
||||
"futures",
|
||||
"futures-timer",
|
||||
"rstest_macros",
|
||||
"rustc_version",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rstest_macros"
|
||||
version = "0.18.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d428f8247852f894ee1be110b375111b586d4fa431f6c46e64ba5a0dcccbe605"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"glob",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"regex",
|
||||
"relative-path",
|
||||
"rustc_version",
|
||||
"syn 2.0.39",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rstest_reuse"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "88530b681abe67924d42cca181d070e3ac20e0740569441a9e35a7cedd2b34a4"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"rand",
|
||||
"rustc_version",
|
||||
"syn 2.0.39",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc_version"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366"
|
||||
dependencies = [
|
||||
"semver",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "semver"
|
||||
version = "1.0.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "836fa6a3e1e547f9a2c4040802ec865b5d85f4014efe00555d7090a3dcaa1090"
|
||||
|
||||
[[package]]
|
||||
name = "slab"
|
||||
version = "0.4.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.109"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.39"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "23e78b90f2fcf45d3e842032ce32e3f2d1545ba6636271dcbf24fa306d87be7a"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
|
||||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
version = "0.11.0+wasi-snapshot-preview1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
||||
18
2023/Cargo.toml
Normal file
18
2023/Cargo.toml
Normal file
@@ -0,0 +1,18 @@
|
||||
[workspace]
|
||||
resolver = "2"
|
||||
members = [ "day-*" ]
|
||||
|
||||
[workspace.package]
|
||||
version = "2023.0.0"
|
||||
edition = "2021"
|
||||
authors = [ "Dylan Thies" ]
|
||||
repository = "https://github.com/smellyfis/AOC-2023.git"
|
||||
|
||||
[workspace.dependencies]
|
||||
derive-getters = "0.3.0"
|
||||
error-stack = "0.4.1"
|
||||
itertools = "0.12.0"
|
||||
log = "0.4.20"
|
||||
nom = "7.1.3"
|
||||
rstest = "0.18.2"
|
||||
rstest_reuse = "0.6.0"
|
||||
16
2023/day-1/Cargo.toml
Normal file
16
2023/day-1/Cargo.toml
Normal file
@@ -0,0 +1,16 @@
|
||||
[package]
|
||||
name = "day-1"
|
||||
version.workspace = true
|
||||
edition.workspace = true
|
||||
authors.workspace = true
|
||||
repository.workspace = true
|
||||
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
derive-getters.workspace = true
|
||||
error-stack.workspace = true
|
||||
itertools.workspace = true
|
||||
log.workspace = true
|
||||
nom.workspace = true
|
||||
2
2023/day-1/src/lib.rs
Normal file
2
2023/day-1/src/lib.rs
Normal file
@@ -0,0 +1,2 @@
|
||||
pub mod part1;
|
||||
pub mod part2;
|
||||
12
2023/day-1/src/main.rs
Normal file
12
2023/day-1/src/main.rs
Normal file
@@ -0,0 +1,12 @@
|
||||
#![warn(clippy::all, clippy::pedantic)]
|
||||
|
||||
use day_1::part1::part1;
|
||||
use day_1::part2::part2;
|
||||
|
||||
fn main() {
|
||||
let input = include_str!("./input.txt");
|
||||
let (_, part1_result) = part1(input).unwrap();
|
||||
println!("part 1: {part1_result}");
|
||||
let part2_result = part2(input);
|
||||
println!("part 2: {part2_result}");
|
||||
}
|
||||
59
2023/day-1/src/part1.rs
Normal file
59
2023/day-1/src/part1.rs
Normal file
@@ -0,0 +1,59 @@
|
||||
#![warn(clippy::all, clippy::pedantic)]
|
||||
|
||||
use nom::{
|
||||
self,
|
||||
character::complete::{alphanumeric1, newline},
|
||||
multi::separated_list1,
|
||||
};
|
||||
|
||||
/// Day-1 part 1 of AC2023
|
||||
///
|
||||
/// # Arguments
|
||||
/// - input the input for day1 as a string
|
||||
///
|
||||
/// # Panics
|
||||
/// This panics whenever a number isn't present in a line of the input
|
||||
///
|
||||
/// # Errors
|
||||
/// errors when can't parse the input
|
||||
pub fn part1(input: &str) -> nom::IResult<&str, String> {
|
||||
let (_, values) = parse_input(input)?;
|
||||
println!("{values:?}");
|
||||
Ok((
|
||||
"",
|
||||
values
|
||||
.iter()
|
||||
.map(|v| v.first().expect("always at least one number") * 10 + v.last().expect("always atleast one number"))
|
||||
.sum::<u32>()
|
||||
.to_string(),
|
||||
))
|
||||
}
|
||||
|
||||
fn parse_input(input: &str) -> nom::IResult<&str, Vec<Vec<u32>>> {
|
||||
let (i, j) = separated_list1(newline, alphanumeric1)(input)?;
|
||||
let res = j
|
||||
.iter()
|
||||
.map(|v| {
|
||||
v.chars()
|
||||
.filter_map(|x| x.to_digit(10))
|
||||
.collect::<Vec<u32>>()
|
||||
})
|
||||
.collect::<Vec<Vec<u32>>>();
|
||||
Ok((i, res))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
||||
const INPUT: &str = "1abc2
|
||||
pqr3stu8vwx
|
||||
a1b2c3d4e5f
|
||||
treb7uchet";
|
||||
|
||||
#[test]
|
||||
fn part1_works() {
|
||||
let (_, result) = part1(INPUT).unwrap();
|
||||
assert_eq!(result, "142".to_string());
|
||||
}
|
||||
}
|
||||
70
2023/day-1/src/part2.rs
Normal file
70
2023/day-1/src/part2.rs
Normal file
@@ -0,0 +1,70 @@
|
||||
#![warn(clippy::all, clippy::pedantic)]
|
||||
|
||||
/// Day 1 Part 2 of AOC2023
|
||||
///
|
||||
/// # Arguments
|
||||
/// - puzzle input
|
||||
///
|
||||
/// # Panics
|
||||
/// this panics if there is no numbers in a line
|
||||
pub fn part2(input: &str) -> String {
|
||||
let values = input.lines().map(parse_line).collect::<Vec<Vec<u32>>>();
|
||||
println!("{values:?}");
|
||||
values
|
||||
.iter()
|
||||
.map(|v| v.first().expect("There is always at least one number") * 10 + v.last().expect("there is always at least one number"))
|
||||
.sum::<u32>()
|
||||
.to_string()
|
||||
}
|
||||
|
||||
fn parse_line(line: &str) -> Vec<u32> {
|
||||
(0..line.len())
|
||||
.filter_map(|index| {
|
||||
let reduced_line = &line[index..];
|
||||
let result = if reduced_line.starts_with("one") {
|
||||
Some(1)
|
||||
} else if reduced_line.starts_with("two") {
|
||||
Some(2)
|
||||
} else if reduced_line.starts_with("three") {
|
||||
Some(3)
|
||||
} else if reduced_line.starts_with("four") {
|
||||
Some(4)
|
||||
} else if reduced_line.starts_with("five") {
|
||||
Some(5)
|
||||
} else if reduced_line.starts_with("six") {
|
||||
Some(6)
|
||||
} else if reduced_line.starts_with("seven") {
|
||||
Some(7)
|
||||
} else if reduced_line.starts_with("eight") {
|
||||
Some(8)
|
||||
} else if reduced_line.starts_with("nine") {
|
||||
Some(9)
|
||||
} else if reduced_line.starts_with("zero") {
|
||||
Some(0)
|
||||
} else {
|
||||
reduced_line.chars().next().expect("there is alwayss a character").to_digit(10)
|
||||
};
|
||||
|
||||
result
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
||||
const INPUT: &str = "two1nine
|
||||
eightwothree
|
||||
abcone2threexyz
|
||||
xtwone3four
|
||||
4nineeightseven2
|
||||
zoneight234
|
||||
7pqrstsixteen";
|
||||
|
||||
#[test]
|
||||
fn part2_works() {
|
||||
let result = part2(INPUT);
|
||||
assert_eq!(result, "281".to_string());
|
||||
}
|
||||
}
|
||||
13
2023/day-2/Cargo.toml
Normal file
13
2023/day-2/Cargo.toml
Normal file
@@ -0,0 +1,13 @@
|
||||
[package]
|
||||
name = "day-2"
|
||||
version.workspace = true
|
||||
edition.workspace = true
|
||||
authors.workspace = true
|
||||
repository.workspace = true
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
nom.workspace = true
|
||||
itertools.workspace = true
|
||||
log.workspace = true
|
||||
4
2023/day-2/src/lib.rs
Normal file
4
2023/day-2/src/lib.rs
Normal file
@@ -0,0 +1,4 @@
|
||||
pub mod part1;
|
||||
pub use crate::part1::part1;
|
||||
pub mod part2;
|
||||
pub use crate::part2::part2;
|
||||
12
2023/day-2/src/main.rs
Normal file
12
2023/day-2/src/main.rs
Normal file
@@ -0,0 +1,12 @@
|
||||
#![warn(clippy::all, clippy::pedantic)]
|
||||
|
||||
use day_2::part1;
|
||||
use day_2::part2;
|
||||
|
||||
fn main() {
|
||||
let input = include_str!("./input.txt");
|
||||
let part1_result = part1(input);
|
||||
println!("part 1: {part1_result}");
|
||||
let part2_result = part2(input);
|
||||
println!("part 2: {part2_result}");
|
||||
}
|
||||
115
2023/day-2/src/part1.rs
Normal file
115
2023/day-2/src/part1.rs
Normal file
@@ -0,0 +1,115 @@
|
||||
#![warn(clippy::all, clippy::pedantic)]
|
||||
|
||||
use log::debug;
|
||||
use nom::{
|
||||
bytes::complete::tag,
|
||||
character::complete::{self, newline},
|
||||
multi::separated_list1,
|
||||
sequence::{preceded, separated_pair},
|
||||
};
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Round {
|
||||
pub red_n: u32,
|
||||
pub green_n: u32,
|
||||
pub blue_n: u32,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Game {
|
||||
pub id: u32,
|
||||
pub rounds: Vec<Round>,
|
||||
}
|
||||
|
||||
impl Game {
|
||||
fn to_part1(&self) -> Option<u32> {
|
||||
if self
|
||||
.rounds
|
||||
.iter()
|
||||
.find_map(|r| {
|
||||
//TODO if inverted use find_map
|
||||
if r.red_n > 12 || r.green_n > 13 || r.blue_n > 14 {
|
||||
Some(self.id)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.is_some()
|
||||
{
|
||||
None
|
||||
} else {
|
||||
Some(self.id)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// part2 of day 2 of AOC 2023
|
||||
///
|
||||
/// # Arguments
|
||||
/// - input the puszzle input
|
||||
///
|
||||
/// # Panics
|
||||
/// panics whenever the input isn't parsable
|
||||
pub fn part1(input: &str) -> String {
|
||||
let (_, games) = process_input(input).expect("there should be input");
|
||||
debug!("{games:?}");
|
||||
games
|
||||
.iter()
|
||||
.filter_map(Game::to_part1)
|
||||
.sum::<u32>()
|
||||
.to_string()
|
||||
}
|
||||
|
||||
fn process_block(input: &str) -> nom::IResult<&str, (u32, String)> {
|
||||
let (i, (cnt, color)) =
|
||||
separated_pair(complete::u32, complete::space1, complete::alpha1)(input)?;
|
||||
Ok((i, (cnt, color.to_owned())))
|
||||
}
|
||||
|
||||
fn process_round(input: &str) -> nom::IResult<&str, Round> {
|
||||
let (i, blocks) = separated_list1(tag(", "), process_block)(input)?;
|
||||
let mut round = Round {
|
||||
red_n: 0,
|
||||
green_n: 0,
|
||||
blue_n: 0,
|
||||
};
|
||||
for (cnt, color) in blocks {
|
||||
match color.as_str() {
|
||||
"red" => round.red_n = cnt,
|
||||
"green" => round.green_n = cnt,
|
||||
"blue" => round.blue_n = cnt,
|
||||
_ => panic!("this should be a color name"),
|
||||
};
|
||||
}
|
||||
Ok((i, round))
|
||||
}
|
||||
|
||||
fn process_game(input: &str) -> nom::IResult<&str, Game> {
|
||||
let (i, (id, rounds)) = separated_pair(
|
||||
preceded(tag("Game "), complete::u32),
|
||||
tag(": "),
|
||||
separated_list1(tag("; "), process_round),
|
||||
)(input)?;
|
||||
Ok((i, Game { id, rounds }))
|
||||
}
|
||||
|
||||
fn process_input(input: &str) -> nom::IResult<&str, Vec<Game>> {
|
||||
separated_list1(newline, process_game)(input)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
||||
const INPUT: &str = "Game 1: 3 blue, 4 red; 1 red, 2 green, 6 blue; 2 green
|
||||
Game 2: 1 blue, 2 green; 3 green, 4 blue, 1 red; 1 green, 1 blue
|
||||
Game 3: 8 green, 6 blue, 20 red; 5 blue, 4 red, 13 green; 5 green, 1 red
|
||||
Game 4: 1 green, 3 red, 6 blue; 3 green, 6 red; 3 green, 15 blue, 14 red
|
||||
Game 5: 6 red, 1 blue, 3 green; 2 blue, 1 red, 2 green";
|
||||
|
||||
#[test]
|
||||
fn part1_works() {
|
||||
let result = part1(INPUT);
|
||||
assert_eq!(result, "8".to_string());
|
||||
}
|
||||
}
|
||||
106
2023/day-2/src/part2.rs
Normal file
106
2023/day-2/src/part2.rs
Normal file
@@ -0,0 +1,106 @@
|
||||
#![warn(clippy::all, clippy::pedantic)]
|
||||
|
||||
use nom::{
|
||||
bytes::complete::tag,
|
||||
character::complete::{self, newline},
|
||||
multi::separated_list1,
|
||||
sequence::{preceded, separated_pair},
|
||||
};
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Round {
|
||||
pub red_n: u32,
|
||||
pub green_n: u32,
|
||||
pub blue_n: u32,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Game {
|
||||
pub _id: u32,
|
||||
pub rounds: Vec<Round>,
|
||||
}
|
||||
|
||||
impl Game {
|
||||
fn to_power(&self) -> u64 {
|
||||
let (r, g, b) = self.rounds.iter().fold((0_u64, 0_u64, 0_u64), |acc, x| {
|
||||
let (mut val_r, mut val_g, mut val_b) = acc;
|
||||
if u64::from(x.red_n) > acc.0 {
|
||||
val_r = x.red_n.into();
|
||||
}
|
||||
if u64::from(x.green_n) > acc.1 {
|
||||
val_g = x.green_n.into();
|
||||
}
|
||||
if u64::from(x.blue_n) > acc.2 {
|
||||
val_b = x.blue_n.into();
|
||||
}
|
||||
(val_r, val_g, val_b)
|
||||
});
|
||||
r * g * b
|
||||
}
|
||||
}
|
||||
|
||||
/// part2 of day 2 of AOC 2023
|
||||
///
|
||||
/// # Arguments
|
||||
/// - input the puszzle input
|
||||
///
|
||||
/// # Panics
|
||||
/// panics whenever the input isn't parsable
|
||||
pub fn part2(input: &str) -> String {
|
||||
let (_, games) = process_input(input).expect("there should be input");
|
||||
games.iter().map(Game::to_power).sum::<u64>().to_string()
|
||||
}
|
||||
|
||||
fn process_block(input: &str) -> nom::IResult<&str, (u32, String)> {
|
||||
let (i, (cnt, color)) =
|
||||
separated_pair(complete::u32, complete::space1, complete::alpha1)(input)?;
|
||||
Ok((i, (cnt, color.to_owned())))
|
||||
}
|
||||
|
||||
fn process_round(input: &str) -> nom::IResult<&str, Round> {
|
||||
let (i, blocks) = separated_list1(tag(", "), process_block)(input)?;
|
||||
let mut round = Round {
|
||||
red_n: 0,
|
||||
green_n: 0,
|
||||
blue_n: 0,
|
||||
};
|
||||
for (cnt, color) in blocks {
|
||||
match color.as_str() {
|
||||
"red" => round.red_n = cnt,
|
||||
"green" => round.green_n = cnt,
|
||||
"blue" => round.blue_n = cnt,
|
||||
_ => panic!("this should be a color name"),
|
||||
};
|
||||
}
|
||||
Ok((i, round))
|
||||
}
|
||||
|
||||
fn process_game(input: &str) -> nom::IResult<&str, Game> {
|
||||
let (i, (id, rounds)) = separated_pair(
|
||||
preceded(tag("Game "), complete::u32),
|
||||
tag(": "),
|
||||
separated_list1(tag("; "), process_round),
|
||||
)(input)?;
|
||||
Ok((i, Game { _id: id, rounds }))
|
||||
}
|
||||
|
||||
fn process_input(input: &str) -> nom::IResult<&str, Vec<Game>> {
|
||||
separated_list1(newline, process_game)(input)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
||||
const INPUT: &str = "Game 1: 3 blue, 4 red; 1 red, 2 green, 6 blue; 2 green
|
||||
Game 2: 1 blue, 2 green; 3 green, 4 blue, 1 red; 1 green, 1 blue
|
||||
Game 3: 8 green, 6 blue, 20 red; 5 blue, 4 red, 13 green; 5 green, 1 red
|
||||
Game 4: 1 green, 3 red, 6 blue; 3 green, 6 red; 3 green, 15 blue, 14 red
|
||||
Game 5: 6 red, 1 blue, 3 green; 2 blue, 1 red, 2 green";
|
||||
|
||||
#[test]
|
||||
fn part2_works() {
|
||||
let result = part2(INPUT);
|
||||
assert_eq!(result, "2286".to_string());
|
||||
}
|
||||
}
|
||||
12
2023/day-3/Cargo.toml
Normal file
12
2023/day-3/Cargo.toml
Normal file
@@ -0,0 +1,12 @@
|
||||
[package]
|
||||
name = "day-3"
|
||||
version.workspace = true
|
||||
edition.workspace = true
|
||||
authors.workspace = true
|
||||
repository.workspace = true
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
itertools.workspace = true
|
||||
log.workspace = true
|
||||
4
2023/day-3/src/lib.rs
Normal file
4
2023/day-3/src/lib.rs
Normal file
@@ -0,0 +1,4 @@
|
||||
pub mod part1;
|
||||
pub use crate::part1::*;
|
||||
pub mod part2;
|
||||
pub use crate::part2::*;
|
||||
12
2023/day-3/src/main.rs
Normal file
12
2023/day-3/src/main.rs
Normal file
@@ -0,0 +1,12 @@
|
||||
#![warn(clippy::all, clippy::pedantic)]
|
||||
|
||||
use day_3::part1;
|
||||
use day_3::part2;
|
||||
|
||||
fn main() {
|
||||
let input = include_str!("./input.txt");
|
||||
let part1_result = part1(input);
|
||||
println!("part 1: {part1_result}");
|
||||
let part2_result = part2(input);
|
||||
println!("part 2: {part2_result}");
|
||||
}
|
||||
129
2023/day-3/src/part1.rs
Normal file
129
2023/day-3/src/part1.rs
Normal file
@@ -0,0 +1,129 @@
|
||||
#![warn(clippy::all, clippy::pedantic)]
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
#[derive(Debug)]
|
||||
struct SerialNumber {
|
||||
pub no: u64,
|
||||
pub start: (usize, usize),
|
||||
pub end: (usize, usize),
|
||||
}
|
||||
|
||||
impl SerialNumber {
|
||||
fn generate_adjacent(&self) -> Vec<(usize, usize)> {
|
||||
let start_row = if self.start.0 == 0 {
|
||||
0
|
||||
} else {
|
||||
self.start.0 - 1
|
||||
};
|
||||
let start_line = if self.start.1 == 0 {
|
||||
0
|
||||
} else {
|
||||
self.start.1 - 1
|
||||
};
|
||||
(start_row..=(self.end.0 + 1))
|
||||
.flat_map(|x| (start_line..=(self.end.1 + 1)).map(move |y| (x, y)))
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn part1(input: &str) -> String {
|
||||
let (serials, symbols) = parse_input(input);
|
||||
serials
|
||||
.iter()
|
||||
.filter(|x| {
|
||||
x.generate_adjacent()
|
||||
.iter()
|
||||
.any(|t| symbols.get(t).is_some())
|
||||
})
|
||||
.map(|x| x.no)
|
||||
.sum::<u64>()
|
||||
.to_string()
|
||||
}
|
||||
|
||||
fn parse_input(input: &str) -> (Vec<SerialNumber>, BTreeMap<(usize, usize), char>) {
|
||||
let mut numbers = Vec::new();
|
||||
let mut symbols = BTreeMap::new();
|
||||
for (line_no, line) in input.lines().enumerate() {
|
||||
let mut prev_char = None;
|
||||
let mut cur_no = 0_u64;
|
||||
let mut cur_no_row_start = 0_usize;
|
||||
for (row_no, c) in line.chars().enumerate() {
|
||||
if let Some(d) = c.to_digit(10) {
|
||||
if prev_char.is_some() {
|
||||
cur_no = cur_no * 10 + u64::from(d);
|
||||
} else {
|
||||
cur_no = u64::from(d);
|
||||
cur_no_row_start = row_no;
|
||||
}
|
||||
prev_char = Some(c);
|
||||
} else {
|
||||
if prev_char.is_some() {
|
||||
//handle saving number off
|
||||
numbers.push(SerialNumber {
|
||||
no: cur_no,
|
||||
start: (cur_no_row_start, line_no),
|
||||
end: (row_no - 1, line_no),
|
||||
});
|
||||
}
|
||||
prev_char = None;
|
||||
if c == '.' {
|
||||
//move along space
|
||||
continue;
|
||||
}
|
||||
//store symbol
|
||||
let _ = symbols.insert((row_no, line_no), c);
|
||||
}
|
||||
}
|
||||
//need to account for new line numbers
|
||||
if prev_char.is_some() {
|
||||
numbers.push(SerialNumber {
|
||||
no: cur_no,
|
||||
start: (cur_no_row_start, line_no),
|
||||
end: (line.len() - 1, line_no),
|
||||
});
|
||||
}
|
||||
}
|
||||
(numbers, symbols)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
||||
const INPUT: &str = "467..114..
|
||||
...*......
|
||||
..35..633.
|
||||
......#...
|
||||
617*......
|
||||
.....+.58.
|
||||
..592.....
|
||||
......755.
|
||||
...$.*....
|
||||
.664.598..";
|
||||
|
||||
const INPUT2: &str = "12.......*..
|
||||
+.........34
|
||||
.......-12..
|
||||
..78........
|
||||
..*....60...
|
||||
78.........9
|
||||
.5.....23..$
|
||||
8...90*12...
|
||||
............
|
||||
2.2......12.
|
||||
.*.........*
|
||||
1.1..503+.56";
|
||||
|
||||
#[test]
|
||||
fn part1_works() {
|
||||
let result = part1(INPUT);
|
||||
assert_eq!(result, "4361".to_string());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn part1_works_more() {
|
||||
let result = part1(INPUT2);
|
||||
assert_eq!(result, "925".to_string());
|
||||
}
|
||||
}
|
||||
113
2023/day-3/src/part2.rs
Normal file
113
2023/day-3/src/part2.rs
Normal file
@@ -0,0 +1,113 @@
|
||||
#![warn(clippy::all, clippy::pedantic)]
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
#[derive(Debug)]
|
||||
struct SerialNumber {
|
||||
pub no: u64,
|
||||
pub start: (usize, usize),
|
||||
pub end: (usize, usize),
|
||||
}
|
||||
|
||||
impl SerialNumber {
|
||||
fn is_adjacent(&self, pos: (usize, usize)) -> bool {
|
||||
usize::abs_diff(self.start.1, pos.1) < 2
|
||||
&& self.start.0 < 2 + pos.0
|
||||
&& pos.0 < 2 + self.end.0
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn part2(input: &str) -> String {
|
||||
let (serials, symbols) = parse_input(input);
|
||||
symbols
|
||||
.iter()
|
||||
.filter_map(|(key, value)| if *value == '*' { Some(*key) } else { None })
|
||||
.filter_map(|pos| {
|
||||
let serials = serials
|
||||
.iter()
|
||||
.filter_map(|serial| {
|
||||
if serial.is_adjacent(pos) {
|
||||
Some(serial.no)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.collect::<Vec<u64>>();
|
||||
if serials.len() == 2 {
|
||||
Some(serials[0] * serials[1])
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.sum::<u64>()
|
||||
.to_string()
|
||||
//find all serials next to '*' and map with '*' location
|
||||
}
|
||||
|
||||
fn parse_input(input: &str) -> (Vec<SerialNumber>, BTreeMap<(usize, usize), char>) {
|
||||
let mut numbers = Vec::new();
|
||||
let mut symbols = BTreeMap::new();
|
||||
for (line_no, line) in input.lines().enumerate() {
|
||||
let mut prev_char = None;
|
||||
let mut cur_no = 0_u64;
|
||||
let mut cur_no_row_start = 0_usize;
|
||||
for (row_no, c) in line.chars().enumerate() {
|
||||
if let Some(d) = c.to_digit(10) {
|
||||
if prev_char.is_some() {
|
||||
cur_no = cur_no * 10 + u64::from(d);
|
||||
} else {
|
||||
cur_no = u64::from(d);
|
||||
cur_no_row_start = row_no;
|
||||
}
|
||||
prev_char = Some(c);
|
||||
} else {
|
||||
if prev_char.is_some() {
|
||||
//handle saving number off
|
||||
numbers.push(SerialNumber {
|
||||
no: cur_no,
|
||||
start: (cur_no_row_start, line_no),
|
||||
end: (row_no - 1, line_no),
|
||||
});
|
||||
}
|
||||
prev_char = None;
|
||||
if c == '.' {
|
||||
//move along space
|
||||
continue;
|
||||
}
|
||||
//store symbol
|
||||
let _ = symbols.insert((row_no, line_no), c);
|
||||
}
|
||||
}
|
||||
//need to account for new line numbers
|
||||
if prev_char.is_some() {
|
||||
numbers.push(SerialNumber {
|
||||
no: cur_no,
|
||||
start: (cur_no_row_start, line_no),
|
||||
end: (line.len() - 1, line_no),
|
||||
});
|
||||
}
|
||||
}
|
||||
(numbers, symbols)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
||||
const INPUT: &str = "467..114..
|
||||
...*......
|
||||
..35..633.
|
||||
......#...
|
||||
617*......
|
||||
.....+.58.
|
||||
..592.....
|
||||
......755.
|
||||
...$.*....
|
||||
.664.598..";
|
||||
|
||||
#[test]
|
||||
fn part2_works() {
|
||||
let result = part2(INPUT);
|
||||
assert_eq!(result, "467835".to_string());
|
||||
}
|
||||
}
|
||||
14
2023/day-4/Cargo.toml
Normal file
14
2023/day-4/Cargo.toml
Normal file
@@ -0,0 +1,14 @@
|
||||
[package]
|
||||
name = "day-4"
|
||||
version.workspace = true
|
||||
edition.workspace = true
|
||||
authors.workspace = true
|
||||
repository.workspace = true
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
nom.workspace = true
|
||||
itertools.workspace = true
|
||||
rstest = {workspace = true}
|
||||
rstest_reuse = {workspace = true}
|
||||
4
2023/day-4/src/lib.rs
Normal file
4
2023/day-4/src/lib.rs
Normal file
@@ -0,0 +1,4 @@
|
||||
pub mod part1;
|
||||
pub use crate::part1::*;
|
||||
pub mod part2;
|
||||
pub use crate::part2::*;
|
||||
12
2023/day-4/src/main.rs
Normal file
12
2023/day-4/src/main.rs
Normal file
@@ -0,0 +1,12 @@
|
||||
#![warn(clippy::all, clippy::pedantic)]
|
||||
|
||||
use day_4::part1;
|
||||
use day_4::part2;
|
||||
|
||||
fn main() {
|
||||
let input = include_str!("./input.txt");
|
||||
let part1_result = part1(input);
|
||||
println!("part 1: {part1_result}");
|
||||
let part2_result = part2(input);
|
||||
println!("part 2: {part2_result}");
|
||||
}
|
||||
106
2023/day-4/src/part1.rs
Normal file
106
2023/day-4/src/part1.rs
Normal file
@@ -0,0 +1,106 @@
|
||||
#![warn(clippy::all, clippy::pedantic)]
|
||||
|
||||
use nom::{
|
||||
bytes::complete::tag,
|
||||
character::complete,
|
||||
multi::{fold_many1, separated_list1},
|
||||
sequence::{preceded, separated_pair, tuple},
|
||||
IResult,
|
||||
};
|
||||
use std::collections::HashSet;
|
||||
|
||||
struct Card {
|
||||
pub _id: u8,
|
||||
pub game_numbers: HashSet<u8>,
|
||||
pub my_numbers: HashSet<u8>,
|
||||
}
|
||||
|
||||
impl Card {
|
||||
fn get_win_count(&self) -> usize {
|
||||
self.my_numbers.intersection(&self.game_numbers).count()
|
||||
}
|
||||
fn get_score(&self) -> Option<usize> {
|
||||
let count = self.get_win_count();
|
||||
if count == 0 {
|
||||
None
|
||||
} else {
|
||||
Some(2_usize.pow(u32::try_from(count).expect("shouldn't have a lot of cards") - 1))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// day 4 part 1 of aoc 2023
|
||||
///
|
||||
/// # Arguments
|
||||
/// - input the input for today's puzzle
|
||||
///
|
||||
/// # Panics
|
||||
/// panics whne it cannot parse the input OR when ever the number of game numbers is greater than
|
||||
/// usize
|
||||
#[must_use]
|
||||
pub fn part1(input: &str) -> String {
|
||||
let (_, cards) = parse_input(input).expect("there should be input");
|
||||
cards
|
||||
.iter()
|
||||
.filter_map(Card::get_score)
|
||||
.sum::<usize>()
|
||||
.to_string()
|
||||
}
|
||||
|
||||
fn parse_num_list(input: &str) -> IResult<&str, HashSet<u8>> {
|
||||
fold_many1(
|
||||
tuple((complete::u8, complete::space0)),
|
||||
HashSet::new,
|
||||
|mut acc, (x, _)| {
|
||||
acc.insert(x);
|
||||
acc
|
||||
},
|
||||
)(input)
|
||||
}
|
||||
|
||||
fn parse_numbers(input: &str) -> IResult<&str, (HashSet<u8>, HashSet<u8>)> {
|
||||
separated_pair(
|
||||
parse_num_list,
|
||||
tuple((tag("|"), complete::space1)),
|
||||
parse_num_list,
|
||||
)(input)
|
||||
}
|
||||
|
||||
fn parse_card(input: &str) -> IResult<&str, Card> {
|
||||
let (input, (id, (my_numbers, game_numbers))) = separated_pair(
|
||||
preceded(tuple((tag("Card"), complete::space1)), complete::u8),
|
||||
tuple((tag(":"), complete::space1)),
|
||||
parse_numbers,
|
||||
)(input)?;
|
||||
|
||||
Ok((
|
||||
input,
|
||||
Card {
|
||||
_id: id,
|
||||
game_numbers,
|
||||
my_numbers,
|
||||
},
|
||||
))
|
||||
}
|
||||
|
||||
fn parse_input(input: &str) -> IResult<&str, Vec<Card>> {
|
||||
separated_list1(complete::line_ending, parse_card)(input)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
||||
const INPUT: &str = "Card 1: 41 48 83 86 17 | 83 86 6 31 17 9 48 53
|
||||
Card 2: 13 32 20 16 61 | 61 30 68 82 17 32 24 19
|
||||
Card 3: 1 21 53 59 44 | 69 82 63 72 16 21 14 1
|
||||
Card 4: 41 92 73 84 69 | 59 84 76 51 58 5 54 83
|
||||
Card 5: 87 83 26 28 32 | 88 30 70 12 93 22 82 36
|
||||
Card 6: 31 18 13 56 72 | 74 77 10 23 35 67 36 11";
|
||||
|
||||
#[test]
|
||||
fn part1_works() {
|
||||
let result = part1(INPUT);
|
||||
assert_eq!(result, "13".to_string());
|
||||
}
|
||||
}
|
||||
121
2023/day-4/src/part2.rs
Normal file
121
2023/day-4/src/part2.rs
Normal file
@@ -0,0 +1,121 @@
|
||||
#![warn(clippy::all, clippy::pedantic)]
|
||||
|
||||
use nom::{
|
||||
bytes::complete::tag,
|
||||
character::complete,
|
||||
combinator::map,
|
||||
multi::{fold_many1, separated_list1},
|
||||
sequence::{preceded, separated_pair, tuple},
|
||||
IResult,
|
||||
};
|
||||
use std::collections::{BTreeMap, HashSet};
|
||||
|
||||
struct Card {
|
||||
pub id: usize,
|
||||
pub game_numbers: HashSet<u8>,
|
||||
pub my_numbers: HashSet<u8>,
|
||||
}
|
||||
impl Card {
|
||||
fn get_win_count(&self) -> usize {
|
||||
self.my_numbers.intersection(&self.game_numbers).count()
|
||||
}
|
||||
}
|
||||
|
||||
/// day 4 part 1 of aoc 2023
|
||||
///
|
||||
/// # Arguments
|
||||
/// - input the input for today's puzzle
|
||||
///
|
||||
/// # Panics
|
||||
/// panics whne it cannot parse the input OR when ever the number of game numbers is greater than
|
||||
/// usize
|
||||
#[must_use]
|
||||
pub fn part2(input: &str) -> String {
|
||||
let (_, cards) = parse_input(input).expect("there should be input");
|
||||
let mut cards_had = BTreeMap::new();
|
||||
for card in cards {
|
||||
if let Some(x) = cards_had.get_mut(&card.id) {
|
||||
*x += 1;
|
||||
} else {
|
||||
cards_had.insert(card.id, 1);
|
||||
}
|
||||
let next_id = card.id + 1;
|
||||
let last_winner = card.id + card.get_win_count();
|
||||
//println!("{} - {next_id} {last_winner}", card.id);
|
||||
if last_winner < next_id {
|
||||
continue;
|
||||
}
|
||||
let card_count = *cards_had.get(&card.id).expect("already should have cards");
|
||||
for id in next_id..=last_winner {
|
||||
if let Some(x) = cards_had.get_mut(&id) {
|
||||
*x += card_count;
|
||||
} else {
|
||||
cards_had.insert(id, card_count);
|
||||
}
|
||||
}
|
||||
}
|
||||
//println!("{cards_had:#?}");
|
||||
|
||||
cards_had.values().sum::<usize>().to_string()
|
||||
}
|
||||
|
||||
fn parse_num_list(input: &str) -> IResult<&str, HashSet<u8>> {
|
||||
fold_many1(
|
||||
tuple((complete::u8, complete::space0)),
|
||||
HashSet::new,
|
||||
|mut acc, (x, _)| {
|
||||
acc.insert(x);
|
||||
acc
|
||||
},
|
||||
)(input)
|
||||
}
|
||||
|
||||
fn parse_numbers(input: &str) -> IResult<&str, (HashSet<u8>, HashSet<u8>)> {
|
||||
separated_pair(
|
||||
parse_num_list,
|
||||
tuple((tag("|"), complete::space1)),
|
||||
parse_num_list,
|
||||
)(input)
|
||||
}
|
||||
|
||||
fn parse_card(input: &str) -> IResult<&str, Card> {
|
||||
let (input, (id, (my_numbers, game_numbers))) = separated_pair(
|
||||
preceded(
|
||||
tuple((tag("Card"), complete::space1)),
|
||||
map(complete::u8, usize::from),
|
||||
),
|
||||
tuple((tag(":"), complete::space1)),
|
||||
parse_numbers,
|
||||
)(input)?;
|
||||
|
||||
Ok((
|
||||
input,
|
||||
Card {
|
||||
id,
|
||||
game_numbers,
|
||||
my_numbers,
|
||||
},
|
||||
))
|
||||
}
|
||||
|
||||
fn parse_input(input: &str) -> IResult<&str, Vec<Card>> {
|
||||
separated_list1(complete::line_ending, parse_card)(input)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
||||
const INPUT: &str = "Card 1: 41 48 83 86 17 | 83 86 6 31 17 9 48 53
|
||||
Card 2: 13 32 20 16 61 | 61 30 68 82 17 32 24 19
|
||||
Card 3: 1 21 53 59 44 | 69 82 63 72 16 21 14 1
|
||||
Card 4: 41 92 73 84 69 | 59 84 76 51 58 5 54 83
|
||||
Card 5: 87 83 26 28 32 | 88 30 70 12 93 22 82 36
|
||||
Card 6: 31 18 13 56 72 | 74 77 10 23 35 67 36 11";
|
||||
|
||||
#[test]
|
||||
fn part2_works() {
|
||||
let result = part2(INPUT);
|
||||
assert_eq!(result, "30".to_string());
|
||||
}
|
||||
}
|
||||
12
2023/day-5/Cargo.toml
Normal file
12
2023/day-5/Cargo.toml
Normal file
@@ -0,0 +1,12 @@
|
||||
[package]
|
||||
name = "day-5"
|
||||
version.workspace = true
|
||||
edition.workspace = true
|
||||
authors.workspace = true
|
||||
repository.workspace = true
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
nom.workspace = true
|
||||
itertools.workspace = true
|
||||
4
2023/day-5/src/lib.rs
Normal file
4
2023/day-5/src/lib.rs
Normal file
@@ -0,0 +1,4 @@
|
||||
pub mod part1;
|
||||
pub use crate::part1::*;
|
||||
pub mod part2;
|
||||
pub use crate::part2::*;
|
||||
12
2023/day-5/src/main.rs
Normal file
12
2023/day-5/src/main.rs
Normal file
@@ -0,0 +1,12 @@
|
||||
#![warn(clippy::all, clippy::pedantic)]
|
||||
|
||||
use day_5::part1;
|
||||
use day_5::part2;
|
||||
|
||||
fn main() {
|
||||
let input = include_str!("./input.txt");
|
||||
let part1_result = part1(input);
|
||||
println!("part 1: {part1_result}");
|
||||
let part2_result = part2(input);
|
||||
println!("part 2: {part2_result}");
|
||||
}
|
||||
18
2023/day-5/src/part1.rs
Normal file
18
2023/day-5/src/part1.rs
Normal file
@@ -0,0 +1,18 @@
|
||||
#![warn(clippy::all, clippy::pedantic)]
|
||||
|
||||
#[must_use] pub fn part1(_input: &str) -> String {
|
||||
"Not Finished".to_string()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
||||
const INPUT: &str = "";
|
||||
|
||||
#[test]
|
||||
fn part1_works() {
|
||||
let result = part1(INPUT);
|
||||
assert_eq!(result, "Not Finished".to_string());
|
||||
}
|
||||
}
|
||||
18
2023/day-5/src/part2.rs
Normal file
18
2023/day-5/src/part2.rs
Normal file
@@ -0,0 +1,18 @@
|
||||
#![warn(clippy::all, clippy::pedantic)]
|
||||
|
||||
#[must_use] pub fn part2(_input: &str) -> String {
|
||||
"Not Finished".to_string()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
||||
const INPUT: &str = "";
|
||||
|
||||
#[test]
|
||||
fn part2_works() {
|
||||
let result = part2(INPUT);
|
||||
assert_eq!(result, "Not Finished".to_string());
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user