generated from janezicmatej/aoc-template
Compare commits
1 Commits
main
...
00000140ae
| Author | SHA1 | Date | |
|---|---|---|---|
|
00000140ae
|
188
Cargo.lock
generated
188
Cargo.lock
generated
@@ -17,18 +17,6 @@ version = "1.0.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
|
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "ahash"
|
|
||||||
version = "0.8.11"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011"
|
|
||||||
dependencies = [
|
|
||||||
"cfg-if",
|
|
||||||
"once_cell",
|
|
||||||
"version_check",
|
|
||||||
"zerocopy",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "aho-corasick"
|
name = "aho-corasick"
|
||||||
version = "1.1.3"
|
version = "1.1.3"
|
||||||
@@ -48,7 +36,6 @@ checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923"
|
|||||||
name = "aoc"
|
name = "aoc"
|
||||||
version = "48.0.0"
|
version = "48.0.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cached",
|
|
||||||
"hashbrown 0.15.2",
|
"hashbrown 0.15.2",
|
||||||
"itertools",
|
"itertools",
|
||||||
"num-integer",
|
"num-integer",
|
||||||
@@ -100,39 +87,6 @@ version = "1.3.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "dfb24e866b15a1af2a1b663f10c6b6b8f397a84aadb828f12e5b289ec23a3a3c"
|
checksum = "dfb24e866b15a1af2a1b663f10c6b6b8f397a84aadb828f12e5b289ec23a3a3c"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "cached"
|
|
||||||
version = "0.54.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "9718806c4a2fe9e8a56fd736f97b340dd10ed1be8ed733ed50449f351dc33cae"
|
|
||||||
dependencies = [
|
|
||||||
"ahash",
|
|
||||||
"cached_proc_macro",
|
|
||||||
"cached_proc_macro_types",
|
|
||||||
"hashbrown 0.14.5",
|
|
||||||
"once_cell",
|
|
||||||
"thiserror",
|
|
||||||
"web-time",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "cached_proc_macro"
|
|
||||||
version = "0.23.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "2f42a145ed2d10dce2191e1dcf30cfccfea9026660e143662ba5eec4017d5daa"
|
|
||||||
dependencies = [
|
|
||||||
"darling",
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"syn 2.0.90",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "cached_proc_macro_types"
|
|
||||||
version = "0.1.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "ade8366b8bd5ba243f0a58f036cc0ca8a2f069cff1a2351ef1cac6b083e16fc0"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cc"
|
name = "cc"
|
||||||
version = "1.0.78"
|
version = "1.0.78"
|
||||||
@@ -161,41 +115,6 @@ version = "0.8.3"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc"
|
checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "darling"
|
|
||||||
version = "0.20.10"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "6f63b86c8a8826a49b8c21f08a2d07338eec8d900540f8630dc76284be802989"
|
|
||||||
dependencies = [
|
|
||||||
"darling_core",
|
|
||||||
"darling_macro",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "darling_core"
|
|
||||||
version = "0.20.10"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "95133861a8032aaea082871032f5815eb9e98cef03fa916ab4500513994df9e5"
|
|
||||||
dependencies = [
|
|
||||||
"fnv",
|
|
||||||
"ident_case",
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"strsim",
|
|
||||||
"syn 2.0.90",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "darling_macro"
|
|
||||||
version = "0.20.10"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806"
|
|
||||||
dependencies = [
|
|
||||||
"darling_core",
|
|
||||||
"quote",
|
|
||||||
"syn 2.0.90",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dotenvy"
|
name = "dotenvy"
|
||||||
version = "0.15.6"
|
version = "0.15.6"
|
||||||
@@ -356,16 +275,6 @@ version = "0.12.3"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
|
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "hashbrown"
|
|
||||||
version = "0.14.5"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
|
|
||||||
dependencies = [
|
|
||||||
"ahash",
|
|
||||||
"allocator-api2",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hashbrown"
|
name = "hashbrown"
|
||||||
version = "0.15.2"
|
version = "0.15.2"
|
||||||
@@ -457,12 +366,6 @@ dependencies = [
|
|||||||
"tokio-native-tls",
|
"tokio-native-tls",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "ident_case"
|
|
||||||
version = "1.0.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "idna"
|
name = "idna"
|
||||||
version = "0.3.0"
|
version = "0.3.0"
|
||||||
@@ -632,9 +535,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "once_cell"
|
name = "once_cell"
|
||||||
version = "1.20.2"
|
version = "1.16.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775"
|
checksum = "86f0b0d4bf799edbc74508c1e8bf170ff5f41238e5f8225603ca7caaae2b7860"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "openssl"
|
name = "openssl"
|
||||||
@@ -659,7 +562,7 @@ checksum = "b501e44f11665960c7e7fcf062c7d96a14ade4aa98116c004b2e37b5be7d736c"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 1.0.107",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -713,18 +616,18 @@ checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro2"
|
name = "proc-macro2"
|
||||||
version = "1.0.92"
|
version = "1.0.69"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0"
|
checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"unicode-ident",
|
"unicode-ident",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "quote"
|
name = "quote"
|
||||||
version = "1.0.37"
|
version = "1.0.33"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af"
|
checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
]
|
]
|
||||||
@@ -926,12 +829,6 @@ dependencies = [
|
|||||||
"windows-sys 0.48.0",
|
"windows-sys 0.48.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "strsim"
|
|
||||||
version = "0.11.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "1.0.107"
|
version = "1.0.107"
|
||||||
@@ -943,17 +840,6 @@ dependencies = [
|
|||||||
"unicode-ident",
|
"unicode-ident",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "syn"
|
|
||||||
version = "2.0.90"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "919d3b74a5dd0ccd15aeb8f93e7006bd9e14c295087c9896a110f490752bcf31"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"unicode-ident",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "system-configuration"
|
name = "system-configuration"
|
||||||
version = "0.5.1"
|
version = "0.5.1"
|
||||||
@@ -989,26 +875,6 @@ dependencies = [
|
|||||||
"winapi",
|
"winapi",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "thiserror"
|
|
||||||
version = "1.0.69"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52"
|
|
||||||
dependencies = [
|
|
||||||
"thiserror-impl",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "thiserror-impl"
|
|
||||||
version = "1.0.69"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"syn 2.0.90",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tinyvec"
|
name = "tinyvec"
|
||||||
version = "1.6.0"
|
version = "1.6.0"
|
||||||
@@ -1134,12 +1000,6 @@ version = "0.2.15"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
|
checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "version_check"
|
|
||||||
version = "0.9.5"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "want"
|
name = "want"
|
||||||
version = "0.3.0"
|
version = "0.3.0"
|
||||||
@@ -1177,7 +1037,7 @@ dependencies = [
|
|||||||
"once_cell",
|
"once_cell",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 1.0.107",
|
"syn",
|
||||||
"wasm-bindgen-shared",
|
"wasm-bindgen-shared",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -1211,7 +1071,7 @@ checksum = "07bc0c051dc5f23e307b13285f9d75df86bfdf816c5721e573dec1f9b8aa193c"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 1.0.107",
|
"syn",
|
||||||
"wasm-bindgen-backend",
|
"wasm-bindgen-backend",
|
||||||
"wasm-bindgen-shared",
|
"wasm-bindgen-shared",
|
||||||
]
|
]
|
||||||
@@ -1232,16 +1092,6 @@ dependencies = [
|
|||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "web-time"
|
|
||||||
version = "1.1.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb"
|
|
||||||
dependencies = [
|
|
||||||
"js-sys",
|
|
||||||
"wasm-bindgen",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "winapi"
|
name = "winapi"
|
||||||
version = "0.3.9"
|
version = "0.3.9"
|
||||||
@@ -1382,23 +1232,3 @@ dependencies = [
|
|||||||
"cfg-if",
|
"cfg-if",
|
||||||
"windows-sys 0.48.0",
|
"windows-sys 0.48.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "zerocopy"
|
|
||||||
version = "0.7.35"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0"
|
|
||||||
dependencies = [
|
|
||||||
"zerocopy-derive",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "zerocopy-derive"
|
|
||||||
version = "0.7.35"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"syn 2.0.90",
|
|
||||||
]
|
|
||||||
|
|||||||
@@ -21,7 +21,6 @@ authors.workspace = true
|
|||||||
repository.workspace = true
|
repository.workspace = true
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
cached = "0.54.0"
|
|
||||||
hashbrown = "0.15.2"
|
hashbrown = "0.15.2"
|
||||||
itertools = "0.13.0"
|
itertools = "0.13.0"
|
||||||
num-integer = "0.1.46"
|
num-integer = "0.1.46"
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
125 17
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
RRRRIICCFF
|
|
||||||
RRRRIICCCF
|
|
||||||
VVRRRCCFFF
|
|
||||||
VVRCCCJFFF
|
|
||||||
VVVVCJJCFE
|
|
||||||
VVIVCCJJEE
|
|
||||||
VVIIICJJEE
|
|
||||||
MIIIIIJJEE
|
|
||||||
MIIISIJEEE
|
|
||||||
MMMISSJEEE
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
Button A: X+94, Y+34
|
|
||||||
Button B: X+22, Y+67
|
|
||||||
Prize: X=8400, Y=5400
|
|
||||||
|
|
||||||
Button A: X+26, Y+66
|
|
||||||
Button B: X+67, Y+21
|
|
||||||
Prize: X=12748, Y=12176
|
|
||||||
|
|
||||||
Button A: X+17, Y+86
|
|
||||||
Button B: X+84, Y+37
|
|
||||||
Prize: X=7870, Y=6450
|
|
||||||
|
|
||||||
Button A: X+69, Y+23
|
|
||||||
Button B: X+27, Y+71
|
|
||||||
Prize: X=18641, Y=10279
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
p=0,4 v=3,-3
|
|
||||||
p=6,3 v=-1,-3
|
|
||||||
p=10,3 v=-1,2
|
|
||||||
p=2,0 v=2,-1
|
|
||||||
p=0,0 v=1,3
|
|
||||||
p=3,0 v=-2,-2
|
|
||||||
p=7,6 v=-1,-3
|
|
||||||
p=3,0 v=-1,-2
|
|
||||||
p=9,3 v=2,3
|
|
||||||
p=7,3 v=-1,2
|
|
||||||
p=2,4 v=2,-3
|
|
||||||
p=9,5 v=-3,-3
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
##########
|
|
||||||
#..O..O.O#
|
|
||||||
#......O.#
|
|
||||||
#.OO..O.O#
|
|
||||||
#..O@..O.#
|
|
||||||
#O#..O...#
|
|
||||||
#O..O..O.#
|
|
||||||
#.OO.O.OO#
|
|
||||||
#....O...#
|
|
||||||
##########
|
|
||||||
|
|
||||||
<vv>^<v^>v>^vv^v>v<>v^v<v<^vv<<<^><<><>>v<vvv<>^v^>^<<<><<v<<<v^vv^v>^
|
|
||||||
vvv<<^>^v^^><<>>><>^<<><^vv^^<>vvv<>><^^v>^>vv<>v<<<<v<^v>^<^^>>>^<v<v
|
|
||||||
><>vv>v^v^<>><>>>><^^>vv>v<^^^>>v^v^<^^>v^^>v^<^v>v<>>v^v^<v>v^^<^^vv<
|
|
||||||
<<v<^>>^^^^>>>v^<>vvv^><v<<<>^^^vv^<vvv>^>v<^^^^v<>^>vvvv><>>v^<<^^^^^
|
|
||||||
^><^><>>><>^^<<^^v>>><^<v>^<vv>>v>>>^v><>^v><<<<v>>v<v<v>vvv>^<><<>^><
|
|
||||||
^>><>^v<><^vvv<^^<><v<<<<<><^v<<<><<<^^<v<^^^><^>>^<v^><<<^>>^v<v^v<v^
|
|
||||||
>^>>^v>vv>^<<^v<>><<><<v<<v><>v<^vv<<<>^^v^>^^>>><<^v>>v^v><^^>>^<>vv^
|
|
||||||
<><^^>^^^<><vvvvv^v<v<<>^v<v>v<<^><<><<><<<^^<<<^<<>><<><^^^>^^<>^>v<>
|
|
||||||
^^>vv<^v^v<vv>^<><v<^v>^^^>>>^^vvv^>vvv<>>>^<^>>>>>^<<^v>^vvv<>^<><<v>
|
|
||||||
v^^>>><<^^<>>^v^<v^vv<>v^<<>^<^v^v><^<<<><<^<v><v<>vv>>v><v^<vv<>v^<<^
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
#################
|
|
||||||
#...#...#...#..E#
|
|
||||||
#.#.#.#.#.#.#.#.#
|
|
||||||
#.#.#.#...#...#.#
|
|
||||||
#.#.#.#.###.#.#.#
|
|
||||||
#...#.#.#.....#.#
|
|
||||||
#.#.#.#.#.#####.#
|
|
||||||
#.#...#.#.#.....#
|
|
||||||
#.#.#####.#.###.#
|
|
||||||
#.#.#.......#...#
|
|
||||||
#.#.###.#####.###
|
|
||||||
#.#.#...#.....#.#
|
|
||||||
#.#.#.#####.###.#
|
|
||||||
#.#.#.........#.#
|
|
||||||
#.#.#.#########.#
|
|
||||||
#S#.............#
|
|
||||||
#################
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
5,4
|
|
||||||
4,2
|
|
||||||
4,5
|
|
||||||
3,0
|
|
||||||
2,1
|
|
||||||
6,3
|
|
||||||
2,4
|
|
||||||
1,5
|
|
||||||
0,6
|
|
||||||
3,3
|
|
||||||
2,6
|
|
||||||
5,1
|
|
||||||
1,2
|
|
||||||
5,5
|
|
||||||
2,5
|
|
||||||
6,5
|
|
||||||
1,4
|
|
||||||
0,4
|
|
||||||
6,4
|
|
||||||
1,1
|
|
||||||
6,1
|
|
||||||
1,0
|
|
||||||
0,5
|
|
||||||
1,6
|
|
||||||
2,0
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
r, wr, b, g, bwu, rb, gb, br
|
|
||||||
|
|
||||||
brwrr
|
|
||||||
bggr
|
|
||||||
gbbr
|
|
||||||
rrbgbr
|
|
||||||
ubwu
|
|
||||||
bwurrg
|
|
||||||
brgr
|
|
||||||
bbrgwb
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
###############
|
|
||||||
#...#...#.....#
|
|
||||||
#.#.#.#.#.###.#
|
|
||||||
#S#...#.#.#...#
|
|
||||||
#######.#.#.###
|
|
||||||
#######.#.#...#
|
|
||||||
#######.#.###.#
|
|
||||||
###..E#...#...#
|
|
||||||
###.#######.###
|
|
||||||
#...###...#...#
|
|
||||||
#.#####.#.###.#
|
|
||||||
#.#...#.#.#...#
|
|
||||||
#.#.#.#.#.#.###
|
|
||||||
#...#...#...###
|
|
||||||
###############
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
029A
|
|
||||||
980A
|
|
||||||
179A
|
|
||||||
456A
|
|
||||||
379A
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
1
|
|
||||||
2
|
|
||||||
3
|
|
||||||
2024
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
kh-tc
|
|
||||||
qp-kh
|
|
||||||
de-cg
|
|
||||||
ka-co
|
|
||||||
yn-aq
|
|
||||||
qp-ub
|
|
||||||
cg-tb
|
|
||||||
vc-aq
|
|
||||||
tb-ka
|
|
||||||
wh-tc
|
|
||||||
yn-cg
|
|
||||||
kh-ub
|
|
||||||
ta-co
|
|
||||||
de-co
|
|
||||||
tc-td
|
|
||||||
tb-wq
|
|
||||||
wh-td
|
|
||||||
ta-ka
|
|
||||||
td-qp
|
|
||||||
aq-cg
|
|
||||||
wq-ub
|
|
||||||
ub-vc
|
|
||||||
de-ta
|
|
||||||
wq-aq
|
|
||||||
wq-vc
|
|
||||||
wh-yn
|
|
||||||
ka-de
|
|
||||||
kh-ta
|
|
||||||
co-tc
|
|
||||||
wh-qp
|
|
||||||
tb-vc
|
|
||||||
td-yn
|
|
||||||
@@ -1,47 +0,0 @@
|
|||||||
x00: 1
|
|
||||||
x01: 0
|
|
||||||
x02: 1
|
|
||||||
x03: 1
|
|
||||||
x04: 0
|
|
||||||
y00: 1
|
|
||||||
y01: 1
|
|
||||||
y02: 1
|
|
||||||
y03: 1
|
|
||||||
y04: 1
|
|
||||||
|
|
||||||
ntg XOR fgs -> mjb
|
|
||||||
y02 OR x01 -> tnw
|
|
||||||
kwq OR kpj -> z05
|
|
||||||
x00 OR x03 -> fst
|
|
||||||
tgd XOR rvg -> z01
|
|
||||||
vdt OR tnw -> bfw
|
|
||||||
bfw AND frj -> z10
|
|
||||||
ffh OR nrd -> bqk
|
|
||||||
y00 AND y03 -> djm
|
|
||||||
y03 OR y00 -> psh
|
|
||||||
bqk OR frj -> z08
|
|
||||||
tnw OR fst -> frj
|
|
||||||
gnj AND tgd -> z11
|
|
||||||
bfw XOR mjb -> z00
|
|
||||||
x03 OR x00 -> vdt
|
|
||||||
gnj AND wpb -> z02
|
|
||||||
x04 AND y00 -> kjc
|
|
||||||
djm OR pbm -> qhw
|
|
||||||
nrd AND vdt -> hwm
|
|
||||||
kjc AND fst -> rvg
|
|
||||||
y04 OR y02 -> fgs
|
|
||||||
y01 AND x02 -> pbm
|
|
||||||
ntg OR kjc -> kwq
|
|
||||||
psh XOR fgs -> tgd
|
|
||||||
qhw XOR tgd -> z09
|
|
||||||
pbm OR djm -> kpj
|
|
||||||
x03 XOR y03 -> ffh
|
|
||||||
x00 XOR y04 -> ntg
|
|
||||||
bfw OR bqk -> z06
|
|
||||||
nrd XOR fgs -> wpb
|
|
||||||
frj XOR qhw -> z04
|
|
||||||
bqk OR frj -> z07
|
|
||||||
y03 OR x01 -> nrd
|
|
||||||
hwm AND bqk -> z03
|
|
||||||
tgd XOR rvg -> z12
|
|
||||||
tnw OR pbm -> gnj
|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
#####
|
|
||||||
.####
|
|
||||||
.####
|
|
||||||
.####
|
|
||||||
.#.#.
|
|
||||||
.#...
|
|
||||||
.....
|
|
||||||
|
|
||||||
#####
|
|
||||||
##.##
|
|
||||||
.#.##
|
|
||||||
...##
|
|
||||||
...#.
|
|
||||||
...#.
|
|
||||||
.....
|
|
||||||
|
|
||||||
.....
|
|
||||||
#....
|
|
||||||
#....
|
|
||||||
#...#
|
|
||||||
#.#.#
|
|
||||||
#.###
|
|
||||||
#####
|
|
||||||
|
|
||||||
.....
|
|
||||||
.....
|
|
||||||
#.#..
|
|
||||||
###..
|
|
||||||
###.#
|
|
||||||
###.#
|
|
||||||
#####
|
|
||||||
|
|
||||||
.....
|
|
||||||
.....
|
|
||||||
.....
|
|
||||||
#....
|
|
||||||
#.#..
|
|
||||||
#.#.#
|
|
||||||
#####
|
|
||||||
@@ -74,16 +74,10 @@ mod tests {
|
|||||||
use super::*;
|
use super::*;
|
||||||
#[test]
|
#[test]
|
||||||
fn test_part_one() {
|
fn test_part_one() {
|
||||||
assert_eq!(
|
assert_eq!(part_one(&aoc::template::read_file("examples", 10)), Some(36));
|
||||||
part_one(&aoc::template::read_file("examples", 10)),
|
|
||||||
Some(36)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
#[test]
|
#[test]
|
||||||
fn test_part_two() {
|
fn test_part_two() {
|
||||||
assert_eq!(
|
assert_eq!(part_two(&aoc::template::read_file("examples", 10)), Some(81));
|
||||||
part_two(&aoc::template::read_file("examples", 10)),
|
|
||||||
Some(81)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,72 +0,0 @@
|
|||||||
use std::mem::swap;
|
|
||||||
|
|
||||||
use hashbrown::HashMap;
|
|
||||||
use itertools::Itertools;
|
|
||||||
|
|
||||||
fn blink(map: &HashMap<usize, usize>, nmap: &mut HashMap<usize, usize>) {
|
|
||||||
for (&k, &v) in map.iter() {
|
|
||||||
match k {
|
|
||||||
0 => *nmap.entry(1).or_default() += v,
|
|
||||||
x if (x.ilog10() + 1) % 2 == 0 => {
|
|
||||||
let xlen = x.ilog10() + 1;
|
|
||||||
let xhalf = 10_usize.pow(xlen / 2);
|
|
||||||
|
|
||||||
*nmap.entry(x / xhalf).or_default() += v;
|
|
||||||
*nmap.entry(x % xhalf).or_default() += v;
|
|
||||||
}
|
|
||||||
x => *nmap.entry(x * 2024).or_default() += v,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn solve(input: &str, blinks: usize) -> usize {
|
|
||||||
let v = input
|
|
||||||
.split(" ")
|
|
||||||
.filter_map(|x| x.parse().ok())
|
|
||||||
.collect_vec();
|
|
||||||
|
|
||||||
let mut map = HashMap::<usize, usize>::new();
|
|
||||||
|
|
||||||
for vv in v {
|
|
||||||
*map.entry(vv).or_default() += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut nmap = HashMap::<usize, usize>::new();
|
|
||||||
|
|
||||||
for _ in 0..blinks {
|
|
||||||
blink(&map, &mut nmap);
|
|
||||||
map.clear();
|
|
||||||
swap(&mut map, &mut nmap);
|
|
||||||
}
|
|
||||||
|
|
||||||
map.values().sum()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn part_one(input: &str) -> Option<usize> {
|
|
||||||
solve(input, 25).into()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn part_two(input: &str) -> Option<usize> {
|
|
||||||
solve(input, 75).into()
|
|
||||||
}
|
|
||||||
|
|
||||||
aoc::solution!(11);
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use super::*;
|
|
||||||
#[test]
|
|
||||||
fn test_part_one() {
|
|
||||||
assert_eq!(
|
|
||||||
part_one(&aoc::template::read_file("examples", 11)),
|
|
||||||
Some(55312)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
#[test]
|
|
||||||
fn test_part_two() {
|
|
||||||
assert_eq!(
|
|
||||||
part_two(&aoc::template::read_file("examples", 11)),
|
|
||||||
Some(65601038650482)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
109
src/bin/12.rs
109
src/bin/12.rs
@@ -1,109 +0,0 @@
|
|||||||
use hashbrown::HashSet;
|
|
||||||
use itertools::Itertools;
|
|
||||||
|
|
||||||
fn count_sides(perim: &mut [(isize, isize)]) -> usize {
|
|
||||||
perim.sort();
|
|
||||||
|
|
||||||
let mut sides = 0;
|
|
||||||
|
|
||||||
let mut k = 0;
|
|
||||||
while k < perim.len() {
|
|
||||||
let (mut i, mut j) = perim[k];
|
|
||||||
|
|
||||||
while let Some((ni, nj)) = perim.get(k + 1).copied() {
|
|
||||||
if i != ni || nj - j != 3 {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
(i, j) = (ni, nj);
|
|
||||||
k += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
sides += 1;
|
|
||||||
k += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
sides
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn solve(input: &str) -> (usize, usize) {
|
|
||||||
let grid = input.lines().map(|x| x.chars().collect_vec()).collect_vec();
|
|
||||||
|
|
||||||
let mut price = 0;
|
|
||||||
let mut discounted = 0;
|
|
||||||
|
|
||||||
let mut stack = Vec::new();
|
|
||||||
let mut visited = HashSet::new();
|
|
||||||
|
|
||||||
let mut ver_sides = Vec::new();
|
|
||||||
let mut hor_sides = Vec::new();
|
|
||||||
|
|
||||||
for p in (0..grid.len()).flat_map(|x| (0..grid[x].len()).map(move |y| (x, y))) {
|
|
||||||
if visited.contains(&p) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
let matcher = grid[p.0][p.1];
|
|
||||||
|
|
||||||
let mut area = 0;
|
|
||||||
ver_sides.clear();
|
|
||||||
hor_sides.clear();
|
|
||||||
|
|
||||||
stack.push(p);
|
|
||||||
while let Some((i, j)) = stack.pop() {
|
|
||||||
if !visited.insert((i, j)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
area += 1;
|
|
||||||
|
|
||||||
for (di, dj) in [(0, 1), (1, 0), (-1, 0), (0, -1)] {
|
|
||||||
let ni = i.wrapping_add(di as usize);
|
|
||||||
let nj = j.wrapping_add(dj as usize);
|
|
||||||
|
|
||||||
let fi = i as isize * 3 + di;
|
|
||||||
let fj = j as isize * 3 + dj;
|
|
||||||
|
|
||||||
match grid.get(ni).and_then(|row| row.get(nj)) {
|
|
||||||
Some(m) if *m == matcher => stack.push((ni, nj)),
|
|
||||||
_ if dj == 0 => hor_sides.push((fi, fj)),
|
|
||||||
_ if dj != 0 => ver_sides.push((fj, fi)),
|
|
||||||
_ => unreachable!(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
price += area * (hor_sides.len() + ver_sides.len());
|
|
||||||
discounted += area * (count_sides(&mut hor_sides) + count_sides(&mut ver_sides));
|
|
||||||
}
|
|
||||||
|
|
||||||
(price, discounted)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn part_one(input: &str) -> Option<usize> {
|
|
||||||
solve(input).0.into()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn part_two(input: &str) -> Option<usize> {
|
|
||||||
solve(input).1.into()
|
|
||||||
}
|
|
||||||
|
|
||||||
aoc::solution!(12);
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use super::*;
|
|
||||||
#[test]
|
|
||||||
fn test_part_one() {
|
|
||||||
assert_eq!(
|
|
||||||
part_one(&aoc::template::read_file("examples", 12)),
|
|
||||||
Some(1930)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
#[test]
|
|
||||||
fn test_part_two() {
|
|
||||||
assert_eq!(
|
|
||||||
part_two(&aoc::template::read_file("examples", 12)),
|
|
||||||
Some(1206)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,79 +0,0 @@
|
|||||||
use regex::Regex;
|
|
||||||
|
|
||||||
fn parse_input(input: &str) -> Vec<[(isize, isize); 3]> {
|
|
||||||
let r = Regex::new(r".*X(?:=|\+)(\d*), Y(?:=|\+)(\d*)").unwrap();
|
|
||||||
|
|
||||||
let mut parsed = Vec::new();
|
|
||||||
|
|
||||||
for machine in input.split("\n\n") {
|
|
||||||
let mut p = [(0, 0); 3];
|
|
||||||
for (idx, line) in machine.lines().enumerate() {
|
|
||||||
let c = r.captures(line).unwrap();
|
|
||||||
let x: isize = c.get(1).unwrap().as_str().parse().unwrap();
|
|
||||||
let y: isize = c.get(2).unwrap().as_str().parse().unwrap();
|
|
||||||
|
|
||||||
p[idx] = (x, y);
|
|
||||||
}
|
|
||||||
parsed.push(p)
|
|
||||||
}
|
|
||||||
|
|
||||||
parsed
|
|
||||||
}
|
|
||||||
|
|
||||||
fn solve(m: ((isize, isize), (isize, isize)), v: (isize, isize)) -> Option<isize> {
|
|
||||||
let det = m.0 .0 * m.1 .1 - m.0 .1 * m.1 .0;
|
|
||||||
|
|
||||||
if det == 0 {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
let x = (v.0 * m.1 .1 - m.0 .1 * v.1) as f64 / det as f64;
|
|
||||||
let y = (m.0 .0 * v.1 - v.0 * m.1 .0) as f64 / det as f64;
|
|
||||||
|
|
||||||
if x.trunc() != x || y.trunc() != y {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
Some(x as isize * 3 + y as isize)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn part_one(input: &str) -> Option<isize> {
|
|
||||||
parse_input(input)
|
|
||||||
.into_iter()
|
|
||||||
.filter_map(|[(a1, b1), (a2, b2), t]| solve(((a1, a2), (b1, b2)), t))
|
|
||||||
.sum::<isize>()
|
|
||||||
.into()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn part_two(input: &str) -> Option<isize> {
|
|
||||||
let prize_add = 10_000_000_000_000;
|
|
||||||
|
|
||||||
parse_input(input)
|
|
||||||
.into_iter()
|
|
||||||
.filter_map(|[(a0, b0), (a1, b1), (t0, t1)]| {
|
|
||||||
solve(((a0, a1), (b0, b1)), (t0 + prize_add, t1 + prize_add))
|
|
||||||
})
|
|
||||||
.sum::<isize>()
|
|
||||||
.into()
|
|
||||||
}
|
|
||||||
|
|
||||||
aoc::solution!(13);
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use super::*;
|
|
||||||
#[test]
|
|
||||||
fn test_part_one() {
|
|
||||||
assert_eq!(
|
|
||||||
part_one(&aoc::template::read_file("examples", 13)),
|
|
||||||
Some(480)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
#[test]
|
|
||||||
fn test_part_two() {
|
|
||||||
assert_eq!(
|
|
||||||
part_two(&aoc::template::read_file("examples", 13)),
|
|
||||||
Some(875318608908)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
107
src/bin/14.rs
107
src/bin/14.rs
@@ -1,107 +0,0 @@
|
|||||||
use hashbrown::HashMap;
|
|
||||||
use num_integer::Integer;
|
|
||||||
use regex::Regex;
|
|
||||||
|
|
||||||
fn parse_input(input: &str) -> Vec<((isize, isize), (isize, isize))> {
|
|
||||||
let r = Regex::new(r"p=(\d+),(\d+) v=(-?\d+),(-?\d+)").unwrap();
|
|
||||||
|
|
||||||
let mut parsed = Vec::new();
|
|
||||||
|
|
||||||
for line in input.lines() {
|
|
||||||
let c = r.captures(line).unwrap();
|
|
||||||
let j: isize = c.get(1).unwrap().as_str().parse().unwrap();
|
|
||||||
let i: isize = c.get(2).unwrap().as_str().parse().unwrap();
|
|
||||||
let y: isize = c.get(3).unwrap().as_str().parse().unwrap();
|
|
||||||
let x: isize = c.get(4).unwrap().as_str().parse().unwrap();
|
|
||||||
|
|
||||||
parsed.push(((i, j), (x, y)));
|
|
||||||
}
|
|
||||||
|
|
||||||
parsed
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn part_one(input: &str) -> Option<usize> {
|
|
||||||
let parsed = parse_input(input);
|
|
||||||
let mut r = [0; 4];
|
|
||||||
|
|
||||||
let h = 103;
|
|
||||||
let w = 101;
|
|
||||||
|
|
||||||
for ((pi, pj), (vi, vj)) in parsed {
|
|
||||||
let ni = (pi + vi * 100).rem_euclid(h);
|
|
||||||
let nj = (pj + vj * 100).rem_euclid(w);
|
|
||||||
|
|
||||||
if ni < h / 2 && nj > w / 2 {
|
|
||||||
r[0] += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ni < h / 2 && nj < w / 2 {
|
|
||||||
r[1] += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ni > h / 2 && nj < w / 2 {
|
|
||||||
r[2] += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ni > h / 2 && nj > w / 2 {
|
|
||||||
r[3] += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
r.into_iter().product::<usize>().into()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn part_two(input: &str) -> Option<usize> {
|
|
||||||
let pv = parse_input(input);
|
|
||||||
|
|
||||||
let h = 103;
|
|
||||||
let w = 101;
|
|
||||||
|
|
||||||
let mut n = 1;
|
|
||||||
|
|
||||||
// hardcoded side lengths of the "easter egg"
|
|
||||||
let th = 33;
|
|
||||||
let tw = 31;
|
|
||||||
|
|
||||||
for ((pi, pj), (vi, vj)) in pv.iter().copied() {
|
|
||||||
let mut m = 1;
|
|
||||||
|
|
||||||
loop {
|
|
||||||
let ni = (pi + vi * m).rem_euclid(h);
|
|
||||||
let nj = (pj + vj * m).rem_euclid(w);
|
|
||||||
if (ni, nj) == (pi, pj) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
m += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
n = n.lcm(&m);
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut sh = HashMap::new();
|
|
||||||
let mut sw = HashMap::new();
|
|
||||||
|
|
||||||
for m in 0..n {
|
|
||||||
sh.clear();
|
|
||||||
sw.clear();
|
|
||||||
|
|
||||||
for ((pi, pj), (vi, vj)) in pv.iter().copied() {
|
|
||||||
let ni = (pi + vi * m).rem_euclid(h);
|
|
||||||
let nj = (pj + vj * m).rem_euclid(w);
|
|
||||||
|
|
||||||
*sw.entry(ni).or_default() += 1_usize;
|
|
||||||
*sh.entry(nj).or_default() += 1_usize;
|
|
||||||
}
|
|
||||||
|
|
||||||
let ch = sh.values().filter(|&&x: &&usize| x >= th).count();
|
|
||||||
let cw = sw.values().filter(|&&x: &&usize| x >= tw).count();
|
|
||||||
|
|
||||||
if ch >= 2 && cw >= 2 {
|
|
||||||
return Some(n as usize);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
None
|
|
||||||
}
|
|
||||||
|
|
||||||
aoc::solution!(14);
|
|
||||||
215
src/bin/15.rs
215
src/bin/15.rs
@@ -1,215 +0,0 @@
|
|||||||
use hashbrown::HashSet;
|
|
||||||
use itertools::Itertools;
|
|
||||||
|
|
||||||
struct ParsedInput {
|
|
||||||
map: Vec<Vec<char>>,
|
|
||||||
dirs: Vec<(isize, isize)>,
|
|
||||||
start: (usize, usize),
|
|
||||||
}
|
|
||||||
|
|
||||||
fn dir_mapper(c: char) -> (isize, isize) {
|
|
||||||
match c {
|
|
||||||
'>' => (0, 1),
|
|
||||||
'<' => (0, -1),
|
|
||||||
'v' => (1, 0),
|
|
||||||
'^' => (-1, 0),
|
|
||||||
_ => unreachable!("found dir {c}"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parse_input(input: &str, extend: bool) -> ParsedInput {
|
|
||||||
let (umap, uins) = input.split_once("\n\n").unwrap();
|
|
||||||
|
|
||||||
let mut map = Vec::new();
|
|
||||||
|
|
||||||
for line in umap.lines() {
|
|
||||||
let mut row: Vec<char> = line.chars().collect();
|
|
||||||
if extend {
|
|
||||||
row = line
|
|
||||||
.chars()
|
|
||||||
.flat_map(|x| {
|
|
||||||
let y = match x {
|
|
||||||
'#' => "##",
|
|
||||||
'O' => "[]",
|
|
||||||
'.' => "..",
|
|
||||||
'@' => "@.",
|
|
||||||
_ => unreachable!("found {x}"),
|
|
||||||
};
|
|
||||||
y.chars()
|
|
||||||
})
|
|
||||||
.collect()
|
|
||||||
};
|
|
||||||
|
|
||||||
map.push(row);
|
|
||||||
}
|
|
||||||
|
|
||||||
let dirs = uins
|
|
||||||
.lines()
|
|
||||||
.flat_map(|x| x.chars().map(dir_mapper))
|
|
||||||
.collect_vec();
|
|
||||||
|
|
||||||
let (si, sj, _) = map
|
|
||||||
.iter()
|
|
||||||
.enumerate()
|
|
||||||
.flat_map(|(i, x)| x.iter().copied().enumerate().map(move |(j, y)| (i, j, y)))
|
|
||||||
.find(|x| x.2 == '@')
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
ParsedInput {
|
|
||||||
map,
|
|
||||||
dirs,
|
|
||||||
start: (si, sj),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn boxes_gps(map: &[Vec<char>]) -> usize {
|
|
||||||
map.iter()
|
|
||||||
.enumerate()
|
|
||||||
.flat_map(|(i, x)| {
|
|
||||||
x.iter()
|
|
||||||
.enumerate()
|
|
||||||
.filter(|(_, y)| ['O', '['].contains(y))
|
|
||||||
.map(move |(j, _)| 100 * i + j)
|
|
||||||
})
|
|
||||||
.sum()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn part_one(input: &str) -> Option<usize> {
|
|
||||||
let ParsedInput {
|
|
||||||
mut map,
|
|
||||||
dirs,
|
|
||||||
start: (mut si, mut sj),
|
|
||||||
} = parse_input(input, false);
|
|
||||||
|
|
||||||
for (di, dj) in dirs.iter().copied() {
|
|
||||||
let mut box_count = 0;
|
|
||||||
|
|
||||||
loop {
|
|
||||||
if map[si][sj] == 'O' {
|
|
||||||
box_count += 1;
|
|
||||||
map[si][sj] = '.';
|
|
||||||
}
|
|
||||||
|
|
||||||
map[si][sj] = '.';
|
|
||||||
|
|
||||||
let ni = si.wrapping_add(di as usize);
|
|
||||||
let nj = sj.wrapping_add(dj as usize);
|
|
||||||
|
|
||||||
if map[ni][nj] == '#' {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
(si, sj) = (ni, nj);
|
|
||||||
|
|
||||||
if map[si][sj] == '.' {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let (di, dj) = (-di, -dj);
|
|
||||||
|
|
||||||
for _ in 0..box_count {
|
|
||||||
map[si][sj] = 'O';
|
|
||||||
si = si.wrapping_add(di as usize);
|
|
||||||
sj = sj.wrapping_add(dj as usize);
|
|
||||||
}
|
|
||||||
|
|
||||||
map[si][sj] = '@';
|
|
||||||
}
|
|
||||||
|
|
||||||
boxes_gps(&map).into()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn can_move_and_mark(
|
|
||||||
acc: &mut HashSet<(usize, usize, usize)>,
|
|
||||||
mark: usize,
|
|
||||||
map: &[Vec<char>],
|
|
||||||
loc: (usize, usize),
|
|
||||||
dir: (isize, isize),
|
|
||||||
) -> bool {
|
|
||||||
let (li, mut lj) = loc;
|
|
||||||
|
|
||||||
match map[li][lj] {
|
|
||||||
'.' => return true,
|
|
||||||
'#' => return false,
|
|
||||||
']' => lj -= 1,
|
|
||||||
_ => (),
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut cmm = |l, dir| can_move_and_mark(acc, mark + 1, map, l, dir);
|
|
||||||
|
|
||||||
let can_move = match dir {
|
|
||||||
(0, -1) => cmm((li, lj - 1), dir),
|
|
||||||
(0, 1) => cmm((li, lj + 2), dir),
|
|
||||||
(-1, 0) => cmm((li - 1, lj), dir) && cmm((li - 1, lj + 1), dir),
|
|
||||||
(1, 0) => cmm((li + 1, lj), dir) && cmm((li + 1, lj + 1), dir),
|
|
||||||
x => unreachable!("found dir {x:?}"),
|
|
||||||
};
|
|
||||||
|
|
||||||
if can_move {
|
|
||||||
acc.insert((li, lj, mark));
|
|
||||||
}
|
|
||||||
|
|
||||||
can_move
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn part_two(input: &str) -> Option<usize> {
|
|
||||||
let ParsedInput {
|
|
||||||
mut map,
|
|
||||||
dirs,
|
|
||||||
start: (mut si, mut sj),
|
|
||||||
} = parse_input(input, true);
|
|
||||||
|
|
||||||
let mut marker = HashSet::new();
|
|
||||||
let mut sorter = Vec::new();
|
|
||||||
|
|
||||||
for (di, dj) in dirs.iter().copied() {
|
|
||||||
marker.clear();
|
|
||||||
sorter.clear();
|
|
||||||
|
|
||||||
let ni = si.wrapping_add(di as usize);
|
|
||||||
let nj = sj.wrapping_add(dj as usize);
|
|
||||||
|
|
||||||
if can_move_and_mark(&mut marker, 0, &map, (ni, nj), (di, dj)) {
|
|
||||||
sorter.extend(marker.drain());
|
|
||||||
sorter.sort_by_key(|x| -(x.2 as isize));
|
|
||||||
|
|
||||||
for (mi, mj, _) in sorter.iter().copied() {
|
|
||||||
let nmi = mi.wrapping_add(di as usize);
|
|
||||||
let nmj = mj.wrapping_add(dj as usize);
|
|
||||||
|
|
||||||
map[mi][mj] = '.';
|
|
||||||
map[mi][mj + 1] = '.';
|
|
||||||
map[nmi][nmj] = '[';
|
|
||||||
map[nmi][nmj + 1] = ']';
|
|
||||||
}
|
|
||||||
|
|
||||||
map[si][sj] = '.';
|
|
||||||
(si, sj) = (ni, nj);
|
|
||||||
map[si][sj] = '@';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
boxes_gps(&map).into()
|
|
||||||
}
|
|
||||||
|
|
||||||
aoc::solution!(15);
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use super::*;
|
|
||||||
#[test]
|
|
||||||
fn test_part_one() {
|
|
||||||
assert_eq!(
|
|
||||||
part_one(&aoc::template::read_file("examples", 15)),
|
|
||||||
Some(10092)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
#[test]
|
|
||||||
fn test_part_two() {
|
|
||||||
assert_eq!(
|
|
||||||
part_two(&aoc::template::read_file("examples", 15)),
|
|
||||||
Some(9021)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
119
src/bin/16.rs
119
src/bin/16.rs
@@ -1,119 +0,0 @@
|
|||||||
use std::{cmp::Reverse, collections::BinaryHeap};
|
|
||||||
|
|
||||||
use aoc::grid_vec::{Direction, Grid, Point};
|
|
||||||
use hashbrown::{HashMap, HashSet};
|
|
||||||
|
|
||||||
fn parse_input(input: &str) -> (Grid, Point, Point) {
|
|
||||||
let mut grid: Grid = input.parse().unwrap();
|
|
||||||
let start = grid.find(b'S').unwrap();
|
|
||||||
let end = grid.find(b'E').unwrap();
|
|
||||||
|
|
||||||
grid[start] = b'.';
|
|
||||||
grid[end] = b'.';
|
|
||||||
|
|
||||||
(grid, start, end)
|
|
||||||
}
|
|
||||||
|
|
||||||
type Prev = HashMap<(Point, Direction), HashSet<(Point, Direction)>>;
|
|
||||||
type Visited = HashMap<(Point, Direction), usize>;
|
|
||||||
|
|
||||||
fn dijkstra(grid: &Grid, start: Point) -> (Visited, Prev) {
|
|
||||||
let mut prev: Prev = HashMap::new();
|
|
||||||
let mut visited: Visited = HashMap::new();
|
|
||||||
|
|
||||||
let mut bh = BinaryHeap::new();
|
|
||||||
bh.push(Reverse((0, start, Direction::E, start, Direction::E)));
|
|
||||||
|
|
||||||
while let Some(Reverse((len, loc, dir, ploc, pdir))) = bh.pop() {
|
|
||||||
let best = visited.entry((loc, dir)).or_insert(usize::MAX);
|
|
||||||
|
|
||||||
if len > *best {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
prev.entry((loc, dir)).or_default().insert((ploc, pdir));
|
|
||||||
|
|
||||||
*best = len;
|
|
||||||
|
|
||||||
let n = loc + dir;
|
|
||||||
|
|
||||||
if grid.get(&n).filter(|&&c| c == b'.').is_some() && !visited.contains_key(&(n, dir)) {
|
|
||||||
bh.push(Reverse((len + 1, n, dir, loc, dir)));
|
|
||||||
}
|
|
||||||
|
|
||||||
let rl = dir.rotate_left();
|
|
||||||
if !visited.contains_key(&(loc, rl)) {
|
|
||||||
bh.push(Reverse((len + 1000, loc, rl, loc, dir)));
|
|
||||||
}
|
|
||||||
|
|
||||||
let rr = dir.rotate_right();
|
|
||||||
if !visited.contains_key(&(loc, rr)) {
|
|
||||||
bh.push(Reverse((len + 1000, loc, rr, loc, dir)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
(visited, prev)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn part_one(input: &str) -> Option<usize> {
|
|
||||||
let (grid, start, end) = parse_input(input);
|
|
||||||
dijkstra(&grid, start)
|
|
||||||
.0
|
|
||||||
.into_iter()
|
|
||||||
.filter(|(k, _)| k.0 == end)
|
|
||||||
.map(|(_, v)| v)
|
|
||||||
.min()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn part_two(input: &str) -> Option<usize> {
|
|
||||||
let (grid, start, end) = parse_input(input);
|
|
||||||
|
|
||||||
let (visited, prev) = dijkstra(&grid, start);
|
|
||||||
|
|
||||||
let mut stack = Vec::new();
|
|
||||||
stack.push(
|
|
||||||
prev.keys()
|
|
||||||
.filter(|&&k| k.0 == end)
|
|
||||||
.min_by_key(|&k| visited.get(k))
|
|
||||||
.copied()
|
|
||||||
.unwrap(),
|
|
||||||
);
|
|
||||||
|
|
||||||
let mut visited = HashSet::new();
|
|
||||||
let mut seats = HashSet::new();
|
|
||||||
|
|
||||||
while let Some((loc, dir)) = stack.pop() {
|
|
||||||
if !visited.insert((loc, dir)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(prevs) = prev.get(&(loc, dir)) {
|
|
||||||
stack.extend(prevs);
|
|
||||||
}
|
|
||||||
|
|
||||||
seats.insert(loc);
|
|
||||||
}
|
|
||||||
|
|
||||||
seats.len().into()
|
|
||||||
}
|
|
||||||
|
|
||||||
aoc::solution!(16);
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use super::*;
|
|
||||||
#[test]
|
|
||||||
fn test_part_one() {
|
|
||||||
assert_eq!(
|
|
||||||
part_one(&aoc::template::read_file("examples", 16)),
|
|
||||||
Some(11048)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
#[test]
|
|
||||||
fn test_part_two() {
|
|
||||||
assert_eq!(
|
|
||||||
part_two(&aoc::template::read_file("examples", 16)),
|
|
||||||
Some(64)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,72 +0,0 @@
|
|||||||
use hashbrown::HashSet;
|
|
||||||
use itertools::Itertools;
|
|
||||||
|
|
||||||
fn parse_input(input: &str) -> (usize, Vec<usize>) {
|
|
||||||
let mut input_iter = input.lines();
|
|
||||||
|
|
||||||
let ua = input_iter.next().unwrap();
|
|
||||||
let uprogram = input_iter.last().unwrap();
|
|
||||||
|
|
||||||
let a = ua.strip_prefix("Register A: ").unwrap().parse().unwrap();
|
|
||||||
let program = uprogram
|
|
||||||
.strip_prefix("Program: ")
|
|
||||||
.unwrap()
|
|
||||||
.split(',')
|
|
||||||
.filter_map(|x| x.parse().ok())
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
(a, program)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn quick_exec(a: usize) -> usize {
|
|
||||||
// hardcoded for my input
|
|
||||||
// below operation was produced by reducing below steps
|
|
||||||
//
|
|
||||||
// B = A % 8
|
|
||||||
// B = B ^ 7
|
|
||||||
// C = A >> B
|
|
||||||
// B = B ^ 7
|
|
||||||
// A = A >> 3
|
|
||||||
// B = B ^ C
|
|
||||||
// out(B % 8)
|
|
||||||
// jmp(0)
|
|
||||||
//
|
|
||||||
// remaining mutation after returning is A >> 3
|
|
||||||
((a % 8) ^ (a >> ((a % 8) ^ 7))) % 8
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn part_one(input: &str) -> Option<String> {
|
|
||||||
let (mut a, _) = parse_input(input);
|
|
||||||
let mut v = vec![];
|
|
||||||
|
|
||||||
while a != 0 {
|
|
||||||
v.push(quick_exec(a));
|
|
||||||
a >>= 3;
|
|
||||||
}
|
|
||||||
|
|
||||||
v.iter().join(",").into()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn part_two(input: &str) -> Option<usize> {
|
|
||||||
let (_, program) = parse_input(input);
|
|
||||||
|
|
||||||
let mut n_candidates = HashSet::new();
|
|
||||||
let mut candidates = HashSet::new();
|
|
||||||
candidates.insert(0);
|
|
||||||
|
|
||||||
for n in program.iter().copied().rev() {
|
|
||||||
for candidate in candidates.iter() {
|
|
||||||
n_candidates.extend(
|
|
||||||
(0..8)
|
|
||||||
.map(|shift| (candidate << 3) + shift)
|
|
||||||
.filter(|&m| quick_exec(m) == n),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
candidates.clear();
|
|
||||||
candidates.extend(n_candidates.drain())
|
|
||||||
}
|
|
||||||
|
|
||||||
candidates.iter().min().copied()
|
|
||||||
}
|
|
||||||
|
|
||||||
aoc::solution!(17);
|
|
||||||
@@ -1,93 +0,0 @@
|
|||||||
use std::collections::VecDeque;
|
|
||||||
|
|
||||||
use hashbrown::{HashMap, HashSet};
|
|
||||||
use itertools::Itertools;
|
|
||||||
|
|
||||||
use aoc::{
|
|
||||||
grid_vec::{Direction, Point},
|
|
||||||
pnt,
|
|
||||||
};
|
|
||||||
|
|
||||||
fn parse_input(input: &str) -> Vec<Point> {
|
|
||||||
input
|
|
||||||
.lines()
|
|
||||||
.map(|x| {
|
|
||||||
x.split(',')
|
|
||||||
.filter_map(|y| y.parse().ok())
|
|
||||||
.collect_tuple()
|
|
||||||
.unwrap()
|
|
||||||
})
|
|
||||||
.map(|x: (usize, usize)| Point { i: x.1, j: x.0 })
|
|
||||||
.collect_vec()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn bfs(
|
|
||||||
visited: &mut HashMap<Point, usize>,
|
|
||||||
queue: &mut VecDeque<(Point, usize)>,
|
|
||||||
corruption: &HashSet<Point>,
|
|
||||||
end: Point,
|
|
||||||
) -> Option<usize> {
|
|
||||||
visited.clear();
|
|
||||||
queue.clear();
|
|
||||||
|
|
||||||
queue.push_back((pnt!(0, 0), 0));
|
|
||||||
|
|
||||||
while let Some((p, l)) = queue.pop_front() {
|
|
||||||
if visited.contains_key(&p) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
visited.insert(p, l);
|
|
||||||
|
|
||||||
if p == end {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
for d in Direction::CROSS {
|
|
||||||
let n = p + d;
|
|
||||||
|
|
||||||
let in_bounds = n.bounded_by(&end);
|
|
||||||
let not_visited = !visited.contains_key(&n);
|
|
||||||
let not_corrupted = !corruption.contains(&n);
|
|
||||||
|
|
||||||
if in_bounds && not_visited && not_corrupted {
|
|
||||||
queue.push_back((n, l + 1));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
visited.get(&end).copied()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn part_one(input: &str) -> Option<usize> {
|
|
||||||
let falling_bytes = parse_input(input);
|
|
||||||
|
|
||||||
let mut visited = HashMap::new();
|
|
||||||
let mut queue = VecDeque::new();
|
|
||||||
|
|
||||||
let end = pnt!(70, 70);
|
|
||||||
let corruption = HashSet::from_iter(falling_bytes.iter().copied().take(1024));
|
|
||||||
|
|
||||||
bfs(&mut visited, &mut queue, &corruption, end)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn part_two(input: &str) -> Option<String> {
|
|
||||||
let falling_bytes = parse_input(input);
|
|
||||||
|
|
||||||
let mut visited = HashMap::new();
|
|
||||||
let mut queue = VecDeque::new();
|
|
||||||
|
|
||||||
let end = pnt!(70, 70);
|
|
||||||
let mut corruption = HashSet::new();
|
|
||||||
let mut c = 0;
|
|
||||||
|
|
||||||
while bfs(&mut visited, &mut queue, &corruption, end).is_some() {
|
|
||||||
corruption.insert(falling_bytes[c]);
|
|
||||||
c += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
let fb = falling_bytes[c - 1];
|
|
||||||
|
|
||||||
Some(format!("{},{}", fb.j, fb.i))
|
|
||||||
}
|
|
||||||
|
|
||||||
aoc::solution!(18);
|
|
||||||
@@ -1,74 +0,0 @@
|
|||||||
use hashbrown::{HashMap, HashSet};
|
|
||||||
|
|
||||||
fn parse_input(input: &str) -> (HashSet<&str>, HashSet<&str>) {
|
|
||||||
let (upatterns, udesigns) = input.split_once("\n\n").unwrap();
|
|
||||||
|
|
||||||
let patterns = upatterns.split(", ").collect();
|
|
||||||
let designs = udesigns.split('\n').collect();
|
|
||||||
|
|
||||||
(patterns, designs)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn count_pattern_designs<'a>(
|
|
||||||
memo: &mut HashMap<&'a str, usize>,
|
|
||||||
patterns: &HashSet<&str>,
|
|
||||||
pattern: &'a str,
|
|
||||||
) -> usize {
|
|
||||||
if pattern.is_empty() {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if !memo.contains_key(pattern) {
|
|
||||||
let mut count = 0;
|
|
||||||
for p in patterns.iter() {
|
|
||||||
if let Some(stripped) = pattern.strip_prefix(p) {
|
|
||||||
count += count_pattern_designs(memo, patterns, stripped)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
memo.insert(pattern, count);
|
|
||||||
}
|
|
||||||
|
|
||||||
memo[pattern]
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn part_one(input: &str) -> Option<usize> {
|
|
||||||
let (patterns, designs) = parse_input(input);
|
|
||||||
|
|
||||||
let mut memo = HashMap::new();
|
|
||||||
|
|
||||||
for d in designs.iter().copied() {
|
|
||||||
count_pattern_designs(&mut memo, &patterns, d);
|
|
||||||
}
|
|
||||||
|
|
||||||
designs.into_iter().filter(|x| memo[x] > 0).count().into()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn part_two(input: &str) -> Option<usize> {
|
|
||||||
let (patterns, designs) = parse_input(input);
|
|
||||||
|
|
||||||
let mut memo = HashMap::new();
|
|
||||||
|
|
||||||
for d in designs.iter().copied() {
|
|
||||||
count_pattern_designs(&mut memo, &patterns, d);
|
|
||||||
}
|
|
||||||
|
|
||||||
designs.into_iter().map(|x| memo[x]).sum::<usize>().into()
|
|
||||||
}
|
|
||||||
|
|
||||||
aoc::solution!(19);
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use super::*;
|
|
||||||
#[test]
|
|
||||||
fn test_part_one() {
|
|
||||||
assert_eq!(part_one(&aoc::template::read_file("examples", 19)), Some(6));
|
|
||||||
}
|
|
||||||
#[test]
|
|
||||||
fn test_part_two() {
|
|
||||||
assert_eq!(
|
|
||||||
part_two(&aoc::template::read_file("examples", 19)),
|
|
||||||
Some(16)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
135
src/bin/20.rs
135
src/bin/20.rs
@@ -1,135 +0,0 @@
|
|||||||
use std::collections::VecDeque;
|
|
||||||
|
|
||||||
use aoc::grid_vec::{Direction, Grid, Point};
|
|
||||||
use hashbrown::HashMap;
|
|
||||||
|
|
||||||
fn parse_input(input: &str) -> (Grid, Point, Point) {
|
|
||||||
let mut grid: Grid = input.parse().unwrap();
|
|
||||||
let start = grid.find(b'S').unwrap();
|
|
||||||
let end = grid.find(b'E').unwrap();
|
|
||||||
|
|
||||||
grid[start] = b'.';
|
|
||||||
grid[end] = b'.';
|
|
||||||
|
|
||||||
(grid, start, end)
|
|
||||||
}
|
|
||||||
fn bfs(
|
|
||||||
grid: &Grid,
|
|
||||||
start: Point,
|
|
||||||
limit: Option<usize>,
|
|
||||||
cheat: bool,
|
|
||||||
visited: &mut HashMap<Point, usize>,
|
|
||||||
queue: &mut VecDeque<(Point, usize)>,
|
|
||||||
) {
|
|
||||||
visited.clear();
|
|
||||||
queue.clear();
|
|
||||||
|
|
||||||
queue.push_back((start, 0));
|
|
||||||
|
|
||||||
while let Some((p, l)) = queue.pop_front() {
|
|
||||||
if visited.contains_key(&p) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
visited.insert(p, l);
|
|
||||||
|
|
||||||
for d in Direction::CROSS {
|
|
||||||
let n = p + d;
|
|
||||||
|
|
||||||
let nv = grid.get(&n);
|
|
||||||
let uwnv = *nv.unwrap_or(&b'#');
|
|
||||||
let valid_neigh = (cheat && nv.is_some()) || uwnv == b'.';
|
|
||||||
let valid_length = l < limit.unwrap_or(usize::MAX);
|
|
||||||
let unvisited = !visited.contains_key(&n);
|
|
||||||
|
|
||||||
if valid_neigh && valid_length && unvisited {
|
|
||||||
queue.push_back((n, l + 1));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_cheat_neighbours_and_benchmark(
|
|
||||||
grid: &Grid,
|
|
||||||
start: Point,
|
|
||||||
cheat_limit: usize,
|
|
||||||
) -> HashMap<Point, Vec<(Point, usize)>> {
|
|
||||||
let mut map = HashMap::<Point, Vec<(Point, usize)>>::new();
|
|
||||||
|
|
||||||
let mut reuse_queue = VecDeque::new();
|
|
||||||
let mut reuse_visited = HashMap::new();
|
|
||||||
|
|
||||||
let mut valid_points = HashMap::new();
|
|
||||||
|
|
||||||
bfs(
|
|
||||||
grid,
|
|
||||||
start,
|
|
||||||
None,
|
|
||||||
false,
|
|
||||||
&mut valid_points,
|
|
||||||
&mut reuse_queue,
|
|
||||||
);
|
|
||||||
|
|
||||||
for (&s, _) in valid_points.iter() {
|
|
||||||
bfs(
|
|
||||||
grid,
|
|
||||||
s,
|
|
||||||
Some(cheat_limit),
|
|
||||||
true,
|
|
||||||
&mut reuse_visited,
|
|
||||||
&mut reuse_queue,
|
|
||||||
);
|
|
||||||
for (&point, &length) in reuse_visited.iter().filter(|(&p, _)| grid[p] == b'.') {
|
|
||||||
map.entry(s).or_default().push((point, length));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
map
|
|
||||||
}
|
|
||||||
|
|
||||||
fn cheated_bfs(
|
|
||||||
grid: &Grid,
|
|
||||||
start: Point,
|
|
||||||
end: Point,
|
|
||||||
cheat_limit: usize,
|
|
||||||
increase_limit: usize,
|
|
||||||
) -> usize {
|
|
||||||
let neighbours = get_cheat_neighbours_and_benchmark(grid, start, cheat_limit);
|
|
||||||
|
|
||||||
let mut reuse_queue = VecDeque::new();
|
|
||||||
|
|
||||||
let mut from_start = HashMap::new();
|
|
||||||
let mut from_end = HashMap::new();
|
|
||||||
|
|
||||||
bfs(grid, start, None, false, &mut from_start, &mut reuse_queue);
|
|
||||||
bfs(grid, end, None, false, &mut from_end, &mut reuse_queue);
|
|
||||||
|
|
||||||
let benchmark = from_start[&end];
|
|
||||||
|
|
||||||
let mut count = 0;
|
|
||||||
|
|
||||||
for node in from_start.keys() {
|
|
||||||
for (neigh, cheat_dist) in neighbours[node].iter() {
|
|
||||||
let start_dist = from_start[node];
|
|
||||||
let end_dist = from_end[neigh];
|
|
||||||
|
|
||||||
let dist = start_dist + cheat_dist + end_dist;
|
|
||||||
if dist < benchmark && dist.abs_diff(benchmark) >= increase_limit {
|
|
||||||
count += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
count
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn part_one(input: &str) -> Option<usize> {
|
|
||||||
let (grid, start, end) = parse_input(input);
|
|
||||||
cheated_bfs(&grid, start, end, 2, 100).into()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn part_two(input: &str) -> Option<usize> {
|
|
||||||
let (grid, start, end) = parse_input(input);
|
|
||||||
cheated_bfs(&grid, start, end, 20, 100).into()
|
|
||||||
}
|
|
||||||
|
|
||||||
aoc::solution!(20);
|
|
||||||
162
src/bin/21.rs
162
src/bin/21.rs
@@ -1,162 +0,0 @@
|
|||||||
use std::collections::VecDeque;
|
|
||||||
|
|
||||||
use hashbrown::HashMap;
|
|
||||||
use itertools::Itertools;
|
|
||||||
|
|
||||||
use cached::proc_macro::cached;
|
|
||||||
use cached::SizedCache;
|
|
||||||
|
|
||||||
#[rustfmt::skip]
|
|
||||||
#[allow(clippy::type_complexity)]
|
|
||||||
const NUMPAD: [(u8, [Option<(u8, u8)>; 4]); 11] = [
|
|
||||||
(b'0', [Some((b'2', b'^')), Some((b'A', b'>')), None, None]),
|
|
||||||
(b'1', [Some((b'2', b'>')), Some((b'4', b'^')), None, None]),
|
|
||||||
(b'2', [Some((b'0', b'v')), Some((b'1', b'<')), Some((b'3', b'>')), Some((b'5', b'^')),]),
|
|
||||||
(b'3', [Some((b'2', b'<')), Some((b'6', b'^')), Some((b'A', b'v')), None,]),
|
|
||||||
(b'4', [Some((b'1', b'v')), Some((b'5', b'>')), Some((b'7', b'^')), None,]),
|
|
||||||
(b'5', [Some((b'2', b'v')), Some((b'4', b'<')), Some((b'6', b'>')), Some((b'8', b'^')),]),
|
|
||||||
(b'6', [Some((b'3', b'v')), Some((b'5', b'<')), Some((b'9', b'^')), None,]),
|
|
||||||
(b'7', [Some((b'4', b'v')), Some((b'8', b'>')), None, None]),
|
|
||||||
(b'8', [Some((b'5', b'v')), Some((b'7', b'<')), Some((b'9', b'>')), None,]),
|
|
||||||
(b'9', [Some((b'6', b'v')), Some((b'8', b'<')), None, None]),
|
|
||||||
(b'A', [Some((b'0', b'<')), Some((b'3', b'^')), None, None]),
|
|
||||||
];
|
|
||||||
|
|
||||||
#[rustfmt::skip]
|
|
||||||
#[allow(clippy::type_complexity)]
|
|
||||||
const KEYPAD: [(u8, [Option<(u8, u8)>; 3]); 5] = [
|
|
||||||
(b'^', [Some((b'A', b'>')), Some((b'v', b'v')), None]),
|
|
||||||
(b'<', [Some((b'v', b'>')), None, None]),
|
|
||||||
(b'v', [Some((b'<', b'<')), Some((b'^', b'^')), Some((b'>', b'>'))]),
|
|
||||||
(b'>', [Some((b'v', b'<')), Some((b'A', b'^')), None]),
|
|
||||||
(b'A', [Some((b'^', b'<')), Some((b'>', b'v')), None]),
|
|
||||||
];
|
|
||||||
|
|
||||||
#[cached(
|
|
||||||
ty = "SizedCache<String, Vec<VecDeque<u8>>>",
|
|
||||||
create = "{ SizedCache::with_size(150) }",
|
|
||||||
convert = r#"{ format!("{}{s}{e}", graph.len()) }"#
|
|
||||||
)]
|
|
||||||
fn bfs(graph: &HashMap<u8, Vec<(u8, u8)>>, s: u8, e: u8) -> Vec<VecDeque<u8>> {
|
|
||||||
let mut res = Vec::new();
|
|
||||||
|
|
||||||
let mut queue = VecDeque::new();
|
|
||||||
let mut shortest = usize::MAX;
|
|
||||||
|
|
||||||
queue.push_back((s, VecDeque::new()));
|
|
||||||
|
|
||||||
while let Some((n, mut p)) = queue.pop_front() {
|
|
||||||
if n == e {
|
|
||||||
if shortest == usize::MAX {
|
|
||||||
shortest = p.len();
|
|
||||||
}
|
|
||||||
|
|
||||||
if p.len() == shortest {
|
|
||||||
p.push_back(b'A');
|
|
||||||
res.push(p);
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if p.len() >= shortest {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (nn, c) in graph[&n].iter().copied() {
|
|
||||||
let mut np = p.clone();
|
|
||||||
np.push_back(c);
|
|
||||||
|
|
||||||
queue.push_back((nn, np));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
res
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cached(
|
|
||||||
ty = "SizedCache<String, usize>",
|
|
||||||
create = "{ SizedCache::with_size(100000) }",
|
|
||||||
convert = r#"{ format!("{sequence:?}{level}{graph}") }"#
|
|
||||||
)]
|
|
||||||
fn dfs(
|
|
||||||
graphs: &[HashMap<u8, Vec<(u8, u8)>>],
|
|
||||||
graph: usize,
|
|
||||||
mut sequence: VecDeque<u8>,
|
|
||||||
level: usize,
|
|
||||||
) -> usize {
|
|
||||||
let graph = &graphs[graph];
|
|
||||||
sequence.push_front(b'A');
|
|
||||||
let mut res = 0;
|
|
||||||
|
|
||||||
for (n1, n2) in sequence.into_iter().tuple_windows() {
|
|
||||||
let paths = bfs(graph, n1, n2);
|
|
||||||
if level == 0 {
|
|
||||||
res += paths.into_iter().map(|p| p.len()).min().unwrap();
|
|
||||||
} else {
|
|
||||||
res += paths
|
|
||||||
.into_iter()
|
|
||||||
.map(|p| dfs(graphs, 1, p, level - 1))
|
|
||||||
.min()
|
|
||||||
.unwrap();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
res
|
|
||||||
}
|
|
||||||
|
|
||||||
fn build_graphs() -> [HashMap<u8, Vec<(u8, u8)>>; 2] {
|
|
||||||
let mut numpad = HashMap::new();
|
|
||||||
for (k, v) in NUMPAD.iter() {
|
|
||||||
numpad.insert(*k, v.iter().filter_map(|&x| x).collect_vec());
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut keypad = HashMap::new();
|
|
||||||
for (k, v) in KEYPAD.iter() {
|
|
||||||
keypad.insert(*k, v.iter().filter_map(|&x| x).collect_vec());
|
|
||||||
}
|
|
||||||
|
|
||||||
[numpad, keypad]
|
|
||||||
}
|
|
||||||
|
|
||||||
fn solve_chain(input: &str, level: usize) -> usize {
|
|
||||||
let graphs = build_graphs();
|
|
||||||
|
|
||||||
let mut res = 0;
|
|
||||||
for line in input.lines() {
|
|
||||||
let n: usize = line.strip_suffix("A").unwrap().parse().unwrap();
|
|
||||||
let sequence = VecDeque::from_iter(line.as_bytes().iter().copied());
|
|
||||||
let min_len = dfs(&graphs, 0, sequence, level);
|
|
||||||
res += min_len * n;
|
|
||||||
}
|
|
||||||
|
|
||||||
res
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn part_one(input: &str) -> Option<usize> {
|
|
||||||
Some(solve_chain(input, 2))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn part_two(input: &str) -> Option<usize> {
|
|
||||||
Some(solve_chain(input, 25))
|
|
||||||
}
|
|
||||||
|
|
||||||
aoc::solution!(21);
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use super::*;
|
|
||||||
#[test]
|
|
||||||
fn test_part_one() {
|
|
||||||
assert_eq!(
|
|
||||||
part_one(&aoc::template::read_file("examples", 21)),
|
|
||||||
Some(126384)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
#[test]
|
|
||||||
fn test_part_two() {
|
|
||||||
assert_eq!(
|
|
||||||
part_two(&aoc::template::read_file("examples", 21)),
|
|
||||||
Some(154115708116294)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,91 +0,0 @@
|
|||||||
use aoc::parsers::to_vec_map;
|
|
||||||
use hashbrown::{HashMap, HashSet};
|
|
||||||
|
|
||||||
fn pseudo_next(mut n: usize) -> usize {
|
|
||||||
n = ((n << 6) ^ n) % 16777216;
|
|
||||||
n = ((n >> 5) ^ n) % 16777216;
|
|
||||||
n = ((n << 11) ^ n) % 16777216;
|
|
||||||
n
|
|
||||||
}
|
|
||||||
|
|
||||||
struct MonkeyTrader {
|
|
||||||
numbers: [usize; 2001],
|
|
||||||
sequences: HashMap<[isize; 4], usize>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl MonkeyTrader {
|
|
||||||
fn new(seed: usize) -> Self {
|
|
||||||
let mut numbers = [0; 2001];
|
|
||||||
numbers[0] = seed;
|
|
||||||
|
|
||||||
let mut n = seed;
|
|
||||||
for num in numbers.iter_mut().skip(1) {
|
|
||||||
n = pseudo_next(n);
|
|
||||||
*num = n;
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut sequences = HashMap::new();
|
|
||||||
for i in 4..2001 {
|
|
||||||
let mut key = [0; 4];
|
|
||||||
for j in 1..=4 {
|
|
||||||
let d1 = numbers[i - 4 + j - 1] % 10;
|
|
||||||
let d2 = numbers[i - 4 + j] % 10;
|
|
||||||
let diff = d2 as isize - d1 as isize;
|
|
||||||
key[j - 1] = diff;
|
|
||||||
}
|
|
||||||
if sequences.contains_key(&key) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
*sequences.entry(key).or_default() = numbers[i] % 10;
|
|
||||||
}
|
|
||||||
|
|
||||||
MonkeyTrader { numbers, sequences }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn part_one(input: &str) -> Option<usize> {
|
|
||||||
to_vec_map(input, '\n', MonkeyTrader::new)
|
|
||||||
.into_iter()
|
|
||||||
.map(|x| x.numbers[2000])
|
|
||||||
.sum::<usize>()
|
|
||||||
.into()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn part_two(input: &str) -> Option<usize> {
|
|
||||||
let traders = to_vec_map(input, '\n', MonkeyTrader::new);
|
|
||||||
let key_union: HashSet<[isize; 4]> = traders
|
|
||||||
.iter()
|
|
||||||
.flat_map(|x| x.sequences.keys().cloned())
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
key_union
|
|
||||||
.into_iter()
|
|
||||||
.map(|k| {
|
|
||||||
traders
|
|
||||||
.iter()
|
|
||||||
.filter_map(|t| t.sequences.get(&k))
|
|
||||||
.sum::<usize>()
|
|
||||||
})
|
|
||||||
.max()
|
|
||||||
}
|
|
||||||
|
|
||||||
aoc::solution!(22);
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use super::*;
|
|
||||||
#[test]
|
|
||||||
fn test_part_one() {
|
|
||||||
assert_eq!(
|
|
||||||
part_one(&aoc::template::read_file("examples", 22)),
|
|
||||||
Some(37990510)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
#[test]
|
|
||||||
fn test_part_two() {
|
|
||||||
assert_eq!(
|
|
||||||
part_two(&aoc::template::read_file("examples", 22)),
|
|
||||||
Some(23)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,88 +0,0 @@
|
|||||||
use std::collections::BTreeSet;
|
|
||||||
|
|
||||||
use hashbrown::{HashMap, HashSet};
|
|
||||||
use itertools::Itertools;
|
|
||||||
|
|
||||||
fn parse_graph(input: &str) -> HashMap<&str, BTreeSet<&str>> {
|
|
||||||
let nodes: HashSet<_> = input.lines().filter_map(|x| x.split_once('-')).collect();
|
|
||||||
let mut graph: HashMap<_, BTreeSet<_>> = HashMap::new();
|
|
||||||
for (n1, n2) in nodes.iter().copied() {
|
|
||||||
graph.entry(n1).or_default().insert(n2);
|
|
||||||
graph.entry(n2).or_default().insert(n1);
|
|
||||||
}
|
|
||||||
|
|
||||||
graph
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn part_one(input: &str) -> Option<usize> {
|
|
||||||
let graph = parse_graph(input);
|
|
||||||
|
|
||||||
let mut triples = HashSet::new();
|
|
||||||
for (n1, neigh) in graph.iter() {
|
|
||||||
for n2 in neigh.iter().copied() {
|
|
||||||
for n3 in graph[n2].iter() {
|
|
||||||
if graph[n3].contains(n1) && n1.starts_with('t') {
|
|
||||||
let mut triple = [n1, n2, n3];
|
|
||||||
triple.sort();
|
|
||||||
triples.insert(triple);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
triples.len().into()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn part_two(input: &str) -> Option<String> {
|
|
||||||
let graph = parse_graph(input);
|
|
||||||
|
|
||||||
let p: BTreeSet<_> = graph.keys().copied().collect();
|
|
||||||
let r = HashSet::new();
|
|
||||||
let x = BTreeSet::new();
|
|
||||||
|
|
||||||
let mut maximals = HashSet::new();
|
|
||||||
|
|
||||||
let mut stack = Vec::new();
|
|
||||||
stack.push((r, p, x));
|
|
||||||
|
|
||||||
while let Some((r, mut p, mut x)) = stack.pop() {
|
|
||||||
if p.is_empty() && x.is_empty() {
|
|
||||||
let mut password = r.iter().copied().collect_vec();
|
|
||||||
password.sort();
|
|
||||||
|
|
||||||
maximals.insert(password.join(","));
|
|
||||||
}
|
|
||||||
|
|
||||||
while let Some(pp) = p.pop_last() {
|
|
||||||
let mut nr = r.clone();
|
|
||||||
nr.insert(pp);
|
|
||||||
|
|
||||||
let np = &p & &graph[pp];
|
|
||||||
let nx = &x & &graph[pp];
|
|
||||||
|
|
||||||
stack.push((nr, np, nx));
|
|
||||||
|
|
||||||
x.insert(pp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
maximals.into_iter().max_by_key(|x| x.len())
|
|
||||||
}
|
|
||||||
|
|
||||||
aoc::solution!(23);
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use super::*;
|
|
||||||
#[test]
|
|
||||||
fn test_part_one() {
|
|
||||||
assert_eq!(part_one(&aoc::template::read_file("examples", 23)), Some(7));
|
|
||||||
}
|
|
||||||
#[test]
|
|
||||||
fn test_part_two() {
|
|
||||||
assert_eq!(
|
|
||||||
part_two(&aoc::template::read_file("examples", 23)),
|
|
||||||
Some("co,de,ka,ta".to_string())
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
132
src/bin/24.rs
132
src/bin/24.rs
@@ -1,132 +0,0 @@
|
|||||||
use std::collections::VecDeque;
|
|
||||||
|
|
||||||
use hashbrown::HashMap;
|
|
||||||
use itertools::Itertools;
|
|
||||||
use regex::Regex;
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
|
||||||
enum Gate {
|
|
||||||
And,
|
|
||||||
Or,
|
|
||||||
XOr,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
struct LogicGate<'a> {
|
|
||||||
input_one: &'a str,
|
|
||||||
input_two: &'a str,
|
|
||||||
output: &'a str,
|
|
||||||
gate: Gate,
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parse_input(input: &str) -> (HashMap<&str, bool>, Vec<LogicGate>) {
|
|
||||||
let (uvals, uevals) = input.split_once("\n\n").unwrap();
|
|
||||||
let vals: HashMap<_, _> = uvals
|
|
||||||
.lines()
|
|
||||||
.map(|x| x.split_once(": ").unwrap())
|
|
||||||
.map(|(k, v)| (k, v == "1"))
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
let mut logic_gates = Vec::new();
|
|
||||||
let re = Regex::new(r#"((?:\w|\d){3}) (AND|XOR|OR) ((?:\w|\d){3}) -> ((?:\w|\d){3})"#).unwrap();
|
|
||||||
for capt in re.captures_iter(uevals) {
|
|
||||||
let input_one = capt.get(1).unwrap().as_str();
|
|
||||||
let gate = match capt.get(2).unwrap().as_str() {
|
|
||||||
"AND" => Gate::And,
|
|
||||||
"OR" => Gate::Or,
|
|
||||||
"XOR" => Gate::XOr,
|
|
||||||
_ => unreachable!(),
|
|
||||||
};
|
|
||||||
let input_two = capt.get(3).unwrap().as_str();
|
|
||||||
let output = capt.get(4).unwrap().as_str();
|
|
||||||
logic_gates.push(LogicGate {
|
|
||||||
input_one,
|
|
||||||
input_two,
|
|
||||||
output,
|
|
||||||
gate,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
(vals, logic_gates)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn part_one(input: &str) -> Option<usize> {
|
|
||||||
let (mut vals, logic_gates) = parse_input(input);
|
|
||||||
let mut queue = VecDeque::from(logic_gates);
|
|
||||||
|
|
||||||
while let Some(s) = queue.pop_front() {
|
|
||||||
if !vals.contains_key(s.input_one) || !vals.contains_key(s.input_two) {
|
|
||||||
queue.push_back(s);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
let v1 = vals[s.input_one];
|
|
||||||
let v2 = vals[s.input_two];
|
|
||||||
|
|
||||||
let o = match s.gate {
|
|
||||||
Gate::And => v1 & v2,
|
|
||||||
Gate::Or => v1 | v2,
|
|
||||||
Gate::XOr => v1 ^ v2,
|
|
||||||
};
|
|
||||||
|
|
||||||
vals.insert(s.output, o);
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut zs = vals
|
|
||||||
.into_iter()
|
|
||||||
.filter(|x| x.0.starts_with('z'))
|
|
||||||
.collect_vec();
|
|
||||||
zs.sort();
|
|
||||||
zs.into_iter()
|
|
||||||
.enumerate()
|
|
||||||
.filter(|x| x.1 .1)
|
|
||||||
.map(|(i, _)| 1 << i)
|
|
||||||
.sum::<usize>()
|
|
||||||
.into()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn part_two(_input: &str) -> Option<String> {
|
|
||||||
// Used graphviz for this part
|
|
||||||
// ```rs
|
|
||||||
// let (_, logic_gates) = parse_input(input);
|
|
||||||
// println!("digraph A {{");
|
|
||||||
// for (idx, lg) in logic_gates.iter().enumerate() {
|
|
||||||
// let LogicGate {
|
|
||||||
// input_one: i1,
|
|
||||||
// input_two: i2,
|
|
||||||
// output: o1,
|
|
||||||
// gate: g,
|
|
||||||
// } = lg;
|
|
||||||
// println!("{i1} -> {g:?}_{idx}");
|
|
||||||
// println!("{i2} -> {g:?}_{idx}");
|
|
||||||
// println!("{g:?}_{idx} -> {o1}");
|
|
||||||
// }
|
|
||||||
// println!("}}");
|
|
||||||
// ```
|
|
||||||
//
|
|
||||||
// and then pipe to dot
|
|
||||||
// ```bash
|
|
||||||
// ... | dot -Tsvg -Kneato > grpah.svg
|
|
||||||
// ```
|
|
||||||
//
|
|
||||||
// i looked for errors in the pattern and found below
|
|
||||||
// solution for my input
|
|
||||||
|
|
||||||
let mut res = ["fkp", "z06", "z11", "ngr", "z31", "mfm", "bpt", "krj"];
|
|
||||||
res.sort();
|
|
||||||
res.join(",").to_string().into()
|
|
||||||
}
|
|
||||||
|
|
||||||
aoc::solution!(24);
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use super::*;
|
|
||||||
#[test]
|
|
||||||
fn test_part_one() {
|
|
||||||
assert_eq!(
|
|
||||||
part_one(&aoc::template::read_file("examples", 24)),
|
|
||||||
Some(2024)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,57 +0,0 @@
|
|||||||
pub fn part_one(input: &str) -> Option<usize> {
|
|
||||||
let mut keys = Vec::new();
|
|
||||||
let mut locks = Vec::new();
|
|
||||||
|
|
||||||
for key_or_lock in input.split("\n\n") {
|
|
||||||
let lock = key_or_lock
|
|
||||||
.lines()
|
|
||||||
.next()
|
|
||||||
.unwrap()
|
|
||||||
.chars()
|
|
||||||
.all(|x| x == '#');
|
|
||||||
|
|
||||||
let mut columns = [0; 5];
|
|
||||||
for (idx, c) in key_or_lock.lines().flat_map(|x| x.chars().enumerate()) {
|
|
||||||
if c == '#' {
|
|
||||||
columns[idx] += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// remove top or bottom row from count
|
|
||||||
for c in columns.iter_mut() {
|
|
||||||
*c -= 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if lock {
|
|
||||||
locks.push(columns);
|
|
||||||
} else {
|
|
||||||
keys.push(columns);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut count = 0;
|
|
||||||
for k in keys.iter() {
|
|
||||||
for l in locks.iter() {
|
|
||||||
if k.iter().zip(l.iter()).all(|(k, l)| k + l <= 5) {
|
|
||||||
count += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
count.into()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn part_two(_input: &str) -> Option<String> {
|
|
||||||
"Happy christmas!".to_string().into()
|
|
||||||
}
|
|
||||||
|
|
||||||
aoc::solution!(25);
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use super::*;
|
|
||||||
#[test]
|
|
||||||
fn test_part_one() {
|
|
||||||
assert_eq!(part_one(&aoc::template::read_file("examples", 25)), Some(3));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,67 +0,0 @@
|
|||||||
use std::{fmt::Display, ops::Mul};
|
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy)]
|
|
||||||
pub struct Direction {
|
|
||||||
pub i: isize,
|
|
||||||
pub j: isize,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for Direction {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
write!(f, "({}, {})", self.i, self.j)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Mul<usize> for Direction {
|
|
||||||
type Output = Self;
|
|
||||||
fn mul(self, rhs: usize) -> Self::Output {
|
|
||||||
Self {
|
|
||||||
i: self.i * rhs as isize,
|
|
||||||
j: self.j * rhs as isize,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Direction {
|
|
||||||
pub const N: Self = Direction { i: -1, j: 0 };
|
|
||||||
pub const E: Self = Direction { i: 0, j: 1 };
|
|
||||||
pub const S: Self = Direction { i: 1, j: 0 };
|
|
||||||
pub const W: Self = Direction { i: 0, j: -1 };
|
|
||||||
|
|
||||||
pub const NE: Self = Direction { i: -1, j: 1 };
|
|
||||||
pub const NW: Self = Direction { i: -1, j: -1 };
|
|
||||||
pub const SE: Self = Direction { i: 1, j: 1 };
|
|
||||||
pub const SW: Self = Direction { i: 1, j: -1 };
|
|
||||||
|
|
||||||
pub const CROSS: [Self; 4] = [Self::N, Self::E, Self::S, Self::W];
|
|
||||||
#[rustfmt::skip]
|
|
||||||
pub const OMNI: [Self; 8] = [
|
|
||||||
Self::N, Self::E, Self::S, Self::W,
|
|
||||||
Self::NE, Self::NW, Self::SE, Self::SW
|
|
||||||
];
|
|
||||||
|
|
||||||
pub fn new(i: isize, j: isize) -> Self {
|
|
||||||
Self { i, j }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn rotate_left(self) -> Self {
|
|
||||||
Self {
|
|
||||||
i: -self.j,
|
|
||||||
j: self.i,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn rotate_right(self) -> Self {
|
|
||||||
Self {
|
|
||||||
i: self.j,
|
|
||||||
j: -self.i,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[macro_export]
|
|
||||||
macro_rules! dir {
|
|
||||||
($i:literal, $j:literal) => {
|
|
||||||
Direction { i: $i, j: $j }
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -1,96 +0,0 @@
|
|||||||
use std::{
|
|
||||||
fmt::Display,
|
|
||||||
ops::{Index, IndexMut},
|
|
||||||
str::FromStr,
|
|
||||||
};
|
|
||||||
|
|
||||||
use super::Point;
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct Grid {
|
|
||||||
grid: Vec<u8>,
|
|
||||||
width: usize,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl FromStr for Grid {
|
|
||||||
type Err = ();
|
|
||||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
|
||||||
let mut grid = Vec::with_capacity(s.len());
|
|
||||||
let mut width = None;
|
|
||||||
|
|
||||||
for line in s.lines() {
|
|
||||||
let w = line.len();
|
|
||||||
|
|
||||||
if width.is_none() {
|
|
||||||
width = Some(w);
|
|
||||||
}
|
|
||||||
|
|
||||||
if width.filter(|&x| x == w).is_none() {
|
|
||||||
panic!("all lines have to be of same length");
|
|
||||||
}
|
|
||||||
|
|
||||||
grid.extend(line.bytes());
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(Self {
|
|
||||||
grid,
|
|
||||||
width: width.unwrap(),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for Grid {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
for (idx, cell) in self.grid.iter().enumerate() {
|
|
||||||
write!(f, "{}", *cell as char)?;
|
|
||||||
if idx > 0 && (idx + 1) % self.width == 0 {
|
|
||||||
writeln!(f)?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Index<Point> for Grid {
|
|
||||||
type Output = u8;
|
|
||||||
fn index(&self, index: Point) -> &Self::Output {
|
|
||||||
&self.grid[index.i * self.width + index.j]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl IndexMut<Point> for Grid {
|
|
||||||
fn index_mut(&mut self, index: Point) -> &mut Self::Output {
|
|
||||||
&mut self.grid[index.i * self.width + index.j]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Grid {
|
|
||||||
pub fn find(&self, f: u8) -> Option<Point> {
|
|
||||||
let n = self
|
|
||||||
.grid
|
|
||||||
.iter()
|
|
||||||
.enumerate()
|
|
||||||
.find(|&(_, &x)| x == f)
|
|
||||||
.map(|x| x.0)?;
|
|
||||||
|
|
||||||
Some(Point::new(n / self.width, n % self.width))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get(&self, p: &Point) -> Option<&u8> {
|
|
||||||
if p.i >= self.grid.len() / self.width || p.j >= self.width {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
self.grid.get(p.i * self.width + p.j)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_mut(&mut self, p: &Point) -> Option<&mut u8> {
|
|
||||||
if p.i >= self.grid.len() / self.width || p.j >= self.width {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
self.grid.get_mut(p.i * self.width + p.j)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn size(&self) -> (usize, usize) {
|
|
||||||
(self.grid.len() / self.width, self.width)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
mod direction;
|
|
||||||
mod grid;
|
|
||||||
mod point;
|
|
||||||
|
|
||||||
pub use direction::Direction;
|
|
||||||
pub use grid::Grid;
|
|
||||||
pub use point::Point;
|
|
||||||
@@ -1,95 +0,0 @@
|
|||||||
use super::Direction;
|
|
||||||
|
|
||||||
use std::{
|
|
||||||
fmt::Display,
|
|
||||||
ops::{Add, AddAssign},
|
|
||||||
};
|
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy)]
|
|
||||||
pub struct Point {
|
|
||||||
pub i: usize,
|
|
||||||
pub j: usize,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for Point {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
write!(f, "({}, {})", self.i, self.j)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Add<Direction> for Point {
|
|
||||||
type Output = Self;
|
|
||||||
fn add(self, rhs: Direction) -> Self::Output {
|
|
||||||
Self {
|
|
||||||
i: self.i.wrapping_add(rhs.i as usize),
|
|
||||||
j: self.j.wrapping_add(rhs.j as usize),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl AddAssign<Direction> for Point {
|
|
||||||
fn add_assign(&mut self, rhs: Direction) {
|
|
||||||
*self = *self + rhs
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Point {
|
|
||||||
pub fn new(i: usize, j: usize) -> Self {
|
|
||||||
Self { i, j }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn n(self) -> Self {
|
|
||||||
Self {
|
|
||||||
i: self.i.wrapping_sub(1),
|
|
||||||
j: self.j,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn s(self) -> Self {
|
|
||||||
Self {
|
|
||||||
i: self.i.wrapping_add(1),
|
|
||||||
j: self.j,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn e(self) -> Self {
|
|
||||||
Self {
|
|
||||||
i: self.i,
|
|
||||||
j: self.j.wrapping_sub(1),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn w(self) -> Self {
|
|
||||||
Self {
|
|
||||||
i: self.i,
|
|
||||||
j: self.j.wrapping_add(1),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn ne(self) -> Self {
|
|
||||||
self.n().e()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn nw(self) -> Self {
|
|
||||||
self.n().w()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn se(self) -> Self {
|
|
||||||
self.s().e()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn sw(self) -> Self {
|
|
||||||
self.s().w()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn bounded_by(&self, other: &Self) -> bool {
|
|
||||||
self.i <= other.i && self.j <= other.j
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[macro_export]
|
|
||||||
macro_rules! pnt {
|
|
||||||
($i:expr, $j:expr) => {
|
|
||||||
Point { i: $i, j: $j }
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -1,5 +1,4 @@
|
|||||||
#![feature(pattern)]
|
#![feature(pattern)]
|
||||||
|
|
||||||
pub mod grid_vec;
|
|
||||||
pub mod parsers;
|
pub mod parsers;
|
||||||
pub mod template;
|
pub mod template;
|
||||||
|
|||||||
Reference in New Issue
Block a user