Compare commits
55 Commits
d84e3bff27
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| fc803d8a0f | |||
| 3a9379f877 | |||
| 241c417a77 | |||
| 4cbe831115 | |||
| a4c33ae3d2 | |||
| 48ad7e7a96 | |||
| caf307bf2d | |||
| 2792304040 | |||
| 42ead11aa0 | |||
| 8e1f42205c | |||
| c4ae25d579 | |||
| f472ace665 | |||
| a9b3c90a6c | |||
| 30ef81cfac | |||
| 861e31efee | |||
| d6c728ccfe | |||
| 8bc589488c | |||
| cfb3ae497e | |||
| b922b808fc | |||
| 5c4e9a9e9d | |||
| b480601ee8 | |||
| ef2340eaae | |||
|
|
b2a5da3222 | ||
|
|
9cbbf63eb1 | ||
|
|
c162fcb6d9 | ||
|
|
097cfac516 | ||
|
|
2b51e67fc6 | ||
|
|
6e438127ec | ||
|
|
21dfc7f630 | ||
|
|
719db128cf | ||
|
|
12f32ed232 | ||
|
|
768d328e87 | ||
|
|
31075fa449 | ||
|
|
d5aa1ddc74 | ||
|
|
8badd4a416 | ||
|
|
241ca8ea18 | ||
|
|
a35881fb01 | ||
|
|
0438a052d2 | ||
|
|
ba622fd408 | ||
|
|
cef96d55be | ||
|
|
3f2ff6e5a2 | ||
|
|
ac3a741f0d | ||
|
|
2bf8edf315 | ||
|
|
6f2e046080 | ||
|
|
6f9ca4dfb6 | ||
|
|
807bff7977 | ||
|
|
c1c761f2ba | ||
|
|
2fa6c40f33 | ||
|
|
54103e8fa6 | ||
|
|
fc328d82af | ||
|
|
267dfb8068 | ||
|
|
6d4bdccc6e | ||
|
|
4eb90ac047 | ||
|
|
2cf9933300 | ||
|
|
e5a3a1458a |
373
Cargo.lock
generated
373
Cargo.lock
generated
@@ -1,177 +1,368 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "aho-corasick"
|
||||
version = "0.6.9"
|
||||
version = "1.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0"
|
||||
dependencies = [
|
||||
"memchr 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "android-tzdata"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0"
|
||||
|
||||
[[package]]
|
||||
name = "android_system_properties"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "aoc_2018"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"itertools 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"regex 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"bmp",
|
||||
"chrono",
|
||||
"gcd",
|
||||
"itertools",
|
||||
"lazy_static",
|
||||
"regex",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bmp"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "69985ff4f58085ac696454692d0b646a66ad1f9cc9be294c91dc51bb5df511ae"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bumpalo"
|
||||
version = "3.14.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec"
|
||||
|
||||
[[package]]
|
||||
name = "byteorder"
|
||||
version = "1.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.0.83"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "0.1.6"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "chrono"
|
||||
version = "0.4.6"
|
||||
version = "0.4.31"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7f2c685bad3eb3d45a01354cedb7d5faa66194d1d58ba6e267a8de788f79db38"
|
||||
dependencies = [
|
||||
"num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"android-tzdata",
|
||||
"iana-time-zone",
|
||||
"js-sys",
|
||||
"num-traits",
|
||||
"wasm-bindgen",
|
||||
"windows-targets",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "core-foundation-sys"
|
||||
version = "0.8.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa"
|
||||
|
||||
[[package]]
|
||||
name = "either"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3be565ca5c557d7f59e7cfcf1844f9e3033650c929c6566f511e8005f205c1d0"
|
||||
|
||||
[[package]]
|
||||
name = "gcd"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0896cb73353671dbe2b17312c97b55b7032831d28c809c703bece4a392b1df3a"
|
||||
|
||||
[[package]]
|
||||
name = "iana-time-zone"
|
||||
version = "0.1.58"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8326b86b6cff230b97d0d312a6c40a60726df3332e721f72a1b035f451663b20"
|
||||
dependencies = [
|
||||
"android_system_properties",
|
||||
"core-foundation-sys",
|
||||
"iana-time-zone-haiku",
|
||||
"js-sys",
|
||||
"wasm-bindgen",
|
||||
"windows-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "iana-time-zone-haiku"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f"
|
||||
dependencies = [
|
||||
"cc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itertools"
|
||||
version = "0.7.11"
|
||||
version = "0.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57"
|
||||
dependencies = [
|
||||
"either 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"either",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "js-sys"
|
||||
version = "0.3.65"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "54c0c35952f67de54bb584e9fd912b3023117cbafc0a77d8f3dee1fb5f572fe8"
|
||||
dependencies = [
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "1.2.0"
|
||||
version = "1.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.44"
|
||||
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.1.1"
|
||||
version = "2.6.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-integer"
|
||||
version = "0.1.39"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167"
|
||||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
version = "0.2.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b3a5d7cc97d6d30d8b9bc8fa19bf45349ffe46241e8816f50f62f6d6aaabee1"
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.1.43"
|
||||
name = "once_cell"
|
||||
version = "1.18.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.69"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da"
|
||||
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 = "regex"
|
||||
version = "1.1.0"
|
||||
version = "1.10.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343"
|
||||
dependencies = [
|
||||
"aho-corasick 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"memchr 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"regex-syntax 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"utf8-ranges 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"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.6.4"
|
||||
version = "0.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.39"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "23e78b90f2fcf45d3e842032ce32e3f2d1545ba6636271dcbf24fa306d87be7a"
|
||||
dependencies = [
|
||||
"ucd-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thread_local"
|
||||
version = "0.3.6"
|
||||
name = "unicode-ident"
|
||||
version = "1.0.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen"
|
||||
version = "0.2.88"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7daec296f25a1bae309c0cd5c29c4b260e510e6d813c286b19eaadf409d40fce"
|
||||
dependencies = [
|
||||
"lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cfg-if",
|
||||
"wasm-bindgen-macro",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "time"
|
||||
version = "0.1.40"
|
||||
name = "wasm-bindgen-backend"
|
||||
version = "0.2.88"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e397f4664c0e4e428e8313a469aaa58310d302159845980fd23b0f22a847f217"
|
||||
dependencies = [
|
||||
"libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"redox_syscall 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"bumpalo",
|
||||
"log",
|
||||
"once_cell",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ucd-util"
|
||||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "utf8-ranges"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "version_check"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.3.6"
|
||||
name = "wasm-bindgen-macro"
|
||||
version = "0.2.88"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5961017b3b08ad5f3fe39f1e79877f8ee7c23c5e5fd5eb80de95abc41f1f16b2"
|
||||
dependencies = [
|
||||
"winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote",
|
||||
"wasm-bindgen-macro-support",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-i686-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
name = "wasm-bindgen-macro-support"
|
||||
version = "0.2.88"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c5353b8dab669f5e10f5bd76df26a9360c748f054f862ff5f3f8aae0c7fb3907"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"wasm-bindgen-backend",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-x86_64-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
name = "wasm-bindgen-shared"
|
||||
version = "0.2.88"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0d046c5d029ba91a1ed14da14dca44b68bf2f124cfbaf741c54151fdb3e0750b"
|
||||
|
||||
[metadata]
|
||||
"checksum aho-corasick 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)" = "1e9a933f4e58658d7b12defcf96dc5c720f20832deebe3e0a19efd3b6aaeeb9e"
|
||||
"checksum cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "082bb9b28e00d3c9d39cc03e64ce4cea0f1bb9b3fde493f0cbc008472d22bdf4"
|
||||
"checksum chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "45912881121cb26fad7c38c17ba7daa18764771836b34fab7d3fbd93ed633878"
|
||||
"checksum either 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3be565ca5c557d7f59e7cfcf1844f9e3033650c929c6566f511e8005f205c1d0"
|
||||
"checksum itertools 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)" = "0d47946d458e94a1b7bcabbf6521ea7c037062c81f534615abcad76e84d4970d"
|
||||
"checksum lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a374c89b9db55895453a74c1e38861d9deec0b01b405a82516e9d5de4820dea1"
|
||||
"checksum libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)" = "10923947f84a519a45c8fefb7dd1b3e8c08747993381adee176d7a82b4195311"
|
||||
"checksum memchr 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0a3eb002f0535929f1199681417029ebea04aadc0c7a4224b46be99c7f5d6a16"
|
||||
"checksum num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)" = "e83d528d2677f0518c570baf2b7abdcf0cd2d248860b68507bdcb3e91d4c0cea"
|
||||
"checksum num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0b3a5d7cc97d6d30d8b9bc8fa19bf45349ffe46241e8816f50f62f6d6aaabee1"
|
||||
"checksum redox_syscall 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)" = "679da7508e9a6390aeaf7fbd02a800fdc64b73fe2204dd2c8ae66d22d9d5ad5d"
|
||||
"checksum regex 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "37e7cbbd370869ce2e8dff25c7018702d10b21a20ef7135316f8daecd6c25b7f"
|
||||
"checksum regex-syntax 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "4e47a2ed29da7a9e1960e1639e7a982e6edc6d49be308a3b02daf511504a16d1"
|
||||
"checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b"
|
||||
"checksum time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "d825be0eb33fda1a7e68012d51e9c7f451dc1a69391e7fdc197060bb8c56667b"
|
||||
"checksum ucd-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "535c204ee4d8434478593480b8f86ab45ec9aae0e83c568ca81abf0fd0e88f86"
|
||||
"checksum utf8-ranges 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "796f7e48bef87609f7ade7e06495a87d5cd06c7866e6a5cbfceffc558a243737"
|
||||
"checksum version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd"
|
||||
"checksum winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "92c1eb33641e276cfa214a0522acad57be5c56b10cb348b3c5117db75f3ac4b0"
|
||||
"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||
"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
[[package]]
|
||||
name = "windows-core"
|
||||
version = "0.51.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f1f8cf84f35d2db49a46868f947758c7a1138116f7fac3bc844f43ade1292e64"
|
||||
dependencies = [
|
||||
"windows-targets",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-targets"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
|
||||
dependencies = [
|
||||
"windows_aarch64_gnullvm",
|
||||
"windows_aarch64_msvc",
|
||||
"windows_i686_gnu",
|
||||
"windows_i686_msvc",
|
||||
"windows_x86_64_gnu",
|
||||
"windows_x86_64_gnullvm",
|
||||
"windows_x86_64_msvc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_gnullvm"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
|
||||
|
||||
11
Cargo.toml
11
Cargo.toml
@@ -2,9 +2,12 @@
|
||||
name = "aoc_2018"
|
||||
version = "0.1.0"
|
||||
authors = ["Johannes <jschaef@mail.uni-paderborn.de>"]
|
||||
edition = "2018"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
regex = "1.1.0"
|
||||
chrono = "0.4.6"
|
||||
itertools = "0.7.11"
|
||||
regex = "1.10.2"
|
||||
chrono = "0.4.31"
|
||||
itertools = "0.11.0"
|
||||
gcd = "1.1.0"
|
||||
lazy_static = "1.4.0"
|
||||
bmp = "0.5.0"
|
||||
357
input/day10.txt
Normal file
357
input/day10.txt
Normal file
@@ -0,0 +1,357 @@
|
||||
position=< 50769, -40375> velocity=<-5, 4>
|
||||
position=< 40697, 10253> velocity=<-4, -1>
|
||||
position=<-40315, -50495> velocity=< 4, 5>
|
||||
position=<-40296, -20123> velocity=< 4, 2>
|
||||
position=< 50760, -50499> velocity=<-5, 5>
|
||||
position=< 30569, -40366> velocity=<-3, 4>
|
||||
position=< 10313, 30502> velocity=<-1, -3>
|
||||
position=<-50447, -10003> velocity=< 5, 1>
|
||||
position=<-20073, 20369> velocity=< 2, -2>
|
||||
position=<-40340, 30499> velocity=< 4, -3>
|
||||
position=< 40673, 10253> velocity=<-4, -1>
|
||||
position=<-50455, -50492> velocity=< 5, 5>
|
||||
position=<-50472, -10001> velocity=< 5, 1>
|
||||
position=< 10280, 30501> velocity=<-1, -3>
|
||||
position=< -9975, -9994> velocity=< 1, 1>
|
||||
position=< 10267, -30247> velocity=<-1, 3>
|
||||
position=<-30171, 20374> velocity=< 3, -2>
|
||||
position=< 40692, 30497> velocity=<-4, -3>
|
||||
position=< 50776, -40374> velocity=<-5, 4>
|
||||
position=< 10269, 20378> velocity=<-1, -2>
|
||||
position=< -9950, 50741> velocity=< 1, -5>
|
||||
position=< 30531, -40366> velocity=<-3, 4>
|
||||
position=< 30571, -50490> velocity=<-3, 5>
|
||||
position=< 40647, -40375> velocity=<-4, 4>
|
||||
position=< 30539, -30247> velocity=<-3, 3>
|
||||
position=< 30568, -30246> velocity=<-3, 3>
|
||||
position=<-20092, 20374> velocity=< 2, -2>
|
||||
position=< -9976, -9999> velocity=< 1, 1>
|
||||
position=< 10320, 20377> velocity=<-1, -2>
|
||||
position=< 30547, 10254> velocity=<-3, -1>
|
||||
position=< 40676, 40623> velocity=<-4, -4>
|
||||
position=< 50769, 40621> velocity=<-5, -4>
|
||||
position=<-30188, -40371> velocity=< 3, 4>
|
||||
position=< 30565, -20125> velocity=<-3, 2>
|
||||
position=<-40329, -20123> velocity=< 4, 2>
|
||||
position=<-20079, 30501> velocity=< 2, -3>
|
||||
position=< 50788, 30495> velocity=<-5, -3>
|
||||
position=<-20075, 10254> velocity=< 2, -1>
|
||||
position=< 20408, 20378> velocity=<-2, -2>
|
||||
position=<-20052, 30496> velocity=< 2, -3>
|
||||
position=<-40344, 40617> velocity=< 4, -4>
|
||||
position=< 10280, 50744> velocity=<-1, -5>
|
||||
position=< 40640, -9996> velocity=<-4, 1>
|
||||
position=< -9974, 50750> velocity=< 1, -5>
|
||||
position=<-20095, -30242> velocity=< 2, 3>
|
||||
position=< 20438, 30493> velocity=<-2, -3>
|
||||
position=< 50796, 10249> velocity=<-5, -1>
|
||||
position=< -9928, 40620> velocity=< 1, -4>
|
||||
position=< -9956, 10251> velocity=< 1, -1>
|
||||
position=< -9968, 30499> velocity=< 1, -3>
|
||||
position=< 50765, 50749> velocity=<-5, -5>
|
||||
position=< -9947, -40369> velocity=< 1, 4>
|
||||
position=< 40676, 20378> velocity=<-4, -2>
|
||||
position=<-30211, -20126> velocity=< 3, 2>
|
||||
position=<-50456, -9994> velocity=< 5, 1>
|
||||
position=<-20092, -30249> velocity=< 2, 3>
|
||||
position=< 10304, -30247> velocity=<-1, 3>
|
||||
position=< 50776, 50748> velocity=<-5, -5>
|
||||
position=<-40295, 10252> velocity=< 4, -1>
|
||||
position=< -9952, -20119> velocity=< 1, 2>
|
||||
position=< 50797, 40623> velocity=<-5, -4>
|
||||
position=<-40300, 20377> velocity=< 4, -2>
|
||||
position=< 10296, 30493> velocity=<-1, -3>
|
||||
position=< 50821, 30495> velocity=<-5, -3>
|
||||
position=<-40355, 30499> velocity=< 4, -3>
|
||||
position=<-20100, -9999> velocity=< 2, 1>
|
||||
position=< 50770, 50750> velocity=<-5, -5>
|
||||
position=<-40311, 50744> velocity=< 4, -5>
|
||||
position=<-30204, 10248> velocity=< 3, -1>
|
||||
position=<-50421, -50499> velocity=< 5, 5>
|
||||
position=< 30552, -10003> velocity=<-3, 1>
|
||||
position=< 30533, -40367> velocity=<-3, 4>
|
||||
position=< 30549, 40618> velocity=<-3, -4>
|
||||
position=< 50802, 50741> velocity=<-5, -5>
|
||||
position=< 50784, 30494> velocity=<-5, -3>
|
||||
position=< 40696, -20123> velocity=<-4, 2>
|
||||
position=<-30205, 30497> velocity=< 3, -3>
|
||||
position=< 10324, 40621> velocity=<-1, -4>
|
||||
position=< -9940, 40621> velocity=< 1, -4>
|
||||
position=<-30179, -50499> velocity=< 3, 5>
|
||||
position=< 20421, -40371> velocity=<-2, 4>
|
||||
position=< 50760, 20378> velocity=<-5, -2>
|
||||
position=< 30538, 50746> velocity=<-3, -5>
|
||||
position=< -9959, -20120> velocity=< 1, 2>
|
||||
position=< -9944, -50497> velocity=< 1, 5>
|
||||
position=< 20420, 40622> velocity=<-2, -4>
|
||||
position=<-40305, -30242> velocity=< 4, 3>
|
||||
position=< 20390, 30497> velocity=<-2, -3>
|
||||
position=<-50428, -40372> velocity=< 5, 4>
|
||||
position=<-50467, -9994> velocity=< 5, 1>
|
||||
position=<-20071, -50494> velocity=< 2, 5>
|
||||
position=< -9965, -9994> velocity=< 1, 1>
|
||||
position=< 40692, -40374> velocity=<-4, 4>
|
||||
position=< -9952, -20124> velocity=< 1, 2>
|
||||
position=< 20396, -10000> velocity=<-2, 1>
|
||||
position=< 20404, 10250> velocity=<-2, -1>
|
||||
position=< 10301, -50492> velocity=<-1, 5>
|
||||
position=< -9968, -9995> velocity=< 1, 1>
|
||||
position=< 20436, 30501> velocity=<-2, -3>
|
||||
position=<-20084, 40618> velocity=< 2, -4>
|
||||
position=< 20428, -20125> velocity=<-2, 2>
|
||||
position=< -9958, 50745> velocity=< 1, -5>
|
||||
position=< 40660, 40618> velocity=<-4, -4>
|
||||
position=< 30522, -40375> velocity=<-3, 4>
|
||||
position=<-40319, -40372> velocity=< 4, 4>
|
||||
position=< 40697, 40624> velocity=<-4, -4>
|
||||
position=<-40295, -30248> velocity=< 4, 3>
|
||||
position=<-40344, -30247> velocity=< 4, 3>
|
||||
position=< 30536, 10254> velocity=<-3, -1>
|
||||
position=< -9952, 10249> velocity=< 1, -1>
|
||||
position=< -9923, 50747> velocity=< 1, -5>
|
||||
position=< 40641, 10253> velocity=<-4, -1>
|
||||
position=<-50452, -50492> velocity=< 5, 5>
|
||||
position=<-40316, 20373> velocity=< 4, -2>
|
||||
position=< 10296, -50493> velocity=<-1, 5>
|
||||
position=< 10313, 40623> velocity=<-1, -4>
|
||||
position=< 50785, 50747> velocity=<-5, -5>
|
||||
position=< 20406, -20118> velocity=<-2, 2>
|
||||
position=<-40313, -20123> velocity=< 4, 2>
|
||||
position=< 50771, -20123> velocity=<-5, 2>
|
||||
position=<-20097, -10003> velocity=< 2, 1>
|
||||
position=< 50792, 30500> velocity=<-5, -3>
|
||||
position=< -9949, -9999> velocity=< 1, 1>
|
||||
position=< -9976, 40619> velocity=< 1, -4>
|
||||
position=<-30195, 50749> velocity=< 3, -5>
|
||||
position=<-50464, -30246> velocity=< 5, 3>
|
||||
position=< 30544, -30243> velocity=<-3, 3>
|
||||
position=< 50792, -40366> velocity=<-5, 4>
|
||||
position=<-20083, -10000> velocity=< 2, 1>
|
||||
position=< 50810, 50746> velocity=<-5, -5>
|
||||
position=<-30180, -20118> velocity=< 3, 2>
|
||||
position=< 20424, -50495> velocity=<-2, 5>
|
||||
position=< 20422, 50741> velocity=<-2, -5>
|
||||
position=<-40304, 40617> velocity=< 4, -4>
|
||||
position=<-30192, -40372> velocity=< 3, 4>
|
||||
position=< -9947, 10246> velocity=< 1, -1>
|
||||
position=<-50464, -9999> velocity=< 5, 1>
|
||||
position=<-40328, 10248> velocity=< 4, -1>
|
||||
position=< 50795, -9994> velocity=<-5, 1>
|
||||
position=<-20107, 40624> velocity=< 2, -4>
|
||||
position=<-50451, -40375> velocity=< 5, 4>
|
||||
position=<-40322, -20118> velocity=< 4, 2>
|
||||
position=< 40653, 10245> velocity=<-4, -1>
|
||||
position=< 20412, 30502> velocity=<-2, -3>
|
||||
position=< -9936, -30251> velocity=< 1, 3>
|
||||
position=< 40665, 20370> velocity=<-4, -2>
|
||||
position=< 10268, -40369> velocity=<-1, 4>
|
||||
position=< -9973, -30251> velocity=< 1, 3>
|
||||
position=< 50813, -40366> velocity=<-5, 4>
|
||||
position=< 50763, -40370> velocity=<-5, 4>
|
||||
position=< 10298, -40366> velocity=<-1, 4>
|
||||
position=<-20087, -20119> velocity=< 2, 2>
|
||||
position=< 10317, -30249> velocity=<-1, 3>
|
||||
position=< 30520, -30242> velocity=<-3, 3>
|
||||
position=<-20057, -20123> velocity=< 2, 2>
|
||||
position=< 10323, 20369> velocity=<-1, -2>
|
||||
position=<-50430, 50750> velocity=< 5, -5>
|
||||
position=< 10324, 40617> velocity=<-1, -4>
|
||||
position=<-50451, -40374> velocity=< 5, 4>
|
||||
position=<-20049, -30247> velocity=< 2, 3>
|
||||
position=<-40295, 10250> velocity=< 4, -1>
|
||||
position=<-40348, -50499> velocity=< 4, 5>
|
||||
position=< 50818, -30242> velocity=<-5, 3>
|
||||
position=< 50795, -10003> velocity=<-5, 1>
|
||||
position=< -9955, 50742> velocity=< 1, -5>
|
||||
position=< 10300, 50750> velocity=<-1, -5>
|
||||
position=<-40324, 40623> velocity=< 4, -4>
|
||||
position=<-40297, -50495> velocity=< 4, 5>
|
||||
position=< 50816, 10251> velocity=<-5, -1>
|
||||
position=<-30207, -20125> velocity=< 3, 2>
|
||||
position=<-50472, 50741> velocity=< 5, -5>
|
||||
position=<-30213, 10254> velocity=< 3, -1>
|
||||
position=<-50460, -50499> velocity=< 5, 5>
|
||||
position=<-20103, 20369> velocity=< 2, -2>
|
||||
position=< -9966, 10254> velocity=< 1, -1>
|
||||
position=< 50808, -50492> velocity=<-5, 5>
|
||||
position=<-30219, -20127> velocity=< 3, 2>
|
||||
position=<-40307, -20121> velocity=< 4, 2>
|
||||
position=< -9951, 40626> velocity=< 1, -4>
|
||||
position=< 40637, 40619> velocity=<-4, -4>
|
||||
position=< 30537, 40620> velocity=<-3, -4>
|
||||
position=<-50432, 50749> velocity=< 5, -5>
|
||||
position=< 30561, -50490> velocity=<-3, 5>
|
||||
position=< 50818, 10245> velocity=<-5, -1>
|
||||
position=< 10317, -40373> velocity=<-1, 4>
|
||||
position=<-30223, 10245> velocity=< 3, -1>
|
||||
position=< 30541, -30242> velocity=<-3, 3>
|
||||
position=< -9935, -30242> velocity=< 1, 3>
|
||||
position=< -9952, -40373> velocity=< 1, 4>
|
||||
position=<-30172, 20369> velocity=< 3, -2>
|
||||
position=<-40300, 50748> velocity=< 4, -5>
|
||||
position=<-50468, -50495> velocity=< 5, 5>
|
||||
position=<-50445, 10254> velocity=< 5, -1>
|
||||
position=<-40348, -20122> velocity=< 4, 2>
|
||||
position=< 10309, 20371> velocity=<-1, -2>
|
||||
position=< 50793, -30242> velocity=<-5, 3>
|
||||
position=< -9983, 30499> velocity=< 1, -3>
|
||||
position=< 30544, -50492> velocity=<-3, 5>
|
||||
position=< 20404, 20376> velocity=<-2, -2>
|
||||
position=< -9976, 30500> velocity=< 1, -3>
|
||||
position=< 40676, 10254> velocity=<-4, -1>
|
||||
position=< 40693, -9999> velocity=<-4, 1>
|
||||
position=<-50420, 40626> velocity=< 5, -4>
|
||||
position=<-50444, 20373> velocity=< 5, -2>
|
||||
position=< -9935, -10003> velocity=< 1, 1>
|
||||
position=<-20065, 50741> velocity=< 2, -5>
|
||||
position=<-40356, 30502> velocity=< 4, -3>
|
||||
position=<-20105, 20373> velocity=< 2, -2>
|
||||
position=< 20440, 10248> velocity=<-2, -1>
|
||||
position=<-20104, -40369> velocity=< 2, 4>
|
||||
position=<-30200, 40620> velocity=< 3, -4>
|
||||
position=< 40660, 20369> velocity=<-4, -2>
|
||||
position=< 50800, 30500> velocity=<-5, -3>
|
||||
position=<-50468, -50490> velocity=< 5, 5>
|
||||
position=< 40676, -9998> velocity=<-4, 1>
|
||||
position=<-30176, -50493> velocity=< 3, 5>
|
||||
position=< 40692, 40626> velocity=<-4, -4>
|
||||
position=<-30228, 50743> velocity=< 3, -5>
|
||||
position=< 30560, -9996> velocity=<-3, 1>
|
||||
position=< 30546, 30497> velocity=<-3, -3>
|
||||
position=<-30200, 20370> velocity=< 3, -2>
|
||||
position=< 30544, -9999> velocity=<-3, 1>
|
||||
position=<-20066, 40621> velocity=< 2, -4>
|
||||
position=<-50472, 50749> velocity=< 5, -5>
|
||||
position=<-50440, 50750> velocity=< 5, -5>
|
||||
position=<-30200, -50490> velocity=< 3, 5>
|
||||
position=< -9939, -50497> velocity=< 1, 5>
|
||||
position=< 20425, -20122> velocity=<-2, 2>
|
||||
position=< -9979, 30494> velocity=< 1, -3>
|
||||
position=<-30222, 30497> velocity=< 3, -3>
|
||||
position=< 30521, 20378> velocity=<-3, -2>
|
||||
position=<-40314, 40617> velocity=< 4, -4>
|
||||
position=< -9959, -50497> velocity=< 1, 5>
|
||||
position=< 20398, 40617> velocity=<-2, -4>
|
||||
position=< 50821, -10001> velocity=<-5, 1>
|
||||
position=< 50811, -9994> velocity=<-5, 1>
|
||||
position=<-50469, 10249> velocity=< 5, -1>
|
||||
position=<-40307, 30499> velocity=< 4, -3>
|
||||
position=<-20107, -9996> velocity=< 2, 1>
|
||||
position=< -9968, -50492> velocity=< 1, 5>
|
||||
position=< 40653, 30493> velocity=<-4, -3>
|
||||
position=<-40316, -50491> velocity=< 4, 5>
|
||||
position=< -9926, 20373> velocity=< 1, -2>
|
||||
position=< -9949, -30247> velocity=< 1, 3>
|
||||
position=< 40668, -30242> velocity=<-4, 3>
|
||||
position=<-40295, -40368> velocity=< 4, 4>
|
||||
position=<-20066, -40371> velocity=< 2, 4>
|
||||
position=<-20084, -40367> velocity=< 2, 4>
|
||||
position=<-20068, 10245> velocity=< 2, -1>
|
||||
position=< 20391, 30498> velocity=<-2, -3>
|
||||
position=< 10298, -20118> velocity=<-1, 2>
|
||||
position=<-50428, -40372> velocity=< 5, 4>
|
||||
position=< 50780, 40626> velocity=<-5, -4>
|
||||
position=< 40688, -40366> velocity=<-4, 4>
|
||||
position=< 10304, 30495> velocity=<-1, -3>
|
||||
position=< -9956, 40620> velocity=< 1, -4>
|
||||
position=<-40298, 30497> velocity=< 4, -3>
|
||||
position=<-40300, 20377> velocity=< 4, -2>
|
||||
position=< 10301, -10001> velocity=<-1, 1>
|
||||
position=< 10304, 10250> velocity=<-1, -1>
|
||||
position=<-20052, -40369> velocity=< 2, 4>
|
||||
position=< 20436, 40617> velocity=<-2, -4>
|
||||
position=<-30191, 20373> velocity=< 3, -2>
|
||||
position=< 50810, -30251> velocity=<-5, 3>
|
||||
position=< 40664, -20125> velocity=<-4, 2>
|
||||
position=< 20400, -30251> velocity=<-2, 3>
|
||||
position=<-50443, -9997> velocity=< 5, 1>
|
||||
position=< 40668, 50743> velocity=<-4, -5>
|
||||
position=<-50419, -50496> velocity=< 5, 5>
|
||||
position=< 50785, -40368> velocity=<-5, 4>
|
||||
position=<-30184, 50750> velocity=< 3, -5>
|
||||
position=< -9931, -40374> velocity=< 1, 4>
|
||||
position=<-50461, -10003> velocity=< 5, 1>
|
||||
position=< 30562, -40366> velocity=<-3, 4>
|
||||
position=< 30571, 10245> velocity=<-3, -1>
|
||||
position=< 20389, -30248> velocity=<-2, 3>
|
||||
position=<-40316, 50747> velocity=< 4, -5>
|
||||
position=<-20064, 40617> velocity=< 2, -4>
|
||||
position=< -9979, 40626> velocity=< 1, -4>
|
||||
position=<-40345, -20118> velocity=< 4, 2>
|
||||
position=< 10264, -50491> velocity=<-1, 5>
|
||||
position=< 20420, 50746> velocity=<-2, -5>
|
||||
position=<-50444, -10003> velocity=< 5, 1>
|
||||
position=< 30544, -50495> velocity=<-3, 5>
|
||||
position=< -9939, 10246> velocity=< 1, -1>
|
||||
position=<-20081, -9998> velocity=< 2, 1>
|
||||
position=< 20404, -9999> velocity=<-2, 1>
|
||||
position=< 10267, -30247> velocity=<-1, 3>
|
||||
position=< 20444, -50497> velocity=<-2, 5>
|
||||
position=< -9952, 10250> velocity=< 1, -1>
|
||||
position=< 10317, -50498> velocity=<-1, 5>
|
||||
position=<-20068, 10253> velocity=< 2, -1>
|
||||
position=< 30544, -30249> velocity=<-3, 3>
|
||||
position=< -9976, -10002> velocity=< 1, 1>
|
||||
position=< -9926, 50750> velocity=< 1, -5>
|
||||
position=<-20107, -20125> velocity=< 2, 2>
|
||||
position=< 50772, 20378> velocity=<-5, -2>
|
||||
position=< -9976, 40620> velocity=< 1, -4>
|
||||
position=<-40338, -20127> velocity=< 4, 2>
|
||||
position=<-20099, -9999> velocity=< 2, 1>
|
||||
position=< 40673, 30501> velocity=<-4, -3>
|
||||
position=< -9984, -30250> velocity=< 1, 3>
|
||||
position=< 40640, -20124> velocity=<-4, 2>
|
||||
position=< 10280, -40373> velocity=<-1, 4>
|
||||
position=< 20417, -20127> velocity=<-2, 2>
|
||||
position=<-20052, 10250> velocity=< 2, -1>
|
||||
position=< 10312, -50499> velocity=<-1, 5>
|
||||
position=< -9963, -20119> velocity=< 1, 2>
|
||||
position=< 30573, 40623> velocity=<-3, -4>
|
||||
position=< 10277, -20118> velocity=<-1, 2>
|
||||
position=< 50778, -50499> velocity=<-5, 5>
|
||||
position=< 10301, 10247> velocity=<-1, -1>
|
||||
position=< 50764, -50492> velocity=<-5, 5>
|
||||
position=< 30520, 50742> velocity=<-3, -5>
|
||||
position=<-40312, -9999> velocity=< 4, 1>
|
||||
position=<-50419, 40620> velocity=< 5, -4>
|
||||
position=< 10321, -20123> velocity=<-1, 2>
|
||||
position=<-40295, 10246> velocity=< 4, -1>
|
||||
position=<-20060, -20119> velocity=< 2, 2>
|
||||
position=<-50439, -10003> velocity=< 5, 1>
|
||||
position=<-40351, -30250> velocity=< 4, 3>
|
||||
position=< -9942, 50745> velocity=< 1, -5>
|
||||
position=< 10304, -40374> velocity=<-1, 4>
|
||||
position=<-50440, 10248> velocity=< 5, -1>
|
||||
position=< 20433, -30249> velocity=<-2, 3>
|
||||
position=<-40299, -20127> velocity=< 4, 2>
|
||||
position=< 20432, -20127> velocity=<-2, 2>
|
||||
position=< 10290, -9998> velocity=<-1, 1>
|
||||
position=<-30200, 20377> velocity=< 3, -2>
|
||||
position=< 20400, -40375> velocity=<-2, 4>
|
||||
position=< 30516, 10251> velocity=<-3, -1>
|
||||
position=< 30517, 20378> velocity=<-3, -2>
|
||||
position=< 20438, -9998> velocity=<-2, 1>
|
||||
position=< 40686, -50490> velocity=<-4, 5>
|
||||
position=< 40638, -50494> velocity=<-4, 5>
|
||||
position=<-50448, -9996> velocity=< 5, 1>
|
||||
position=<-40305, 40617> velocity=< 4, -4>
|
||||
position=<-40340, 30499> velocity=< 4, -3>
|
||||
position=<-50456, -50499> velocity=< 5, 5>
|
||||
position=< -9965, -20127> velocity=< 1, 2>
|
||||
position=<-30176, 40617> velocity=< 3, -4>
|
||||
position=< -9947, 30496> velocity=< 1, -3>
|
||||
position=<-50430, -9998> velocity=< 5, 1>
|
||||
position=< 30529, 50750> velocity=<-3, -5>
|
||||
position=< 50812, -20127> velocity=<-5, 2>
|
||||
position=< 10317, 10254> velocity=<-1, -1>
|
||||
position=< 40644, 30499> velocity=<-4, -3>
|
||||
position=<-20067, 40617> velocity=< 2, -4>
|
||||
position=<-40351, -50491> velocity=< 4, 5>
|
||||
position=< 50816, -30242> velocity=<-5, 3>
|
||||
position=< 20445, -20118> velocity=<-2, 2>
|
||||
position=< 20414, -30246> velocity=<-2, 3>
|
||||
position=< 20439, -10003> velocity=<-2, 1>
|
||||
position=<-50472, 50747> velocity=< 5, -5>
|
||||
position=<-20108, -30242> velocity=< 2, 3>
|
||||
position=<-30195, 10248> velocity=< 3, -1>
|
||||
position=<-30175, 10254> velocity=< 3, -1>
|
||||
34
input/day12.txt
Normal file
34
input/day12.txt
Normal file
@@ -0,0 +1,34 @@
|
||||
initial state: ..##.#######...##.###...#..#.#.#..#.##.#.##....####..........#..#.######..####.#.#..###.##..##..#..#
|
||||
|
||||
#..#. => .
|
||||
..#.. => .
|
||||
..#.# => #
|
||||
##.#. => .
|
||||
.#... => #
|
||||
#.... => .
|
||||
##### => #
|
||||
.#.## => .
|
||||
#.#.. => .
|
||||
#.### => #
|
||||
.##.. => #
|
||||
##... => .
|
||||
#...# => #
|
||||
####. => #
|
||||
#.#.# => .
|
||||
#..## => .
|
||||
.#### => .
|
||||
...## => .
|
||||
..### => #
|
||||
.#..# => .
|
||||
##..# => #
|
||||
.#.#. => .
|
||||
..##. => .
|
||||
###.. => .
|
||||
###.# => #
|
||||
#.##. => #
|
||||
..... => .
|
||||
.##.# => #
|
||||
....# => .
|
||||
##.## => #
|
||||
...#. => #
|
||||
.###. => .
|
||||
150
input/day13.txt
Normal file
150
input/day13.txt
Normal file
@@ -0,0 +1,150 @@
|
||||
/----------------------------------------------------------------------------------------------------------\
|
||||
| /---------------------\ /-----------------\ |
|
||||
/-------------------------\ | /--------+-----------\ | | /----------\ | |
|
||||
| /----------+----+----------------------------------------+--------+-----------+-------\ | | | | | |
|
||||
| /------------+\ | | /-------------------------+--------+-\ | | | | | | | |
|
||||
| | || | | /----+-------------------------+--------+-+---------+-------+-+-\ | | | | |
|
||||
| | /--++--------\| /+---------+----+-------------------------+--------+\| | /--+-+-+---------+-+----------+-\ | |
|
||||
| | | || /-++---++---------+----+-------------------------+--------+++---------+----+--+-+-+---------+-+----\ | | | |
|
||||
| | | ||/-----+-++---++---------+----+--\ /------------------+--------+++---------+----+--+-+-+---------+-+----+-----+-+--+\ |
|
||||
/---------+-+---------+--+++-----+-++---++---------+----+--+---+-\ | ||| | | | | | | | | | | || |
|
||||
| | | | ||| | || || | | | | | /---------\ | ||| | | | | | | | | | | || |
|
||||
| | | | ||| /+-++---++---------+----+--+---+-+--+---------+---+--------+++---------+----+--+-+\| | | | | | || |
|
||||
| | | | ||| || || || | /+--+---+-+--+---------+---+--------+++------\ | | | ||| | \----+-----/ | || |
|
||||
| /--+-+---------+--+++----++-++---++---------+---++--+---+-+--+-------\ | | ||| | | | | ||| | | | || |
|
||||
| /---+--+-+---------+--+++----++-++---++->\ | || | | | | | | | ||| | | | | ||| | | | || |
|
||||
| | | | | | ||| || || || | /---+---++--+---+-+--+-------+-+---+--------+++------+--+----+--+-+++---------+----\ | | || |
|
||||
| | | | | | ||| || || || | v |/--++--+-\ | | | | | | ||| /---+--+----+--+-+++--------\| | | | || |
|
||||
| | | | | |/-+++----++-++---++--+--+---++--++--+-+-+-+--+-------+\| | ||| | | | /--+--+-+++--------++----+-+-------+--++--\|
|
||||
| | | | | /---++-+++----++-++---++--+--+---++--++--+-+-+-+--+--\ ||| | ||| | | | | | | ||| || | | | || ||
|
||||
| | | | | | || ||| || || || | | || || | | | | | | ||| | ||| | /-+--+-+--+--+-+++--------++----+-+---\ | || ||
|
||||
| | | | | | || ||| || || || | | || ||/-+-+-+-+--+--+----+++---+--------+++--+-+-+--+-+--+--+-+++--------++-\ | | | | || ||
|
||||
| | | | | /--+---++-+++----++-++---++--+--+---++--+++-+-+-+-+\ | | /--+++---+--------+++--+-+-+>-+-+--+--+-+++--------++-+--+-+---+---+--++\ ||
|
||||
| | | | | | /+---++-+++----++\|| \+--+--+---++--+++-+-+-+-++-+--+-+--+++---+--------+/| | | | | | |/-+-+++--------++-+--+-+---+-\ | ||| ||
|
||||
| | | | | | || || ||| ||||| | | | || ||| | | | || | | | ||| | /------+-+--+-+-+--+-+--++-+-+++--------++-+\ | | | | | ||| ||
|
||||
| | | | | | || \+-+++----+++/| \--+--+---++--+++-+-+-+-++-+--+-+--+++---+-+------+-+--+-+-+--+-+--++-+-+++--------++-++-+-+-<-+-+-+--+++-+/
|
||||
| \---+--+-+--+-++----+-+++----+++-+-------/ | /++--+++-+-+-+-++-+--+\| ||| | | \-+--+-+-+--+-+--++-+-/|| || || | | | | | ||| |
|
||||
| | | | | || | ||| ||| | | ||| ||| | | | || | ||| ||| | | | /+-+-+--+-+--++-+--++--------++-++-+-+--\| | | ||| |
|
||||
| | | | | || | ||| ||| | | ||| ||| | | | || | ||| ||| | | | || | | | | || | || || || | | || | | ||| |
|
||||
| | | | | || | ||| ||| | | ||| ||| | | | || | ||| ||| | | /-----+-++-+-+--+-+--++-+--++------\ || || | | || | | ||| |
|
||||
| | | | |/++----+-+++----+++-+----------+--+++--+++-+-+-+-++-+--+++--+++---+-+--+-----+-++-+-+--+-+--++-+-\|| | || || | | || | | ||| |
|
||||
| |/-+-+--++++----+-+++----+++-+----------+--+++--+++-+-+-+\|| | ||| ||| | | | | ||/+-+--+-+--++-+-+++-----\| || ||/+-+--++-+-+--+++\|
|
||||
|/-----++-+-+--++++----+-+++----+++-+----------+--+++\ ||| | | |||| | ||| ||| | | | /---+-++++-+--+-+--++-+-+++-----++-++-++++-+--++-+-+--+++++\
|
||||
|| || | | ||||/---+-+++----+++-+----------+\ |||| ||| | | |||| | ||| ||| \-+--+-+---+-++++-+--/ | || | ||| || || |||| | || | | ||||||
|
||||
|| || | | ||||| | ||| |||/+----------++-++++-+++-+-+-++++-+--+++--+++-----+--+-+---+-++++-+----+--++-+-+++-----++-++-++++-+--++-+\| ||||||
|
||||
|| || | | ||||| | ||| ||||| || ^||| ||| | | |||| | ||| ||| | | | | |||| | | || | ||| || || |||| | || ||| ||||||
|
||||
|| || | | ||||| | ||| /+++++----------++-++++-+++-+-+-++++-+--+++--+++-----+--+-+---+-++++-+----+--++-+-+++-----++-++-++++\| || ||| ||||||
|
||||
|| || | |/-+++++---+-+++-\ |||||| || |||| ||| | | |||| | ||| ||| | | | | |||| | | || | ||| || || |||||| || ||| ||||||
|
||||
|| || | || ||||| | ||| | |||||| ||/++++-+++-+-+-++++-+-\||| ||| | | | /+-++++-+----+--++-+-+++-----++\|| |||||| || ||| ||||||
|
||||
|| || | || ||||| | ||| | |||||| /-----+++++++-+++-+-+-++++-+-++++--+++-----+--+-+--++-++++-+----+--++-+-+++-----+++++-++++++--++-+++\ ||||||
|
||||
|| || | || ||||| | ||| | |||||| | ||||||| ||| | | |||| | |||| ||| | | | || |||| | | || | ||| ||||| |||||| || |||| |||||v
|
||||
|| || | || ||||| | ||| | |||||| /+-----+++++++-+++-+-+-++++-+-++++--+++-----+--+-+--++-++++-+----+--++\| ||| ||||| |||||| || |||| ||||||
|
||||
|| || | || ||||| | ||| | |||||| || ||||||| ||| | | |||| | |||| ||| | | \--++-++++-+----+--++++-+++-----+++++-++++++--++-++++-+++++/
|
||||
|| || | || ||||| | ||| | |||||| || ||||||| |||/+-+-++++-+-++++--+++----\| | || |||| | | |||| ||| ||||| |||||| || |||| |||||
|
||||
|| || | || ||||| | ||| | |||||| || ||||||| \++++-+-++++-+-++++--+++----++--+----++-++++-/ | |||| ||| ||||| |||||| || |||| |||||
|
||||
|| || \-++-+++++---+-+++-+-+++++/ || /+++++++--++++-+-++++-+-++++--+++----++--+----++-++++------+--++++-+++-----+++++-++++++--++\|||| |||||
|
||||
|| || || ||||| | |||/+-+++++----++----++++++++--++++-+-++++-+-++++--+++--\ || |/---++-++++------+--++++-+++-----+++++-++++++-\||||||| |||||
|
||||
|| || || ||||| | ||\++-+++++----++----++++++++--+++/ | |||| |/++++--+++--+-++\ || /-++-++++------+--++++-+++----\||||| |||||| |||||||| |||||
|
||||
|| || || ||||| | || || ||||| || |||||||| ||| | |||| |||||| ||| | ||| || | || |||| | |||| ||| |||||\-++++++-++++++++-/||||
|
||||
|| /--++---++-+++++---+-++-++-+++++--\ || |||||||| ||| /+-++++-++++++--+++--+-+++-++-+-++-++++------+--++++-+++----+++++\ |||||| |||||||| ||||
|
||||
|| | || ||/+++++---+-++-++-+++++--+-++----++++++++--+++-++-++++-++++++--+++--+-+++-++-+-++\|||| | |||| ||| |||||| |||||| |||||||| ||||
|
||||
|| | || |||||||| | || || ||||| | || |||||||| ||| || |||| |||||| ||| | ||| || | |||||\+------+--++++-+++----+/|||| |||||| |||||||| ||||
|
||||
|| | || |||||||| |/++-++-+++++--+-++----++++++++--+++-++-++++-++++++--+++--+\||| || | ||||| | | |||| ||| | |||| |||||| |||||||| ||||
|
||||
|| | || |||||||| |||| || ||||| | || /++++++++--+++-++-++++-++++++--+++--+++++-++-+-+++++-+--\ | |||| ||| | |||| |||||| |||||||| ||||
|
||||
|| | || |||||||| ||^| || ||||| | || /-+++++++++--+++-++-++++-++++++--+++--+++++-++-+-+++++-+--+---+--++++-+++---\| |||| |||||| |||||||| ||||
|
||||
|| | || |||||||| |||| || ||||| | || | ||||||||| ||| || |||| |||||| ||| ||||| || | ||||| | | | |||| ||| || |||| |||||| |||||||| ||||
|
||||
|| | /++---++++++++---++++-++-+++++--+-++-+-+++++++++--+++-++-++++-++++++--+++-\||||| || | ||||| | | | |||| ||| || |||| |||||| |||||||| ||||
|
||||
|| | ||| |\++++++---++++-+/ ||||| | || | ||||||||| ||| || |||| |||||| ||| |||||| ||/+-+++++-+--+---+--++++-+++---++\|||| |||||| |||||||| ||||
|
||||
|| /+-+++---+-++++++---++++-+--+++++--+-++-+-+++++++++--+++-++-++++-++++++--+++-++++++-++++-+++++-+--+---+\ |||| ||| ||||||| |||||| |||||||| ||||
|
||||
|| || |||/--+-++++++---++++-+--+++++--+-++-+-+++++++++--+++-++-++++-++++++--+++-++++++-++++\||||| | | || |||| ||| ||||||| |||||| |||||||| ||||
|
||||
|| || |||| | |||||| |||| | ||||| | || | ||||||||| ||| || |||| |||||| ||| |||||| |||||||||| | | \+-++++-+++---+++++++-++++++-++++++++--+++/
|
||||
|| || |||| | |||||| |||| | ||||| | || | ||||||||| ||| || |||| |||||| ||| |||||| |||||||||| | | | |||| ||| ||||||| |||||| |||||||| |||
|
||||
|| || |||| | |||||| |||| | ||||| | || | ||||||||| \++-++-++++-++++++--+++-++++++-++++++/||| | | | |||| ||| |||||||/++++++-++++++++--+++-\
|
||||
|| || |||| | |||||| |||| | ||||| | |\-+-+++++++++---++-++-++++-++++++--+++-++++++-++++++-+++-+--+----+-++++-+++->-++++++++++++++-+++++++/ ||| |
|
||||
|| || |||| | |||||\---++++-+--+++++--+-+--+-+++/||||| || ||/++++-++++++-\||| |||||| |||||| ||| | | | |||| ||| |||||||||||||| ||||||| ||| |
|
||||
|| || |||| | |||||/---++++-+--+++++--+-+-\| ||\-+++++---++-+++++++-++++++-++++-++++++-++++++-+++-+--+----+-++++-+++---+++++++++++/|| ||||||| ||| |
|
||||
|| || |\++--+-++++++---++++-+--+++++--+-+-++-++--+++++---++-+++++++<++++++-+/|| |||||| \+++++-+++-+--+----+-++++-+++---+++/||||||\-++-+++++++---++/ |
|
||||
|| || | || | |||||| |||| | ||||| | | || || ||||| || ||||||| |\++++-+-++-+++++/ ||||| ||| | | | |||| ||| ||| |||||| || ||||||| || |
|
||||
|| || | || | |||||| /++++-+--+++++--+-+-++-++\ ||||| || ||||||| |/++++-+-++-+++++---+++++-+++-+--+----+-++++-+++---+++-++++++\ || ||||||| || |
|
||||
|| ||/+-++--+-++++++--+++++-+--+++++--+-+-++-+++-+++++---++-+++++++-++++++\| || ||||| ||||| ||| | | | |||| ||| ||| ||||||| || ||||||| || |
|
||||
|| |||| || | |||||| ||||| | ||||| | | || ||| ||||| || ||||||| |||||\++-++-+++++---+++++-+++-+--+----+-++++-+++---+++-+++++++-++-+++++++---+/ |
|
||||
|| |||| || | |||||| ||||| | ||||| |/+-++-+++-+++++---++\||||||| ||||| || || ||||| ||||| ||| | | | |||| ||| ||| ||||||| || ||||||| | |
|
||||
|| |||| || | |||||| /+++++-+--+++++--+++-++-+++-+++++---++++++++++-+++++-++-++-+++++---+++++-+++-+--+\ | |||| ||| ||| ||||||| || ||||||| | |
|
||||
|| |||| || ^ |||||| |||||| | ||||| ||| || ||| ||||| /-++++++++++-+++++-++-++-+++++---+++++-+++-+--++\/-+-++++-+++---+++-+++++++-++-+++++++--\| |
|
||||
|| |||| || | \+++++-++++++-+--+++++--+++-++-+++-+++++-+-++++++++++-+++++-++-++-+++++---+++++-/||/+--++++-+-++++-+++-\ ||| ||||||| || ||||||| || |
|
||||
|| |||| || | \++++-++++++-+--+++++--+++-++-+++-+++++-+-+++++++++/ ||||| || || ||||| ||||| |||| |||| | |||| ||| | ||| ||||||| || ||||||| || |
|
||||
|| |||| || | |||| |||||| | ||||| ||| |\-+++-+++++-+-+++++++++--+++++-++-++-+++++---+++++--++++--++++-+-++++-+++-+-/|| ||||||| || ||||||| || |
|
||||
|| |||| || | |||| |||||| | ||||| |||/+--+++-+++++-+-+++++++++--+++++-++-++-+++++---+++++--++++--++++-+-++++-+++-+--++-+++++++-++-+++++++\ || |
|
||||
|| |||| || | |||| |||||| | ||||| ||||| ||| ||||| | ||||||||| ||||| || || ||||| ||||| |||| |||| | |||| ||| | || ||||||| || |||||||| || |
|
||||
|| |||| || /+---++++-++++++-+--+++++--+++++\ ||| ||||| | ||||||||| ||||| || || ||||| ||||| |||| |||| | |||| ||| | || ||||||| || |||||||| || |
|
||||
|| |||| || || |||| |||||| | |\+++--++++++-+++-+++++-+-+++++++++--+++++-++-++-+++++---+++++--++++--++++-+-++++-+/| | || ||||||| || |||||||| || |
|
||||
|| |||| \+-++---++++-++++++-+--+-+++--++++++-+++-+++++-+-+++++++/| ||||| || || ||||| ||||| |||| |||| | |||| | | | || ||||||| || |||||||| || |
|
||||
|| |||| | || |||| |||||| | \-+++--++++++-+++-+++++-+-+++++++-+--+++++-++-++-+++++---+++++--++++--++++-+-++++-+-+-+--++-+++++++-/| |||||||| || |
|
||||
|| |||| | || |||| |||||| | ||| |||||| ||| ||||| | ||||||| | ||||| || || ||||\---+++++--++++--++++-+-++++-+-+-+--++-+++++/| | |||||||| || |
|
||||
|| |||| /+-++---++++-++++++-+----+++--++++++\||| ||||| | ||||||| | ||||| || || |||| ||||| |||| |||| | \+++-+-+-+--++-+++++-+--+-++++++/| || |
|
||||
|| |||| || || |||| |||||| | ||| |||||||||| ||||| | ||||||| | ||||| || || |||| ||||| |||| |||| | ||| | | | || ||||| | | |||||| | || |
|
||||
|| |||| || || |||| |||||| | ||| |||||||||| ||||| | ||||||| | ||||| || || |||| ||||| |||| |||| | ||| | | | || ||||| | | |||||| | || |
|
||||
|| |||| || || |||| |||||| | ||| |||||||||| ||||| | ||||||| | ||||| || || |||| ||||\--++++--++++-+--+++-+-+-+--++-/|||| | | |||||| | || |
|
||||
|| |||| || || |||| |||||| | ||| |||||||||| ||||| | ||||||| | ||||| || || |||| |||| |||| |||| | ||| | | | || |||| | | |||||| | || |
|
||||
|| |||| || || |||| |||||| | ||| |||||||||| ||||| | ||||||| | ||||| || || |||| |||| |\++--++++-+--+++-+-+-+--++--/||| | | |||||| | || |
|
||||
|| |||| || || |||| |||||| | ||| |||||||||| |\+++-+-+++++++-+--++++/ || || |||| /-++++---+-++--++++-+--+++-+-+-+--++---+++-+--+-++++++-+-++--\|
|
||||
|| |||| || || |||| |||||| | ||| |||||||||| | ||| | ||||||| | |||| || || |||| | |||| | || |||| | ||| | | | || ||| | | |||||| | || ||
|
||||
|| |||| || || |||| |||||| | ||| |||||||||| | ||| | ||||||| | /++++--++-++-++++--+-++++---+-++--++++-+--+++-+-+-+--++---+++-+--+-++++++-+\|| ||
|
||||
|| ||||/++-++---++++-++++++-+---\\++--++++++++++-+-+++-+-+++++++-+-+++++--++-++-++++--+-++++---+-++--++++-+--+++-+-+-+--++---+++-+--/ |||||| |||| ||
|
||||
|| ||||||| || |||| |||||| | | || |||||||||| | ||| | ||||||\-+-+++++--++-++-++++--+-++++---+-++--++++-+--+++-+-+-+--++---+++-+----++++++-+++/ ||
|
||||
|| ||||||| || |||| \+++++-+---+-++--++++++++++-+-+++-+-++++++--+-+++++--++-++-++++--+-++++---+-++--+/|| | ||| | | | || ||| | |||||| ||| ||
|
||||
|| ||||||| || |||| ||||| | | || |||||||||| | ||| | |||||| | ||||| || || |||| | |||| | |^ | || | ||| | | | || |\+-+----++++++-+++---+/
|
||||
|| |||\+++-++---++++--+++++-+---+-++--++++++++++-+-+++-+-++++++--+-+++++--++-++-/||| | |||| | || | || | ||| | | | || | | | |||||| ||| |
|
||||
|| ||| ||| || |||| ||||| | | || |\++++++++-+-+++-+-++/||| | ||||| || || ||| | |||| | || | || | ||| | | | || | v | |||||| ||| |
|
||||
|| ||| ||| || |||| |||\+-+---+-++--+-++++++++-+-+++-+-++-+++--+-+++++--++-++--+++--+-++++---+-++--+-++-+--++/ | | | || | | | |||||| ||| |
|
||||
|| ||| ||| || |||| ||| | | | || | |||||||| | ||| | || ||| | |\+++--++-+/ ||| | |||| | || |/++-+--++--+-+-+--++---+-+-+-\ |||||| ||| |
|
||||
|| ||| ||| || |||| ||| | | | || | |||||||| | ||| | || ||\--+-+-+++--+/ | ||| | |||| | || |||| | || | | |/-++---+-+-+-+--++++++-+++-\ |
|
||||
|| ||| |||/++---++++--+++-+\| | || | |||||||| | ||| | \+-++---+-+-+++--+--+---+++--+-++++---+-++--++++-+--++--+-+-++-++---+-//+-+--++++++-+++-+\|
|
||||
|| ||| |||||| |||| ||| ||| | || | |||||||| | ||| | | || | | ||| | | ||| | |||| | || |||| | || | | || || | || | |||||| ||| |||
|
||||
\+-+++-++++++---++++--+++-+++---+-++--+-++++++++-+-+++-+--+-++---/ | ||| | | ||| | |||| | || |||| | ||/-+-+-++-++---+\ || | |||||| ||| |||
|
||||
| |\+-++++++---++++--+++-+++---+-++--/ ||||||\+-+-+++-+--+-++-----+-+++--+--+---+++--+-++++---+-++--++++-+--+++-+-+-++-++---++-++-+--+++/|| ||| |||
|
||||
| | | |||||\---++++--+++-/|| | || |||||| | | ||| | | || | ||| | | ||| | |||| /-+-++--++++-+--+++-+-+-++-++---++-++-+--+++-++\||| |||
|
||||
| | | ||||| /++++--+++--++---+-++----++++++-+-+\\++-+--+-++-----+-+++--+--+---+++--+-++++-+-+-++--++++-+--+++-+-/ || || || || | ||| |||||| |||
|
||||
| | | ||||| |||\+--+++--++---+-++----++++++-+-++-++-+--+-++-----+-++/ | | |||/-+-++++-+-+-++--++++\| ||| | || || || || | ||| |||||| |||
|
||||
| | | ||||| ^|| | ||\--++---+-++----++++++-+-++-++-+--+-++-----+-++---+--+---+/|| | |||| | \-++--++++++--+++-+---++-++---++-++-+--+/| |||||| |||
|
||||
| | | ||||\---+++-+--++---++---+-++----+++/|| | || || | |/++-----+-++---+--+---+-++-+\|||| | || |||||| ||| | || || || || | | | |||||| |||
|
||||
| | | |||| ||| | || || | || \++-++-+-++-++-+--++++-----+-++---+--+---+-++-++++++-+---++--++++++--+/| | || || || \+-+--+-+-++++++-+/|
|
||||
| | | |||| ||| | || || | || || || | || || | \+++-----+-++---+--+---+-/| |||||| | || |||||| | | | || || || | | | | |||||| | |
|
||||
| | | |||| ||| | |\---++---+-++-----++-++-+-++-++-+---+++-----+-++---+--/ | | |||||| | || |||||| | | | || || || | | | | |||||| | |
|
||||
| | | |\++----+++-+--+----++---+-++-----++-/| | || \+>+---++/ \-++---+------+--+-++++++-+---++--++++++--+-+-+---++-++---++--+-+--+-+-++++/| | |
|
||||
| | | | || ||\-+--+----++---+-/| || | | || | | || || | | | |||||| | || |||||| | | | || || || | | | | |||| | | |
|
||||
| | | | || /-++--+--+----++---+--+-----++--+-+-++--+\| || || | | | |||||| | || |||||| | | | || || /++--+-+--+-+-++++-+-+\|
|
||||
| | | | || | || |/-+----++---+--+-----++--+-+-++--+++---++--------++---+------+--+-++++++-+--\|| |||||| | | | || || ||| | | | | |||| | |||
|
||||
| | | | || | || || | || | | || | ^ || ||| || || | | | |||||| | ||| |||||| | | | || || ||| | | | | |||| | |||
|
||||
| | | | || | || || | || | | || | | || ||| || || | | | |||||| | ||\--++++++--+-+-+---++-++--+++--+-+--+-/ |||| | |||
|
||||
| | | | || | \+--++-+----++---+--+-----++--+-+-+/ ||| || /------++---+------+--+-++++++-+--++<--++++++--+-+-+---++-++--+++--+-+--+---++++-+-+++-\
|
||||
| | | | || | | || | || | | || | | | ||| || | || | | | |||\++-+--++---++++++--+-+-+---++-+/ ||| | | | |||| | ||| |
|
||||
\-+-+-+-++--+--+--++-+----++---+--+-----++--+-+-+---/|| || | || | | | ||| || | || |||||| | | | |\-+---+++--+-+--+---++++-+-/|| |
|
||||
| | | || | | || | || | | || | | \----++---++-+------+/ | | | ||| || | || |\++++--+-+-+---+--+---+++--+-/ | |||| | || |
|
||||
| | | || | | || | || | | || | | || || | | | | | ||| || | || | |||| \-+-+---+--+---+++--+----+---/||| | || |
|
||||
| \-+-++--+--+--++-+----++---+--+-----++--+-+------++---++-+------+----/ | | ||| || | |\---+-++++----+-+---/ | ||| | | ||| | || |
|
||||
| | || | | || | || | | || | | || || | | | | ||| || | | /+-++++----+-+------+---+++--+----+---\||| | || |
|
||||
| | || | | || | || | | || | | || || | | | | ||| || | | || |\++----+-+------+---+++--+----+---++++-/ || |
|
||||
| | || | | || | || | \-----++--+-+------++---++-+------+-----------+--+-+++-++-+--+---++-+-++----+-+------+---+++--+----+---+/|| || |
|
||||
| | || | | || | || | || | | |\---++-+------+-----------+--+-+++-++-+--+---++-/ || | | | ||| | | | || || |
|
||||
| | || | | || | || | || \-+------+----++-+------+-----------+--+-+++-++-+--+---+/ || \-+------+---++/ | | | || || |
|
||||
| | || | | || | || | || | | |\-+------+-----------+--+-+++-++-+--+---+----++------+------+---+/ | | | || || |
|
||||
| | || | | || | || | || | | | | | | \-+++-++-+--+---+----/| | | | | | | || || |
|
||||
| | || | | || \----++---+--------++----/ | | | | | /+++-++-+--+---+-----+------+------+---+\ | | | || || |
|
||||
| | || | | \+------++---+--------+/ /-----+----+--+------+-----------+--\|\++-++-+--+---+-----+------+------+---++---+----+---+-++----+/ |
|
||||
| | |\--+--+---+------/| | \------+-----+----+--+------+-----------+--++-++-++-+--+---+-----+------+------+---++---+----+---+-+/ | |
|
||||
| | | | \---+-------+---+--->-----------+-----+----+--+------+-----------+--++-++-++-+--+---+-----+------/ | \+---+----+---+-+-----/ |
|
||||
| | | | | | | | | | | | | || || || | | | | | | | | | | |
|
||||
| | | | \-------+---+---------------+-----+----+--+------+-----------+--++-++-++-+--/ | | | | | | | | |
|
||||
| | | \--------------+---+---------------+-----/ | | | | || || || \------+-----+-------------+----+---+----+---+-/ |
|
||||
| | | | | | \--+------+-----------+--++-/| || | | | | | | | |
|
||||
| | | | | | | | | || | \+--------+-----+-------------/ | | | | |
|
||||
| | | | | | | | | || | | | | | | | | |
|
||||
\---+-+------------------+---+---------------+-------------+------+-----------+--++--+--+--------+-----/ | | | | |
|
||||
| \------------------+---+---------------+-------------+------+-----------+--++--+--/ | | | | | |
|
||||
| | | \-------------+------+-----------+--/| \-----------+------------------------+---+----/ | |
|
||||
| | | | \-----------+---+--------------+------------------------+---/ | |
|
||||
| \---+-----------------------------+------------------/ \--------------+------------------------/ | |
|
||||
\------------------------/ | | | |
|
||||
| \-------------------------------------/ |
|
||||
\--------------------------------------------------------------------------------------/
|
||||
32
input/day15.txt
Normal file
32
input/day15.txt
Normal file
@@ -0,0 +1,32 @@
|
||||
################################
|
||||
####################.......#####
|
||||
##################.G.......###.#
|
||||
##################...G.........#
|
||||
#############................###
|
||||
############..............######
|
||||
############...##......#########
|
||||
############...G.....#.#########
|
||||
##..##........G##.........######
|
||||
##..##.....#.G...........E#..###
|
||||
##..##.....#.....G......G..E..##
|
||||
##G............................#
|
||||
#....G........#####..G.........#
|
||||
#......#.G...#######..E.......##
|
||||
#...##..G...#########E.....#####
|
||||
##...G.#....#########.....######
|
||||
######G.G...#########..#.#######
|
||||
######.#...G#########.##########
|
||||
#####.......#########.##########
|
||||
#####.GE.....#######..##########
|
||||
#####.....E...#####...##########
|
||||
#######....G..........##########
|
||||
#######..........G..############
|
||||
######.G............############
|
||||
#########...........#..#########
|
||||
############..........##########
|
||||
############E...E.##...#########
|
||||
#############.....E..E.#########
|
||||
##############.........#########
|
||||
##############...#....##########
|
||||
###############..#.#############
|
||||
################################
|
||||
4261
input/day16.txt
Normal file
4261
input/day16.txt
Normal file
File diff suppressed because it is too large
Load Diff
1470
input/day17.txt
Normal file
1470
input/day17.txt
Normal file
File diff suppressed because it is too large
Load Diff
50
input/day18.txt
Normal file
50
input/day18.txt
Normal file
@@ -0,0 +1,50 @@
|
||||
|#..|#...|..|.#..|###|.....#.|.......||#..|....||.
|
||||
#||..##.#........||#...##.|..###.|.||...|.#.|.|.#.
|
||||
##.#.###....##....|..||#.||##.|.###|........||.##.
|
||||
#.|.||#...|..####......|.#|#..#.#|##...||..#..|...
|
||||
.....#..#.|.####..#..#...|||...||.|...#......#..|.
|
||||
.|..#..#.......|...#.|...|.##....|#|..#|###..#..#.
|
||||
.##..#..##..|.#|||.##..|..#.##..|....#..#|.##|.|#.
|
||||
|#..|#...|...|.|.......#.#......|...|.#.|||.|||#.#
|
||||
|....#...|..#..#.....#.|..#.#..|#|.#|...|..|#..|#|
|
||||
.#...##..|#.##......##...#|||..|.....#.|..|...|..#
|
||||
#.....|..|...||.|.|.....|....#|..|#...#|...#.....#
|
||||
...|...###.||......|..#|..|...|.##|........#|#|..|
|
||||
|.|.#.#......||#|||..|#....|#.|...#|..|.|.#|#.|.|.
|
||||
###.#.|....|.......##.#|###.|#.#..#.|.#...#...###.
|
||||
|###...|.....#.|.##..#...|#.#.|.##.#........#..|..
|
||||
|.||.|...##...##|......#..|.##.##|..#..|#..#.##...
|
||||
#....|#.....|...|...|............#..#|.....|.#.|.#
|
||||
...#..|..|||#.|.......#|...#...##|.......####.|...
|
||||
.#..|..#..|....||#.##.....|||...#..|.#..|.#..|..##
|
||||
....#...##.........#....|..#.......#...|.....##.#.
|
||||
|...|...|....#|####||###..|.|..|.||.#......#.|#...
|
||||
.#.#|.|.|....#.....||...||..|...##.#..|.|.#......|
|
||||
..|.......|||.|..#.#......|.|..##.||....|###....#.
|
||||
##....#.......#.|#.##.........|.|....#...|.#|.|.#|
|
||||
|#.##...|||||#.##.#...#.|#...|.||.|...|..#...#..|.
|
||||
...#||..#.......||..|.###.#.|#......||..|.#.....#.
|
||||
#..|.||#.#...|..........#.....#...#...###||.#.....
|
||||
#..#.|###|#|..|##...##.#......#|.#.#|..#.......|#.
|
||||
.|.....|.|..#.###|.#|.##.....|.|..|..|..#..|...##.
|
||||
.|........#...#..|.|..||#....|....#..|.|........|#
|
||||
....#.|...#|||...#......#...##......|#....#.||.#..
|
||||
.|.....|....#......#.|#.|.|.|..#.#.|..##.#||.....#
|
||||
.....#...|.#|..#..#|#.#|.|..|.#........#|..#|....#
|
||||
|.||..##...|#.#||..|..#.|..|..#..|..#.|.#|.#...|#.
|
||||
...|#.###...#..|#..##..||....#.||..#.|.|#.#..|..||
|
||||
......|#|.#.#|.|....#..##|##|#...|.#.|.#....##|#..
|
||||
#..||.....#....#....#.#.....|.....#....|....|...#.
|
||||
.#....#.##..........|.||.#.....#|#|||.#..#|......|
|
||||
..||..|....#..........#.|...#|.|#.|#..|#||.#...|#|
|
||||
..#..#.#|......#|.....||.#..##.|.#..#.||...|.|||..
|
||||
.#....|....#.|#...#..||..||.##..#.||....|.#|....|.
|
||||
..#|.|.....#....#..|..||..#..##.|.||..||||#.#..|.|
|
||||
.|#.|.||........#|.#|#....||..#||#...|..........##
|
||||
..#|.|..|||..###..|||.#..#.#||||.#.|##...|#......|
|
||||
..|...#|...|.#.#|.#...#.|..||##.#..#.|...#.#.#|#..
|
||||
#..#..|##.#|......#...|#|##..#.|...#.#.....#..##..
|
||||
..#.|..###|.|#.|........|.....|.....#..|.|.#...|.#
|
||||
..#|.|#.#.|#..|....|#...|.....|........|.|##.|#||#
|
||||
#.....##.#..#..#...|#||.#.#.#..|....|||.|.|......#
|
||||
...#|#....|.#.#..##.|.....#....|.|||..##.|.#.|.##.
|
||||
37
input/day19.txt
Normal file
37
input/day19.txt
Normal file
@@ -0,0 +1,37 @@
|
||||
#ip 4
|
||||
addi 4 16 4
|
||||
seti 1 9 5
|
||||
seti 1 5 2
|
||||
mulr 5 2 1
|
||||
eqrr 1 3 1
|
||||
addr 1 4 4
|
||||
addi 4 1 4
|
||||
addr 5 0 0
|
||||
addi 2 1 2
|
||||
gtrr 2 3 1
|
||||
addr 4 1 4
|
||||
seti 2 6 4
|
||||
addi 5 1 5
|
||||
gtrr 5 3 1
|
||||
addr 1 4 4
|
||||
seti 1 2 4
|
||||
mulr 4 4 4
|
||||
addi 3 2 3
|
||||
mulr 3 3 3
|
||||
mulr 4 3 3
|
||||
muli 3 11 3
|
||||
addi 1 5 1
|
||||
mulr 1 4 1
|
||||
addi 1 2 1
|
||||
addr 3 1 3
|
||||
addr 4 0 4
|
||||
seti 0 2 4
|
||||
setr 4 8 1
|
||||
mulr 1 4 1
|
||||
addr 4 1 1
|
||||
mulr 4 1 1
|
||||
muli 1 14 1
|
||||
mulr 1 4 1
|
||||
addr 3 1 3
|
||||
seti 0 0 0
|
||||
seti 0 2 4
|
||||
1
input/day20.txt
Normal file
1
input/day20.txt
Normal file
File diff suppressed because one or more lines are too long
32
input/day21.txt
Normal file
32
input/day21.txt
Normal file
@@ -0,0 +1,32 @@
|
||||
#ip 1
|
||||
seti 123 0 2
|
||||
bani 2 456 2
|
||||
eqri 2 72 2
|
||||
addr 2 1 1
|
||||
seti 0 0 1
|
||||
seti 0 3 2
|
||||
bori 2 65536 5
|
||||
seti 4843319 1 2
|
||||
bani 5 255 4
|
||||
addr 2 4 2
|
||||
bani 2 16777215 2
|
||||
muli 2 65899 2
|
||||
bani 2 16777215 2
|
||||
gtir 256 5 4
|
||||
addr 4 1 1
|
||||
addi 1 1 1
|
||||
seti 27 4 1
|
||||
seti 0 7 4
|
||||
addi 4 1 3
|
||||
muli 3 256 3
|
||||
gtrr 3 5 3
|
||||
addr 3 1 1
|
||||
addi 1 1 1
|
||||
seti 25 0 1
|
||||
addi 4 1 4
|
||||
seti 17 0 1
|
||||
setr 4 1 5
|
||||
seti 7 3 1
|
||||
eqrr 2 0 4
|
||||
addr 4 1 1
|
||||
seti 5 3 1
|
||||
1000
input/day23.txt
Normal file
1000
input/day23.txt
Normal file
File diff suppressed because it is too large
Load Diff
23
input/day24.txt
Normal file
23
input/day24.txt
Normal file
@@ -0,0 +1,23 @@
|
||||
Immune System:
|
||||
3400 units each with 1430 hit points (immune to fire, radiation, slashing) with an attack that does 4 radiation damage at initiative 4
|
||||
138 units each with 8650 hit points (weak to bludgeoning; immune to slashing, cold, radiation) with an attack that does 576 slashing damage at initiative 16
|
||||
255 units each with 9469 hit points (weak to radiation, fire) with an attack that does 351 bludgeoning damage at initiative 8
|
||||
4145 units each with 2591 hit points (immune to cold; weak to slashing) with an attack that does 6 fire damage at initiative 12
|
||||
3605 units each with 10989 hit points with an attack that does 26 fire damage at initiative 19
|
||||
865 units each with 11201 hit points with an attack that does 102 slashing damage at initiative 10
|
||||
633 units each with 10092 hit points (weak to slashing, radiation) with an attack that does 150 slashing damage at initiative 11
|
||||
2347 units each with 3322 hit points with an attack that does 12 cold damage at initiative 2
|
||||
7045 units each with 3877 hit points (weak to radiation) with an attack that does 5 bludgeoning damage at initiative 5
|
||||
1086 units each with 8626 hit points (weak to radiation) with an attack that does 69 slashing damage at initiative 13
|
||||
|
||||
Infection:
|
||||
2152 units each with 12657 hit points (weak to fire, cold) with an attack that does 11 fire damage at initiative 18
|
||||
40 units each with 39458 hit points (immune to radiation, fire, slashing; weak to bludgeoning) with an attack that does 1519 slashing damage at initiative 7
|
||||
59 units each with 35138 hit points (immune to radiation; weak to fire) with an attack that does 1105 fire damage at initiative 15
|
||||
1569 units each with 51364 hit points (weak to radiation) with an attack that does 55 radiation damage at initiative 17
|
||||
929 units each with 23887 hit points (weak to bludgeoning) with an attack that does 48 cold damage at initiative 14
|
||||
5264 units each with 14842 hit points (immune to cold, fire; weak to slashing, bludgeoning) with an attack that does 4 bludgeoning damage at initiative 9
|
||||
1570 units each with 30419 hit points (weak to radiation, cold; immune to fire) with an attack that does 35 slashing damage at initiative 1
|
||||
1428 units each with 21393 hit points (weak to radiation) with an attack that does 29 cold damage at initiative 6
|
||||
1014 units each with 25717 hit points (weak to fire) with an attack that does 47 fire damage at initiative 3
|
||||
7933 units each with 29900 hit points (immune to bludgeoning, radiation, slashing) with an attack that does 5 slashing damage at initiative 20
|
||||
1405
input/day25.txt
Normal file
1405
input/day25.txt
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,4 +1,3 @@
|
||||
fn main() {
|
||||
aoc_2018::tasks::day08::both();
|
||||
// aoc_2018::tasks::day08::task2();
|
||||
aoc_2018::tasks::day24::task2();
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use std::collections::HashSet;
|
||||
use crate::utils;
|
||||
use std::collections::HashSet;
|
||||
|
||||
pub fn task1() {
|
||||
let frequency: i32 = utils::read_file("input/day01.txt")
|
||||
@@ -23,7 +23,8 @@ pub fn task2() {
|
||||
} else {
|
||||
Some((*current, true))
|
||||
}
|
||||
}).find(|state| state.1);
|
||||
})
|
||||
.find(|state| state.1);
|
||||
|
||||
println!("Part 2: {} was there already!", final_state.unwrap().0);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use crate::utils;
|
||||
use std::collections::HashMap;
|
||||
use std::collections::HashSet;
|
||||
use crate::utils;
|
||||
|
||||
pub fn task1() {
|
||||
let input = utils::read_file("input/day02.txt");
|
||||
@@ -10,7 +10,7 @@ pub fn task1() {
|
||||
for line in input.lines() {
|
||||
let mut counts = [0u8; 26];
|
||||
for c in line.chars() {
|
||||
counts[(c as usize - 'a' as usize)] += 1;
|
||||
counts[c as usize - 'a' as usize] += 1;
|
||||
}
|
||||
if counts.iter().any(|count| *count == 2) {
|
||||
count_two += 1;
|
||||
@@ -83,7 +83,7 @@ pub fn task2_linear() {
|
||||
// has that prefix.
|
||||
let mut root = Node::default();
|
||||
for id in input.lines() {
|
||||
add_id_to_tree(&mut root, &id);
|
||||
add_id_to_tree(&mut root, id);
|
||||
}
|
||||
|
||||
// find a match..
|
||||
@@ -92,11 +92,11 @@ pub fn task2_linear() {
|
||||
}
|
||||
|
||||
fn find_some_match(node: &Node) -> Option<String> {
|
||||
if let Some(result) = check_children_for_match(&node) {
|
||||
return Some(result);
|
||||
if let Some(result) = check_children_for_match(node) {
|
||||
Some(result)
|
||||
} else {
|
||||
for child in node.outgoing.values() {
|
||||
if let Some(result) = find_some_match(&child) {
|
||||
if let Some(result) = find_some_match(child) {
|
||||
return Some(result);
|
||||
}
|
||||
}
|
||||
@@ -113,14 +113,14 @@ fn find_some_match(node: &Node) -> Option<String> {
|
||||
/// suffixes that appear more than once in a child node. Then we look at
|
||||
/// all possible suffixes from all child nodes. If one suffix appears exactly
|
||||
/// twice, we have a match.
|
||||
fn check_children_for_match<'a>(node: &Node<'a>) -> Option<String> {
|
||||
fn check_children_for_match(node: &Node<'_>) -> Option<String> {
|
||||
let edges: Vec<_> = node.outgoing.keys().collect();
|
||||
// create a set of candidate suffixes for each edge
|
||||
let suffix_candidates: HashMap<char, HashSet<&str>> = edges
|
||||
.iter()
|
||||
.map(|c| {
|
||||
let mut suffix_count = HashMap::<&str, HashSet<&str>>::new();
|
||||
let ref ids = node.outgoing.get(&c).unwrap().same_prefix;
|
||||
let ids = &node.outgoing.get(c).unwrap().same_prefix;
|
||||
for id in ids {
|
||||
suffix_count
|
||||
.entry(&id[node.depth + 1..])
|
||||
@@ -136,23 +136,19 @@ fn check_children_for_match<'a>(node: &Node<'a>) -> Option<String> {
|
||||
.map(|(suffix, _)| *suffix)
|
||||
.collect(),
|
||||
)
|
||||
}).collect();
|
||||
// go over all suffixes and count their occurences. If # = 2, match!
|
||||
})
|
||||
.collect();
|
||||
// go over all suffixes and count their occurrences. If # = 2, match!
|
||||
let mut suffix_counter: HashMap<&str, usize> = HashMap::new();
|
||||
for suffix_set in suffix_candidates.values() {
|
||||
for suffix in suffix_set {
|
||||
*suffix_counter.entry(suffix).or_insert(0) += 1;
|
||||
}
|
||||
}
|
||||
if let Some(suffix) =
|
||||
suffix_counter
|
||||
.iter()
|
||||
.find_map(|(suffix, count)| if *count == 2 { Some(suffix) } else { None })
|
||||
{
|
||||
Some(format!("{}{}", node.prefix, &suffix))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
suffix_counter
|
||||
.iter()
|
||||
.find_map(|(suffix, count)| if *count == 2 { Some(suffix) } else { None })
|
||||
.map(|suffix| format!("{}{}", node.prefix, &suffix))
|
||||
}
|
||||
|
||||
#[derive(Default, Debug)]
|
||||
@@ -165,12 +161,12 @@ struct Node<'a> {
|
||||
|
||||
fn add_id_to_tree<'a>(root: &mut Node<'a>, id: &'a str) {
|
||||
let mut current = root;
|
||||
current.same_prefix.insert(&id);
|
||||
current.same_prefix.insert(id);
|
||||
for (i, c) in id.chars().enumerate() {
|
||||
{
|
||||
let mut next = current.outgoing.entry(c).or_insert(Node::default());
|
||||
let next = current.outgoing.entry(c).or_insert(Node::default());
|
||||
next.depth = i + 1;
|
||||
next.same_prefix.insert(&id);
|
||||
next.same_prefix.insert(id);
|
||||
next.prefix = &id[..=i];
|
||||
}
|
||||
current = { current }.outgoing.get_mut(&c).unwrap();
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use crate::utils;
|
||||
use regex::Regex;
|
||||
use std::collections::HashMap;
|
||||
use crate::utils;
|
||||
|
||||
#[derive(PartialEq)]
|
||||
enum Use {
|
||||
@@ -16,19 +16,20 @@ pub fn task1() {
|
||||
.lines()
|
||||
.map(|line| {
|
||||
// #12 @ 590,968: 25x14
|
||||
let m = re.captures(&line).unwrap();
|
||||
let m = re.captures(line).unwrap();
|
||||
let id: u32 = m.get(1).unwrap().as_str().parse().unwrap();
|
||||
let left: u32 = m.get(2).unwrap().as_str().parse().unwrap();
|
||||
let top: u32 = m.get(3).unwrap().as_str().parse().unwrap();
|
||||
let width: u32 = m.get(4).unwrap().as_str().parse().unwrap();
|
||||
let height: u32 = m.get(5).unwrap().as_str().parse().unwrap();
|
||||
(id, left, top, width, height)
|
||||
}).fold(
|
||||
})
|
||||
.fold(
|
||||
HashMap::<(u32, u32), Use>::new(),
|
||||
|mut map, (id, left, top, width, height)| {
|
||||
for x in left..left + width {
|
||||
for y in top..top + height {
|
||||
if let None = map.get(&(x, y)) {
|
||||
if map.get(&(x, y)).is_none() {
|
||||
map.insert((x, y), Use::Single(id));
|
||||
} else {
|
||||
map.insert((x, y), Use::Multi);
|
||||
@@ -38,7 +39,8 @@ pub fn task1() {
|
||||
|
||||
map
|
||||
},
|
||||
).iter()
|
||||
)
|
||||
.iter()
|
||||
.filter(|it| *it.1 == Use::Multi)
|
||||
.count();
|
||||
|
||||
@@ -53,21 +55,22 @@ pub fn task2() {
|
||||
let claims: Vec<_> = input
|
||||
.lines()
|
||||
.map(|line| {
|
||||
let m = re.captures(&line).unwrap();
|
||||
let m = re.captures(line).unwrap();
|
||||
let id: u32 = m.get(1).unwrap().as_str().parse().unwrap();
|
||||
let left: u32 = m.get(2).unwrap().as_str().parse().unwrap();
|
||||
let top: u32 = m.get(3).unwrap().as_str().parse().unwrap();
|
||||
let width: u32 = m.get(4).unwrap().as_str().parse().unwrap();
|
||||
let height: u32 = m.get(5).unwrap().as_str().parse().unwrap();
|
||||
(id, left, top, width, height)
|
||||
}).collect();
|
||||
})
|
||||
.collect();
|
||||
|
||||
let distribution: HashMap<(u32, u32), Use> = claims.iter().fold(
|
||||
HashMap::<(u32, u32), Use>::new(),
|
||||
|mut map, (id, left, top, width, height)| {
|
||||
for x in *left..*left + *width {
|
||||
for y in *top..*top + *height {
|
||||
if let None = map.get(&(x, y)) {
|
||||
if map.get(&(x, y)).is_none() {
|
||||
map.insert((x, y), Use::Single(*id));
|
||||
} else {
|
||||
map.insert((x, y), Use::Multi);
|
||||
@@ -90,7 +93,8 @@ pub fn task2() {
|
||||
}
|
||||
}
|
||||
true
|
||||
}).unwrap();
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
println!("Part 2: {}", winner_id);
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
use crate::utils;
|
||||
use chrono::prelude::*;
|
||||
use chrono::Duration;
|
||||
use chrono::NaiveDateTime;
|
||||
use std::collections::HashMap;
|
||||
use crate::utils;
|
||||
|
||||
enum Activity {
|
||||
Starts(u32),
|
||||
@@ -29,13 +29,14 @@ pub fn task1() {
|
||||
} else if line.contains("wakes up") {
|
||||
Activity::Awakens
|
||||
} else {
|
||||
let number: u32 = line.split(' ').find(|part| part.starts_with("#")).unwrap()[1..]
|
||||
let number: u32 = line.split(' ').find(|part| part.starts_with('#')).unwrap()[1..]
|
||||
.parse()
|
||||
.unwrap();
|
||||
Activity::Starts(number)
|
||||
};
|
||||
(time, activity)
|
||||
}).collect();
|
||||
})
|
||||
.collect();
|
||||
input.sort_by_key(|it| it.0);
|
||||
|
||||
let mut current_id: u32 = 0;
|
||||
@@ -45,7 +46,7 @@ pub fn task1() {
|
||||
let minute = Duration::minutes(1);
|
||||
for (time, activity) in input.into_iter() {
|
||||
// for all minutes since last time slot fill arrays
|
||||
let mut iter_time = last_time.clone();
|
||||
let mut iter_time = last_time;
|
||||
while iter_time < time {
|
||||
if current_state == State::Asleep && iter_time.hour() == 0 {
|
||||
sleep_map.entry(current_id).or_insert([0; 60])[iter_time.minute() as usize] += 1;
|
||||
@@ -98,13 +99,14 @@ pub fn task2() {
|
||||
} else if line.contains("wakes up") {
|
||||
Activity::Awakens
|
||||
} else {
|
||||
let number: u32 = line.split(' ').find(|part| part.starts_with("#")).unwrap()[1..]
|
||||
let number: u32 = line.split(' ').find(|part| part.starts_with('#')).unwrap()[1..]
|
||||
.parse()
|
||||
.unwrap();
|
||||
Activity::Starts(number)
|
||||
};
|
||||
(time, activity)
|
||||
}).collect();
|
||||
})
|
||||
.collect();
|
||||
input.sort_by_key(|it| it.0);
|
||||
|
||||
let mut current_id: u32 = 0;
|
||||
@@ -114,7 +116,7 @@ pub fn task2() {
|
||||
let minute = Duration::minutes(1);
|
||||
for (time, activity) in input.into_iter() {
|
||||
// for all minutes since last time slot fill arrays
|
||||
let mut iter_time = last_time.clone();
|
||||
let mut iter_time = last_time;
|
||||
while iter_time < time {
|
||||
if current_state == State::Asleep && iter_time.hour() == 0 {
|
||||
sleep_map.entry(current_id).or_insert([0; 60])[iter_time.minute() as usize] += 1;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use std::time::Instant;
|
||||
use crate::utils;
|
||||
use std::time::Instant;
|
||||
|
||||
pub fn task1() {
|
||||
let mut input = utils::read_file("input/day05.txt");
|
||||
@@ -24,9 +24,11 @@ pub fn task2() {
|
||||
.chars()
|
||||
.filter(|ch| ch.eq_ignore_ascii_case(&c))
|
||||
.collect::<String>(),
|
||||
).len(),
|
||||
)
|
||||
.len(),
|
||||
)
|
||||
}).min_by_key(|it| it.1)
|
||||
})
|
||||
.min_by_key(|it| it.1)
|
||||
.unwrap();
|
||||
|
||||
println!("Duration: {:?}", Instant::now() - start);
|
||||
@@ -56,6 +58,7 @@ fn reduce(input: &str) -> String {
|
||||
stack.push(c);
|
||||
}
|
||||
stack
|
||||
}).iter()
|
||||
})
|
||||
.iter()
|
||||
.collect()
|
||||
}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
use std::cmp::Ordering::{Equal, Greater, Less};
|
||||
|
||||
use crate::utils;
|
||||
|
||||
pub fn task1() {
|
||||
@@ -12,7 +14,8 @@ pub fn task1() {
|
||||
split.next().unwrap().parse().unwrap(),
|
||||
split.next().unwrap().parse().unwrap(),
|
||||
)
|
||||
}).collect();
|
||||
})
|
||||
.collect();
|
||||
|
||||
let max_x = coordinates.iter().max_by_key(|it| it.0).unwrap().0;
|
||||
let max_y = coordinates.iter().max_by_key(|it| it.1).unwrap().1;
|
||||
@@ -26,22 +29,17 @@ pub fn task1() {
|
||||
area.push(vec);
|
||||
}
|
||||
|
||||
for (_, (a, b)) in coordinates.iter().enumerate() {
|
||||
for x in 0..area.len() {
|
||||
for y in 0..area[x].len() {
|
||||
for (a, b) in coordinates.iter() {
|
||||
for (x, col) in area.iter_mut().enumerate() {
|
||||
for (y, cell) in col.iter_mut().enumerate() {
|
||||
let d = (i32::abs(*a as i32 - x as i32) + i32::abs(*b as i32 - y as i32)) as u16;
|
||||
area[x][y] = match area[x][y] {
|
||||
*cell = match *cell {
|
||||
None => Single(d, (*a, *b)),
|
||||
Single(dd, (aa, bb)) => {
|
||||
if dd < d {
|
||||
Single(dd, (aa, bb))
|
||||
} else if dd > d {
|
||||
Single(d, (*a, *b))
|
||||
} else {
|
||||
// equal
|
||||
Multi(d)
|
||||
}
|
||||
}
|
||||
Single(dd, (aa, bb)) => match dd.cmp(&d) {
|
||||
Less => Single(dd, (aa, bb)),
|
||||
Equal => Single(d, (*a, *b)),
|
||||
Greater => Multi(d),
|
||||
},
|
||||
Multi(dd) => {
|
||||
if d < dd {
|
||||
Single(d, (*a, *b))
|
||||
@@ -60,18 +58,15 @@ pub fn task1() {
|
||||
.map(|(_, (a, b))| {
|
||||
let count = area
|
||||
.iter()
|
||||
.flat_map(|v| v)
|
||||
.flatten()
|
||||
.filter(|entry| {
|
||||
if let Single(_, (x, y)) = entry {
|
||||
if a == x && b == y {
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
a == x && b == y
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}).count();
|
||||
})
|
||||
.count();
|
||||
let infinite = area[0].iter().any(|bla| bla.belongs_to_point(*a, *b))
|
||||
|| area[area.len() - 1]
|
||||
.iter()
|
||||
@@ -82,7 +77,8 @@ pub fn task1() {
|
||||
.any(|line| line[line.len() - 1].belongs_to_point(*a, *b));
|
||||
// println!("{} has size {} (infinite: {:?})", i, count, infinite);
|
||||
(count, infinite)
|
||||
}).collect::<Vec<_>>();
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
println!(
|
||||
"Overall occupation: {} of {}",
|
||||
@@ -127,7 +123,8 @@ pub fn task2() {
|
||||
split.next().unwrap().parse().unwrap(),
|
||||
split.next().unwrap().parse().unwrap(),
|
||||
)
|
||||
}).collect();
|
||||
})
|
||||
.collect();
|
||||
|
||||
let max_x = coordinates.iter().max_by_key(|it| it.0).unwrap().0;
|
||||
let max_y = coordinates.iter().max_by_key(|it| it.1).unwrap().1;
|
||||
@@ -141,10 +138,13 @@ pub fn task2() {
|
||||
.map(|(a, b)| {
|
||||
(i32::abs(*a as i32 - x as i32) + i32::abs(*b as i32 - y as i32))
|
||||
as usize
|
||||
}).sum::<usize>()
|
||||
}).filter(|it| *it < 10000)
|
||||
})
|
||||
.sum::<usize>()
|
||||
})
|
||||
.filter(|it| *it < 10000)
|
||||
.count()
|
||||
}).sum();
|
||||
})
|
||||
.sum();
|
||||
|
||||
println!("Part 2: {}", result);
|
||||
}
|
||||
|
||||
@@ -19,12 +19,12 @@ pub fn task1() {
|
||||
let mut open: HashSet<char> = tasks
|
||||
.iter()
|
||||
.filter(|task| !depends_on.contains_key(task))
|
||||
.map(|c| *c)
|
||||
.copied()
|
||||
.collect();
|
||||
|
||||
let mut result = String::new();
|
||||
while open.len() > 0 {
|
||||
let next = open.iter().min().unwrap().clone();
|
||||
while !open.is_empty() {
|
||||
let next = *open.iter().min().unwrap();
|
||||
open.remove(&next);
|
||||
result.push(next);
|
||||
let newly_open: HashSet<char> = depends_on
|
||||
@@ -32,7 +32,7 @@ pub fn task1() {
|
||||
.filter(|(_task, deps)| deps.iter().all(|dep| result.chars().any(|c| c == *dep)))
|
||||
.map(|(task, _)| *task)
|
||||
.collect();
|
||||
open = open.union(&newly_open).map(|c| *c).collect();
|
||||
open = open.union(&newly_open).copied().collect();
|
||||
for c in newly_open {
|
||||
depends_on.remove(&c);
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ use crate::utils;
|
||||
|
||||
pub fn both() {
|
||||
let input: Vec<usize> = utils::read_file("input/day08.txt")
|
||||
.split(" ")
|
||||
.split(' ')
|
||||
.map(|x| x.parse().unwrap())
|
||||
.collect();
|
||||
|
||||
@@ -23,13 +23,13 @@ impl Node {
|
||||
let num_meta: usize = input[1];
|
||||
let mut children = Vec::new();
|
||||
while num_children > 0 {
|
||||
let (node, rest) = Node::extract_from(&rest_input);
|
||||
let (node, rest) = Node::extract_from(rest_input);
|
||||
children.push(node);
|
||||
rest_input = rest;
|
||||
num_children -= 1;
|
||||
}
|
||||
|
||||
let metadata = rest_input[..num_meta].iter().map(|x| *x).collect();
|
||||
let metadata = rest_input[..num_meta].to_vec();
|
||||
(Node { metadata, children }, &rest_input[num_meta..])
|
||||
}
|
||||
|
||||
@@ -39,14 +39,14 @@ impl Node {
|
||||
.children
|
||||
.iter()
|
||||
.map(|child| {
|
||||
let s: usize = child.metadata_sum().clone();
|
||||
let s: usize = child.metadata_sum();
|
||||
s
|
||||
})
|
||||
.sum::<usize>()
|
||||
}
|
||||
|
||||
fn task2(&self) -> usize {
|
||||
if self.children.len() > 0 {
|
||||
if !self.children.is_empty() {
|
||||
self.metadata
|
||||
.iter()
|
||||
.map(|meta| match self.children.get(*meta - 1) {
|
||||
|
||||
94
src/tasks/day09.rs
Normal file
94
src/tasks/day09.rs
Normal file
@@ -0,0 +1,94 @@
|
||||
const PLAYERS: usize = 468;
|
||||
const MODULO: usize = 23;
|
||||
const HIGHEST_MARBLE: usize = 7184300;
|
||||
|
||||
pub fn task1() {
|
||||
let mut player_score = [0usize; PLAYERS];
|
||||
let mut current_player = 1;
|
||||
let mut current_index: usize = 0;
|
||||
let mut deck: Vec<usize> = Vec::new();
|
||||
deck.push(0);
|
||||
for marble in 1..=HIGHEST_MARBLE {
|
||||
if marble % MODULO == 0 {
|
||||
current_index = rem(current_index, 7, deck.len());
|
||||
player_score[current_player] += marble;
|
||||
player_score[current_player] += deck.remove(current_index);
|
||||
} else {
|
||||
current_index = (current_index + 2) % deck.len();
|
||||
deck.insert(current_index, marble);
|
||||
}
|
||||
current_player = (current_player + 1) % PLAYERS;
|
||||
if marble % 10000 == 0 {
|
||||
println!("{} ({}%)", marble, marble as f32 / HIGHEST_MARBLE as f32);
|
||||
}
|
||||
}
|
||||
|
||||
let result = player_score.iter().max().unwrap();
|
||||
println!("The highest score is {}", result);
|
||||
}
|
||||
|
||||
pub fn rem(a: usize, sub: usize, m: usize) -> usize {
|
||||
if sub > a {
|
||||
(a + m - sub) % m
|
||||
} else {
|
||||
(a - sub) % m
|
||||
}
|
||||
}
|
||||
|
||||
pub fn task2() {
|
||||
let _dummy_node = ListNode {
|
||||
value: 0,
|
||||
id_left: 0,
|
||||
id_right: 0,
|
||||
};
|
||||
|
||||
let mut player_score = [0usize; PLAYERS];
|
||||
let mut current_player = 1;
|
||||
|
||||
let mut nodes = Vec::with_capacity(HIGHEST_MARBLE);
|
||||
nodes.push(ListNode {
|
||||
value: 0,
|
||||
id_left: 0,
|
||||
id_right: 0,
|
||||
});
|
||||
let mut current_node = &nodes[0];
|
||||
|
||||
for marble in 1..=HIGHEST_MARBLE {
|
||||
if marble % MODULO == 0 {
|
||||
for _ in 0..7 {
|
||||
current_node = &nodes[current_node.id_left];
|
||||
}
|
||||
player_score[current_player] += marble;
|
||||
player_score[current_player] += current_node.value;
|
||||
let id_left = current_node.id_left;
|
||||
let id_right = current_node.id_right;
|
||||
nodes[id_left].id_right = id_right;
|
||||
nodes[id_right].id_left = id_left;
|
||||
current_node = &nodes[id_right];
|
||||
} else {
|
||||
let id_left = current_node.id_right;
|
||||
let id_right = nodes[current_node.id_right].id_right;
|
||||
let new = ListNode {
|
||||
value: marble,
|
||||
id_left,
|
||||
id_right,
|
||||
};
|
||||
nodes.push(new);
|
||||
let id_new = nodes.len() - 1;
|
||||
nodes[id_left].id_right = id_new;
|
||||
nodes[id_right].id_left = id_new;
|
||||
current_node = &nodes[id_new];
|
||||
}
|
||||
current_player = (current_player + 1) % PLAYERS;
|
||||
}
|
||||
|
||||
let result = player_score.iter().max().unwrap();
|
||||
println!("The highest score is {}", result);
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct ListNode {
|
||||
value: usize,
|
||||
id_left: usize,
|
||||
id_right: usize,
|
||||
}
|
||||
95
src/tasks/day10.rs
Normal file
95
src/tasks/day10.rs
Normal file
@@ -0,0 +1,95 @@
|
||||
use crate::utils;
|
||||
use regex::Regex;
|
||||
|
||||
pub fn task1() {
|
||||
let input = utils::read_file("input/day10.txt");
|
||||
// position=<-4, 3> velocity=< 2, 0>
|
||||
let regex = Regex::new(
|
||||
r"position=<\s*(?P<x>-?\d+),\s*(?P<y>-?\d+)> velocity=<\s*(?P<vx>-?\d+),\s*(?P<vy>-?\d+)>",
|
||||
)
|
||||
.unwrap();
|
||||
let mut lights: Vec<Light> = input
|
||||
.lines()
|
||||
//.inspect(|line| println!("{}", line))
|
||||
.map(|line| {
|
||||
let cap = regex.captures(line).unwrap();
|
||||
Light {
|
||||
x: cap["x"].parse::<i32>().unwrap(),
|
||||
y: cap["y"].parse::<i32>().unwrap(),
|
||||
vx: cap["vx"].parse::<i32>().unwrap(),
|
||||
vy: cap["vy"].parse::<i32>().unwrap(),
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
|
||||
// for light in lights.iter() {
|
||||
// println!("{:?}", light);
|
||||
// }
|
||||
|
||||
let mut old_area = get_area(&lights);
|
||||
let mut time = 0;
|
||||
loop {
|
||||
time += 1;
|
||||
let new_lights: Vec<Light> = lights.iter().map(|light| light.move_copy()).collect();
|
||||
// print_lights(&new_lights);
|
||||
let new_area = get_area(&new_lights);
|
||||
// println!("Area: {} ", new_area);
|
||||
if new_area > old_area {
|
||||
break;
|
||||
} else {
|
||||
lights = new_lights;
|
||||
old_area = new_area;
|
||||
}
|
||||
}
|
||||
println!("Found a minimum after {} seconds", time - 1);
|
||||
print_lights(&lights);
|
||||
}
|
||||
|
||||
fn get_area(lights: &[Light]) -> usize {
|
||||
let xmin = lights.iter().map(|it| it.x).min().unwrap();
|
||||
let xmax = lights.iter().map(|it| it.x).max().unwrap();
|
||||
let ymin = lights.iter().map(|it| it.y).min().unwrap();
|
||||
let ymax = lights.iter().map(|it| it.y).max().unwrap();
|
||||
(xmax - xmin) as usize * (ymax - ymin) as usize
|
||||
}
|
||||
|
||||
fn print_lights(lights: &[Light]) {
|
||||
let xmin = lights.iter().map(|it| it.x).min().unwrap();
|
||||
let xmax = lights.iter().map(|it| it.x).max().unwrap();
|
||||
let ymin = lights.iter().map(|it| it.y).min().unwrap();
|
||||
let ymax = lights.iter().map(|it| it.y).max().unwrap();
|
||||
let width = xmax - xmin + 1;
|
||||
let height = ymax - ymin + 1;
|
||||
|
||||
let mut screen: Vec<Vec<u8>> = Vec::with_capacity(height as usize);
|
||||
for _ in 0..=height {
|
||||
let mut chars = Vec::with_capacity(width as usize);
|
||||
chars.resize(width as usize + 1, b'.');
|
||||
screen.push(chars);
|
||||
}
|
||||
lights
|
||||
.iter()
|
||||
.for_each(|light| screen[(light.y - ymin) as usize][(light.x - xmin) as usize] = b'#');
|
||||
for line in screen.iter() {
|
||||
println!("{}", String::from_utf8(line.clone()).unwrap());
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Light {
|
||||
x: i32,
|
||||
y: i32,
|
||||
vx: i32,
|
||||
vy: i32,
|
||||
}
|
||||
|
||||
impl Light {
|
||||
fn move_copy(&self) -> Self {
|
||||
Light {
|
||||
x: self.x + self.vx,
|
||||
y: self.y + self.vy,
|
||||
vx: self.vx,
|
||||
vy: self.vy,
|
||||
}
|
||||
}
|
||||
}
|
||||
124
src/tasks/day11.rs
Normal file
124
src/tasks/day11.rs
Normal file
@@ -0,0 +1,124 @@
|
||||
pub fn task1() {
|
||||
let square_size = 3;
|
||||
let serial = 6392;
|
||||
let result = (1..=300 - square_size)
|
||||
.flat_map(|x: i32| (1..=300 - square_size).map(move |y: i32| (x, y)))
|
||||
.map(|(x, y)| {
|
||||
let power: i32 = (x..x + square_size)
|
||||
.map(|x| {
|
||||
(y..y + square_size)
|
||||
.map(move |y| fuel_level(x, y, serial))
|
||||
.sum::<i32>()
|
||||
})
|
||||
.sum();
|
||||
(x, y, power)
|
||||
})
|
||||
.max_by_key(|(_, _, value)| *value);
|
||||
println!("{:?}", result);
|
||||
}
|
||||
|
||||
pub fn task2() {
|
||||
let serial = 6392;
|
||||
|
||||
let mut values: Vec<Vec<i32>> = Vec::with_capacity(301);
|
||||
for x in 0..=300 {
|
||||
let mut v: Vec<i32> = Vec::with_capacity(301);
|
||||
for y in 0..=300 {
|
||||
v.push(fuel_level(x, y, serial));
|
||||
}
|
||||
values.push(v);
|
||||
}
|
||||
let values = &values;
|
||||
|
||||
let result = (1..300)
|
||||
.map(|square_size| {
|
||||
let result = (1..=300 - square_size)
|
||||
.flat_map(|x: i32| (1..=300 - square_size).map(move |y: i32| (x, y)))
|
||||
.map(|(x, y)| {
|
||||
let power: i32 = (x..x + square_size)
|
||||
.map(|x| {
|
||||
(y..y + square_size)
|
||||
.map(move |y| values[x as usize][y as usize])
|
||||
.sum::<i32>()
|
||||
})
|
||||
.sum();
|
||||
(x, y, power)
|
||||
})
|
||||
.max_by_key(|(_, _, value)| *value)
|
||||
.unwrap();
|
||||
(result.0, result.1, result.2, square_size)
|
||||
})
|
||||
.max_by_key(|result| result.2);
|
||||
println!("{:?}", result);
|
||||
}
|
||||
|
||||
pub fn task2_fast() {
|
||||
let serial = 6392;
|
||||
|
||||
let mut cache: Vec<Vec<i32>> = Vec::with_capacity(301);
|
||||
for x in 0_usize..=300 {
|
||||
let mut v: Vec<i32> = Vec::with_capacity(301);
|
||||
for y in 0_usize..=300 {
|
||||
if x == 0 || y == 0 {
|
||||
v.push(0);
|
||||
} else {
|
||||
v.push(
|
||||
fuel_level(x as i32, y as i32, serial) + v[v.len() - 1] + cache[x - 1][y]
|
||||
- cache[x - 1][y - 1],
|
||||
)
|
||||
}
|
||||
}
|
||||
cache.push(v);
|
||||
}
|
||||
let values = &cache;
|
||||
|
||||
for x in 0_usize..=300 {
|
||||
for y in 0_usize..=300 {
|
||||
if x != 0 && y != 0 {
|
||||
let cached = area_sum(values, x, y, 1);
|
||||
let calc = fuel_level(x as i32, y as i32, serial);
|
||||
//println!("{},{}: {} ({})", x, y, values[x][y], calc);
|
||||
assert_eq!(calc, cached);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let result = (1..=300)
|
||||
.map(|square_size| {
|
||||
let result = (1..=301 - square_size)
|
||||
.flat_map(|x: usize| (1..=301 - square_size).map(move |y: usize| (x, y)))
|
||||
.map(|(x, y)| (x, y, area_sum(values, x, y, square_size)))
|
||||
.max_by_key(|(_, _, value)| *value)
|
||||
.unwrap();
|
||||
(result.0, result.1, result.2, square_size)
|
||||
})
|
||||
.max_by_key(|result| result.2);
|
||||
println!("{:?}", result);
|
||||
}
|
||||
|
||||
fn area_sum(values: &[Vec<i32>], x: usize, y: usize, length: usize) -> i32 {
|
||||
values[x + length - 1][y + length - 1] + values[x - 1][y - 1]
|
||||
- values[x - 1][y + length - 1]
|
||||
- values[x + length - 1][y - 1]
|
||||
}
|
||||
|
||||
fn fuel_level(x: i32, y: i32, serial: i32) -> i32 {
|
||||
let rack_id = x + 10;
|
||||
let mut power = rack_id * y;
|
||||
power += serial;
|
||||
power *= rack_id;
|
||||
power = power / 100 % 10;
|
||||
power -= 5;
|
||||
power
|
||||
}
|
||||
|
||||
mod test {
|
||||
#[test]
|
||||
fn name() {
|
||||
use super::fuel_level;
|
||||
assert_eq!(fuel_level(3, 5, 8), 4);
|
||||
assert_eq!(fuel_level(122, 79, 57), -5);
|
||||
assert_eq!(fuel_level(217, 196, 39), 0);
|
||||
assert_eq!(fuel_level(101, 153, 71), 4);
|
||||
}
|
||||
}
|
||||
54
src/tasks/day12.rs
Normal file
54
src/tasks/day12.rs
Normal file
@@ -0,0 +1,54 @@
|
||||
use crate::utils;
|
||||
use std::collections::HashMap;
|
||||
use std::ops::Add;
|
||||
|
||||
pub fn task1() {
|
||||
let input = utils::read_file("input/day12.txt");
|
||||
let mut input = input.lines();
|
||||
let num_generations = 20;
|
||||
|
||||
let mut state: Vec<char> = "."
|
||||
.repeat(num_generations)
|
||||
.add(&input.next().unwrap()[15..])
|
||||
.add(&".".repeat(num_generations + 2))
|
||||
.chars()
|
||||
.collect();
|
||||
|
||||
let mut transformations: HashMap<String, char> = HashMap::new();
|
||||
|
||||
input.next();
|
||||
for line in input {
|
||||
let key = line.split(" => ").next().unwrap();
|
||||
transformations.insert(key.to_string(), line.chars().last().unwrap());
|
||||
}
|
||||
|
||||
for _ in 0..num_generations {
|
||||
println!("{}", state.iter().collect::<String>());
|
||||
let mut new_state = state.clone();
|
||||
for (i, c) in new_state[2..state.len() - 2].iter_mut().enumerate() {
|
||||
let next = transformations.get(&state[i..i + 5].iter().collect::<String>());
|
||||
if let Some(cc) = next {
|
||||
*c = *cc;
|
||||
} else {
|
||||
*c = '.';
|
||||
}
|
||||
}
|
||||
state = new_state;
|
||||
}
|
||||
|
||||
println!("{}", state.iter().collect::<String>());
|
||||
|
||||
let sum: isize = state
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(i, c)| {
|
||||
if *c == '#' {
|
||||
i as isize - (num_generations as isize)
|
||||
} else {
|
||||
0
|
||||
}
|
||||
})
|
||||
.sum();
|
||||
|
||||
println!("Result: {}", sum);
|
||||
}
|
||||
146
src/tasks/day13.rs
Normal file
146
src/tasks/day13.rs
Normal file
@@ -0,0 +1,146 @@
|
||||
use crate::utils;
|
||||
use std::collections::HashMap;
|
||||
|
||||
pub fn task1() {
|
||||
let (map, mut carts) = read_input();
|
||||
println!("We have {} carts initially", carts.len());
|
||||
loop {
|
||||
perform_round(&map, &mut carts);
|
||||
}
|
||||
}
|
||||
|
||||
fn read_input() -> (Vec<Vec<char>>, Vec<Cart>) {
|
||||
let input = utils::read_file("input/day13.txt");
|
||||
let input: Vec<&str> = input.lines().collect();
|
||||
let width = input[0].len();
|
||||
let height = input.len();
|
||||
let mut map = Vec::new();
|
||||
let mut inner_vec = Vec::new();
|
||||
inner_vec.resize(height, ' ');
|
||||
map.resize(width, inner_vec);
|
||||
let mut carts = Vec::new();
|
||||
let tiles = vec!['|', '-', '/', '\\', '+'];
|
||||
for (y, line) in input.iter().enumerate() {
|
||||
for (x, c) in line.chars().enumerate() {
|
||||
if tiles.contains(&c) {
|
||||
map[x][y] = c;
|
||||
} else if c != ' ' {
|
||||
map[x][y] = match c {
|
||||
'>' => '-',
|
||||
'<' => '-',
|
||||
'^' => '-',
|
||||
'v' => '-',
|
||||
_ => panic!("{} is invalid input char at this point", c),
|
||||
};
|
||||
carts.push(Cart {
|
||||
x,
|
||||
y,
|
||||
direction: c,
|
||||
intersections_visited: 0,
|
||||
active: true,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
(map, carts)
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Cart {
|
||||
x: usize,
|
||||
y: usize,
|
||||
direction: char,
|
||||
intersections_visited: usize,
|
||||
active: bool,
|
||||
}
|
||||
|
||||
fn perform_round(map: &[Vec<char>], carts: &mut Vec<Cart>) {
|
||||
carts.sort_unstable_by(|a, b| {
|
||||
if a.y == b.y {
|
||||
a.x.cmp(&b.x)
|
||||
} else {
|
||||
a.y.cmp(&b.y)
|
||||
}
|
||||
});
|
||||
let mut positions: HashMap<(usize, usize), usize> = carts
|
||||
.iter()
|
||||
.enumerate()
|
||||
.filter(|(_, cart)| cart.active)
|
||||
.map(|(i, cart)| ((cart.x, cart.y), i))
|
||||
.collect();
|
||||
|
||||
for cart_index in 0..carts.len() {
|
||||
let cart = &mut carts[cart_index];
|
||||
if !cart.active {
|
||||
continue;
|
||||
}
|
||||
|
||||
let pos_old = (cart.x, cart.y);
|
||||
match cart.direction {
|
||||
'>' => cart.x += 1,
|
||||
'<' => cart.x -= 1,
|
||||
'^' => cart.y -= 1,
|
||||
'v' => cart.y += 1,
|
||||
c => panic!("invalid direction {}", c),
|
||||
}
|
||||
cart.direction = match (cart.direction, map[cart.x][cart.y]) {
|
||||
('>', '/') => '^',
|
||||
('>', '\\') => 'v',
|
||||
('<', '/') => 'v',
|
||||
('<', '\\') => '^',
|
||||
('^', '/') => '>',
|
||||
('^', '\\') => '<',
|
||||
('v', '/') => '<',
|
||||
('v', '\\') => '>',
|
||||
(direction, '+') => {
|
||||
let new_direction = match cart.intersections_visited % 3 {
|
||||
0 => match direction {
|
||||
'>' => '^',
|
||||
'^' => '<',
|
||||
'<' => 'v',
|
||||
'v' => '>',
|
||||
_ => panic!("Invalid direction"),
|
||||
},
|
||||
1 => direction,
|
||||
2 => match direction {
|
||||
'>' => 'v',
|
||||
'^' => '>',
|
||||
'<' => '^',
|
||||
'v' => '<',
|
||||
_ => panic!("Invalid direction"),
|
||||
},
|
||||
_ => panic!("modulo 3 cannot be larger than 2"),
|
||||
};
|
||||
cart.intersections_visited += 1;
|
||||
new_direction
|
||||
}
|
||||
(_, _) => cart.direction,
|
||||
};
|
||||
if positions.contains_key(&(cart.x, cart.y)) {
|
||||
// Task1: panic here with coordinates
|
||||
println!("We have a collision at {},{}!", cart.x, cart.y);
|
||||
let other_index = positions[&(cart.x, cart.y)];
|
||||
cart.active = false;
|
||||
if !carts[other_index].active {
|
||||
panic!("that one crashed already before!");
|
||||
}
|
||||
carts[other_index].active = false;
|
||||
positions.remove(&(carts[cart_index].x, carts[cart_index].y));
|
||||
positions.remove(&pos_old);
|
||||
println!(
|
||||
"{} carts left",
|
||||
carts.iter().filter(|cart| cart.active).count()
|
||||
);
|
||||
} else {
|
||||
positions.remove(&pos_old);
|
||||
positions.insert((cart.x, cart.y), cart_index);
|
||||
}
|
||||
}
|
||||
if carts.iter().filter(|cart| cart.active).count() == 1 {
|
||||
panic!(
|
||||
"exactly one active cart left: {:?}",
|
||||
carts.iter().find(|cart| cart.active)
|
||||
);
|
||||
}
|
||||
}
|
||||
55
src/tasks/day14.rs
Normal file
55
src/tasks/day14.rs
Normal file
@@ -0,0 +1,55 @@
|
||||
pub fn task1() {
|
||||
let input: usize = 509671;
|
||||
|
||||
let mut scores = vec![3, 7];
|
||||
let mut recipes = vec![0, 1];
|
||||
|
||||
while scores.len() < input + 10 {
|
||||
let mut score: usize = recipes.iter().map(|recipe| scores[*recipe]).sum();
|
||||
if score >= 10 {
|
||||
scores.push(1);
|
||||
score -= 10;
|
||||
}
|
||||
scores.push(score);
|
||||
|
||||
for recipe in recipes.iter_mut() {
|
||||
*recipe = (*recipe + 1 + scores[*recipe]) % scores.len();
|
||||
}
|
||||
}
|
||||
|
||||
let result = scores[input..input + 10]
|
||||
.iter()
|
||||
.map(|s| s.to_string())
|
||||
.collect::<String>();
|
||||
println!("Last 10 for {}: {}", input, result);
|
||||
}
|
||||
|
||||
pub fn task2() {
|
||||
let input = vec![5, 0, 9, 6, 7, 1];
|
||||
|
||||
let mut scores = vec![3, 7];
|
||||
let mut recipes = vec![0, 1];
|
||||
|
||||
while scores.len() < 7
|
||||
|| scores[scores.len() - 6..] != input[..]
|
||||
&& scores[scores.len() - 7..scores.len() - 1] != input[..]
|
||||
{
|
||||
let mut score: usize = recipes.iter().map(|recipe| scores[*recipe]).sum();
|
||||
if score >= 10 {
|
||||
scores.push(1);
|
||||
score -= 10;
|
||||
}
|
||||
scores.push(score);
|
||||
|
||||
for recipe in recipes.iter_mut() {
|
||||
*recipe = (*recipe + 1 + scores[*recipe]) % scores.len();
|
||||
}
|
||||
}
|
||||
|
||||
if scores[scores.len() - 6..] != input[..] {
|
||||
println!("{}", scores.len() - 7)
|
||||
} else {
|
||||
println!("{}", scores.len() - 8)
|
||||
}
|
||||
// 20227890 too high
|
||||
}
|
||||
488
src/tasks/day15.rs
Normal file
488
src/tasks/day15.rs
Normal file
@@ -0,0 +1,488 @@
|
||||
use crate::utils;
|
||||
use std::collections::HashMap;
|
||||
use std::collections::HashSet;
|
||||
use std::collections::VecDeque;
|
||||
use std::fmt::Display;
|
||||
|
||||
const HEALTH: i32 = 200;
|
||||
|
||||
pub fn task1() {
|
||||
let input = utils::read_file("input/day15.txt");
|
||||
let mut game = Game::from_input(&input.lines().collect(), 3, 3);
|
||||
println!("{}", game);
|
||||
let mut round = 0;
|
||||
while game.round() {
|
||||
round += 1;
|
||||
// println!("{}", game);
|
||||
// println!("round was {}", round);
|
||||
}
|
||||
println!("Final full round was {}", round);
|
||||
println!(
|
||||
"Result: {}",
|
||||
game.units.iter().map(|it| it.health).sum::<i32>() * round
|
||||
);
|
||||
}
|
||||
|
||||
pub fn task2() {
|
||||
let input = utils::read_file("input/day15.txt");
|
||||
let input = input.lines().collect();
|
||||
let mut highest_fail = 3;
|
||||
let mut lowest_win = None::<i32>;
|
||||
while lowest_win.is_none() || lowest_win.unwrap() - 1 > highest_fail {
|
||||
let attack = match lowest_win {
|
||||
Some(upper) => highest_fail + (upper - highest_fail) / 2,
|
||||
None => 2 * highest_fail,
|
||||
};
|
||||
let mut game = Game::from_input(&input, 3, attack);
|
||||
let initial_elve_count = game
|
||||
.units
|
||||
.iter()
|
||||
.filter(|unit| unit.warrior_type == WarriorType::Elve)
|
||||
.count();
|
||||
let mut round = 0;
|
||||
while game.round() {
|
||||
round += 1;
|
||||
}
|
||||
if game
|
||||
.units
|
||||
.iter()
|
||||
.filter(|unit| unit.warrior_type == WarriorType::Elve)
|
||||
.count()
|
||||
== initial_elve_count
|
||||
{
|
||||
lowest_win = Some(attack);
|
||||
} else {
|
||||
highest_fail = attack;
|
||||
}
|
||||
println!(
|
||||
"Result: {}",
|
||||
game.units.iter().map(|it| it.health).sum::<i32>() * round
|
||||
);
|
||||
}
|
||||
println!("Searching stopped with lowest win {:?}", lowest_win); // 7169 too low
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq)]
|
||||
enum Tile {
|
||||
Empty,
|
||||
Wall,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Debug)]
|
||||
enum WarriorType {
|
||||
Elve,
|
||||
Goblin,
|
||||
}
|
||||
|
||||
impl WarriorType {
|
||||
fn enemy_type(&self) -> Self {
|
||||
use self::WarriorType::*;
|
||||
match self {
|
||||
Elve => Goblin,
|
||||
Goblin => Elve,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
|
||||
struct Position(usize, usize);
|
||||
|
||||
impl Position {
|
||||
fn neighbors(&self, width: usize, height: usize) -> Vec<Position> {
|
||||
vec![
|
||||
(self.0 as isize, self.1 as isize - 1),
|
||||
(self.0 as isize - 1, self.1 as isize),
|
||||
(self.0 as isize + 1, self.1 as isize),
|
||||
(self.0 as isize, self.1 as isize + 1),
|
||||
]
|
||||
.into_iter()
|
||||
.filter(|p| p.0 > 0 && p.0 < width as isize - 1 && p.1 > 0 && p.1 < height as isize - 1)
|
||||
.map(|it| Position(it.0 as usize, it.1 as usize))
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn manhattan_distance(&self, other: &Self) -> usize {
|
||||
let a = if self.0 > other.0 {
|
||||
self.0 - other.0
|
||||
} else {
|
||||
other.0 - self.0
|
||||
};
|
||||
let b = if self.1 > other.1 {
|
||||
self.1 - other.1
|
||||
} else {
|
||||
other.1 - self.1
|
||||
};
|
||||
a + b
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd for Position {
|
||||
fn partial_cmp(&self, other: &Self) -> std::option::Option<std::cmp::Ordering> {
|
||||
if self.1 == other.1 {
|
||||
Some(self.0.cmp(&other.0))
|
||||
} else {
|
||||
Some(self.1.cmp(&other.1))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Ord for Position {
|
||||
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
|
||||
if self.1 == other.1 {
|
||||
self.0.cmp(&other.0)
|
||||
} else {
|
||||
self.1.cmp(&other.1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Warrior {
|
||||
warrior_type: WarriorType,
|
||||
position: Position,
|
||||
health: i32,
|
||||
attack: i32,
|
||||
}
|
||||
|
||||
struct Game {
|
||||
units: Vec<Warrior>,
|
||||
/// [x, y]
|
||||
tiles: Vec<Vec<Tile>>,
|
||||
width: usize,
|
||||
height: usize,
|
||||
}
|
||||
|
||||
impl Game {
|
||||
fn closest_fighting_position(
|
||||
&self,
|
||||
from: Position,
|
||||
target_type: WarriorType,
|
||||
) -> Option<Position> {
|
||||
let mut map = Map::from_game(self, from);
|
||||
|
||||
for unit in self.units.iter() {
|
||||
if unit.warrior_type == target_type {
|
||||
for neighbor in unit.position.neighbors(self.width, self.height) {
|
||||
if map.fields[neighbor.0][neighbor.1] == MapTile::Empty {
|
||||
map.fields[neighbor.0][neighbor.1] = MapTile::TargetNonOccupied;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
map.find_closest_target(from)
|
||||
}
|
||||
|
||||
fn next_position(&self, from: Position, to: Position) -> Option<Position> {
|
||||
if from == to {
|
||||
return Some(from);
|
||||
}
|
||||
// let input = vec![
|
||||
// (1, Position(from.0, from.1 - 1)),
|
||||
// (2, Position(from.0 - 1, from.1)),
|
||||
// (3, Position(from.0 + 1, from.1)),
|
||||
// (4, Position(from.0, from.1 + 1)),
|
||||
// ];
|
||||
// if let Some((_, best)) = input
|
||||
// .iter()
|
||||
// .filter_map(|(delta, start)| {
|
||||
// let map = Map::from_game(&self, from);
|
||||
// if let Some(path) = map.shortest_path(*start, to) {
|
||||
// Some((delta + path.len() * 10, *path.first().unwrap_or(start)))
|
||||
// } else {
|
||||
// None
|
||||
// }
|
||||
// })
|
||||
// .min_by_key(|(d, _)| *d)
|
||||
// {
|
||||
// Some(best)
|
||||
// } else {
|
||||
// None
|
||||
// }
|
||||
let map = Map::from_game(self, from);
|
||||
map.shortest_path(from, to)
|
||||
.map(|path| *path.get(1).unwrap_or(&from))
|
||||
}
|
||||
|
||||
/// Returns true if a full round was played, false if the round aborted because all
|
||||
/// enemies of one party are dead
|
||||
fn round(&mut self) -> bool {
|
||||
self.units.sort_unstable_by_key(|it| it.position);
|
||||
|
||||
let mut curr = 0;
|
||||
while curr < self.units.len() {
|
||||
if !self
|
||||
.units
|
||||
.iter()
|
||||
.any(|warrior| warrior.warrior_type == self.units[curr].warrior_type.enemy_type())
|
||||
{
|
||||
println!("There are no enemies anymore!");
|
||||
return false;
|
||||
}
|
||||
|
||||
// movement phase
|
||||
if let Some(next_target_position) = self.closest_fighting_position(
|
||||
self.units[curr].position,
|
||||
self.units[curr].warrior_type.enemy_type(),
|
||||
) {
|
||||
if self.units[curr].position != next_target_position {
|
||||
if let Some(next_position) =
|
||||
self.next_position(self.units[curr].position, next_target_position)
|
||||
{
|
||||
// println!(
|
||||
// "{:?} moves to {:?} via {:?}",
|
||||
// self.units[curr].position, next_target_position, next_position
|
||||
// );
|
||||
self.units[curr].position = next_position;
|
||||
} else {
|
||||
panic!("We have a reachable target but no path to it! {:?} wants to go to {:?}", self.units[curr], next_target_position);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// attack phase
|
||||
let neighbors = self.units[curr].position.neighbors(self.width, self.height);
|
||||
let mut close_enemies: Vec<usize> = self
|
||||
.units
|
||||
.iter()
|
||||
.enumerate()
|
||||
.filter(|(_, it)| it.warrior_type == self.units[curr].warrior_type.enemy_type())
|
||||
.filter(|(_, it)| neighbors.contains(&it.position))
|
||||
.map(|(i, _)| i)
|
||||
.collect();
|
||||
close_enemies.sort_unstable_by(|a, b| {
|
||||
let a = &self.units[*a];
|
||||
let b = &self.units[*b];
|
||||
if a.health == b.health {
|
||||
a.position.cmp(&b.position)
|
||||
} else {
|
||||
a.health.cmp(&b.health)
|
||||
}
|
||||
});
|
||||
if let Some(closest_index) = close_enemies.first() {
|
||||
if self.units[*closest_index]
|
||||
.position
|
||||
.manhattan_distance(&self.units[curr].position)
|
||||
> 1
|
||||
{
|
||||
panic!("Distance WTF")
|
||||
}
|
||||
let attack = self.units[curr].attack;
|
||||
let enemy = &mut self.units[*closest_index];
|
||||
enemy.health -= attack;
|
||||
if enemy.health <= 0 {
|
||||
let enemy = self.units.remove(*closest_index);
|
||||
if *closest_index < curr {
|
||||
curr -= 1;
|
||||
}
|
||||
self.tiles[enemy.position.0][enemy.position.1] = Tile::Empty;
|
||||
}
|
||||
}
|
||||
curr += 1;
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
fn from_input(input: &Vec<&str>, goblin_attack: i32, elve_attack: i32) -> Self {
|
||||
use self::Tile::*;
|
||||
use self::WarriorType::*;
|
||||
let width = input[0].len();
|
||||
let height = input.len();
|
||||
let mut inner_vec = Vec::new();
|
||||
inner_vec.resize(height, Empty);
|
||||
let mut tiles = Vec::new();
|
||||
tiles.resize(width, inner_vec);
|
||||
|
||||
let mut units = Vec::new();
|
||||
for (y, line) in input.iter().enumerate() {
|
||||
for (x, c) in line.chars().enumerate() {
|
||||
tiles[x][y] = match c {
|
||||
'.' => Empty,
|
||||
'#' => Wall,
|
||||
'E' => {
|
||||
units.push(Warrior {
|
||||
warrior_type: Elve,
|
||||
position: Position(x, y),
|
||||
health: HEALTH,
|
||||
attack: elve_attack,
|
||||
});
|
||||
Empty
|
||||
}
|
||||
'G' => {
|
||||
units.push(Warrior {
|
||||
warrior_type: Goblin,
|
||||
position: Position(x, y),
|
||||
health: HEALTH,
|
||||
attack: goblin_attack,
|
||||
});
|
||||
Empty
|
||||
}
|
||||
c => panic!("Unexpected input character '{}'", c),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Game {
|
||||
units,
|
||||
tiles,
|
||||
width,
|
||||
height,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Game {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
|
||||
use self::Tile::*;
|
||||
for y in 0..self.height {
|
||||
let mut line = String::with_capacity(self.width);
|
||||
for x in 0..self.width {
|
||||
if let Some(warrior) = self.units.iter().find(|it| it.position == Position(x, y)) {
|
||||
line.push(match warrior.warrior_type {
|
||||
WarriorType::Elve => 'E',
|
||||
WarriorType::Goblin => 'G',
|
||||
});
|
||||
} else {
|
||||
line.push(match &self.tiles[x][y] {
|
||||
Empty => '.',
|
||||
Wall => '#',
|
||||
});
|
||||
}
|
||||
}
|
||||
f.write_str(&line)?;
|
||||
f.write_str("\n")?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Map {
|
||||
fields: Vec<Vec<MapTile>>,
|
||||
width: usize,
|
||||
height: usize,
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Debug)]
|
||||
enum MapTile {
|
||||
Empty,
|
||||
TargetNonOccupied,
|
||||
Occupied,
|
||||
}
|
||||
|
||||
impl Display for Map {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
|
||||
use self::MapTile::*;
|
||||
for y in 0..self.height {
|
||||
let mut line = String::with_capacity(self.width);
|
||||
for x in 0..self.width {
|
||||
line.push(match &self.fields[x][y] {
|
||||
Empty => '.',
|
||||
Occupied => 'X',
|
||||
TargetNonOccupied => 'o',
|
||||
});
|
||||
}
|
||||
f.write_str(&line)?;
|
||||
f.write_str("\n")?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Map {
|
||||
fn from_game(game: &Game, clear: Position) -> Self {
|
||||
let mut fields = Vec::with_capacity(game.width);
|
||||
for x in 0..game.width {
|
||||
let mut new = Vec::with_capacity(game.height);
|
||||
for y in 0..game.height {
|
||||
new.push(match &game.tiles[x][y] {
|
||||
Tile::Empty => MapTile::Empty,
|
||||
Tile::Wall => MapTile::Occupied,
|
||||
});
|
||||
}
|
||||
fields.push(new);
|
||||
}
|
||||
for warrior in game.units.iter() {
|
||||
fields[warrior.position.0][warrior.position.1] = MapTile::Occupied;
|
||||
}
|
||||
fields[clear.0][clear.1] = MapTile::Empty;
|
||||
Map {
|
||||
fields,
|
||||
width: game.width,
|
||||
height: game.height,
|
||||
}
|
||||
}
|
||||
|
||||
fn shortest_path(&self, from: Position, to: Position) -> Option<Vec<Position>> {
|
||||
if to == from {
|
||||
return Some(vec![]);
|
||||
}
|
||||
if self.fields[from.0][from.1] != MapTile::Empty {
|
||||
return None;
|
||||
}
|
||||
let mut open: VecDeque<(Option<Position>, Position)> = VecDeque::new();
|
||||
open.push_back((None, from));
|
||||
let mut predecessors: HashMap<Position, Option<Position>> = HashMap::new();
|
||||
|
||||
while let Some((predecessor, curr_pos)) = open.pop_front() {
|
||||
predecessors.insert(curr_pos, predecessor);
|
||||
if curr_pos == to {
|
||||
break;
|
||||
}
|
||||
if self.fields[curr_pos.0][curr_pos.1] != MapTile::Empty {
|
||||
continue;
|
||||
}
|
||||
for pos in curr_pos.neighbors(self.width, self.height) {
|
||||
if !predecessors.contains_key(&pos) && !open.iter().any(|it| it.1 == pos) {
|
||||
open.push_back((Some(curr_pos), pos));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(Some(_)) = predecessors.get(&to) {
|
||||
let mut result: Vec<Position> = Vec::new();
|
||||
let mut current = to;
|
||||
result.push(current);
|
||||
while let Some(Some(predecessor)) = predecessors.get(¤t) {
|
||||
result.push(*predecessor);
|
||||
current = *predecessor;
|
||||
}
|
||||
result.reverse();
|
||||
Some(result)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn find_closest_target(&self, from: Position) -> Option<Position> {
|
||||
let mut open: VecDeque<(usize, Position)> = VecDeque::new();
|
||||
open.push_back((0, from));
|
||||
let mut visited: HashSet<Position> = HashSet::new();
|
||||
let mut current_found_distance = usize::max_value();
|
||||
let mut candidates: Vec<Position> = Vec::new();
|
||||
|
||||
while let Some((curr_dist, curr_pos)) = open.pop_front() {
|
||||
if curr_dist > current_found_distance {
|
||||
break;
|
||||
}
|
||||
if self.fields[curr_pos.0][curr_pos.1] == MapTile::TargetNonOccupied {
|
||||
candidates.push(curr_pos);
|
||||
current_found_distance = curr_dist;
|
||||
// all others would have a higher distance and therefore are not relevant
|
||||
continue;
|
||||
}
|
||||
if self.fields[curr_pos.0][curr_pos.1] == MapTile::Occupied {
|
||||
continue;
|
||||
}
|
||||
for pos in curr_pos.neighbors(self.width, self.height) {
|
||||
if !visited.contains(&pos) && !open.iter().any(|it| it.1 == pos) {
|
||||
open.push_back((curr_dist + 1, pos));
|
||||
}
|
||||
}
|
||||
visited.insert(curr_pos);
|
||||
}
|
||||
|
||||
candidates.sort_unstable();
|
||||
candidates.first().copied()
|
||||
}
|
||||
}
|
||||
630
src/tasks/day16.rs
Normal file
630
src/tasks/day16.rs
Normal file
@@ -0,0 +1,630 @@
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::ops::{BitAnd, BitOr};
|
||||
|
||||
use itertools::Itertools;
|
||||
|
||||
pub fn task1() {
|
||||
let count = include_str!("../../input/day16.txt")
|
||||
.split_once("\n\n\n\n")
|
||||
.unwrap()
|
||||
.0
|
||||
.split("\n\n")
|
||||
.map(|sample_input| parse(sample_input))
|
||||
.map(matches_count)
|
||||
.filter(|count| *count >= 3)
|
||||
.count();
|
||||
println!("Day 16 part1: {count}");
|
||||
}
|
||||
|
||||
pub fn task2() {
|
||||
let (samples, program) = include_str!("../../input/day16.txt")
|
||||
.split_once("\n\n\n\n")
|
||||
.unwrap();
|
||||
|
||||
let code_to_op_candidates = samples
|
||||
.split("\n\n")
|
||||
.map(|sample_input| parse(sample_input))
|
||||
.map(|sample| (sample.1.opcode, matches_ops(sample)))
|
||||
.into_group_map_by(|x| x.0);
|
||||
|
||||
// let code_to_op: HashMap<usize, HashSet<Op>> =
|
||||
let mut code_to_op_candidates: HashMap<_, _> = code_to_op_candidates
|
||||
.into_iter()
|
||||
.map(|(code, ops)| {
|
||||
let mut set: HashSet<_> = HashSet::from_iter(OPS.iter().map(ToOwned::to_owned));
|
||||
for (_, candidate_set) in ops {
|
||||
set = set
|
||||
.intersection(&candidate_set)
|
||||
.map(ToOwned::to_owned)
|
||||
.collect();
|
||||
}
|
||||
|
||||
(code, set)
|
||||
})
|
||||
.collect();
|
||||
|
||||
let mut codes_to_op: HashMap<usize, Op> = HashMap::new();
|
||||
loop {
|
||||
let single = code_to_op_candidates.iter().find(|(_, ops)| ops.len() == 1);
|
||||
let Some(single) = single else {
|
||||
break;
|
||||
};
|
||||
|
||||
let code = *single.0;
|
||||
let op = *single.1.iter().next().unwrap();
|
||||
|
||||
codes_to_op.insert(code, op);
|
||||
|
||||
code_to_op_candidates.iter_mut().for_each(|(_, ops)| {
|
||||
ops.remove(&op);
|
||||
});
|
||||
}
|
||||
|
||||
if codes_to_op.len() != OPS.len() {
|
||||
panic!("Bad final opcode assignments: {codes_to_op:?}");
|
||||
}
|
||||
|
||||
let program: Vec<Instruction> = program.lines().map(parse_instruction).collect();
|
||||
|
||||
let mut registers = Registers([0, 0, 0, 0]);
|
||||
for instruction in program {
|
||||
let op: Op = codes_to_op[&instruction.opcode];
|
||||
registers = op.process(registers, instruction);
|
||||
}
|
||||
|
||||
println!("Day 16 part 2: {}", registers.0[0]);
|
||||
}
|
||||
|
||||
fn parse(sample: &str) -> Sample {
|
||||
let (before, instruction, after) = sample.lines().collect_tuple().unwrap();
|
||||
let before: Vec<_> = before
|
||||
.trim_start_matches("Before: [")
|
||||
.trim_end_matches("]")
|
||||
.split(", ")
|
||||
.collect();
|
||||
let before = Registers::from(before);
|
||||
let after: Vec<_> = after
|
||||
.trim_start_matches("After: [")
|
||||
.trim_end_matches("]")
|
||||
.split(", ")
|
||||
.collect();
|
||||
let after = Registers::from(after);
|
||||
let instruction = parse_instruction(instruction);
|
||||
|
||||
Sample(before, instruction, after)
|
||||
}
|
||||
|
||||
fn parse_instruction(instruction: &str) -> Instruction {
|
||||
let instruction: Vec<usize> = instruction.split(" ").map(|x| x.parse().unwrap()).collect();
|
||||
let instruction = Instruction {
|
||||
opcode: instruction[0],
|
||||
a: instruction[1],
|
||||
b: instruction[2],
|
||||
c: instruction[3],
|
||||
};
|
||||
instruction
|
||||
}
|
||||
|
||||
fn matches(sample: Sample, op: Op) -> bool {
|
||||
op.process(sample.0, sample.1) == sample.2
|
||||
}
|
||||
|
||||
fn matches_count(sample: Sample) -> usize {
|
||||
let vec = OPS.iter().filter(|op| matches(sample, **op)).collect_vec();
|
||||
vec.len()
|
||||
}
|
||||
|
||||
fn matches_ops(sample: Sample) -> HashSet<Op> {
|
||||
OPS.iter()
|
||||
.filter(|op| matches(sample, **op))
|
||||
.map(|op| op.to_owned())
|
||||
.collect()
|
||||
}
|
||||
|
||||
const OPS: &[Op] = &[
|
||||
Op::AddR,
|
||||
Op::AddI,
|
||||
Op::MulR,
|
||||
Op::MulI,
|
||||
Op::BanR,
|
||||
Op::BanI,
|
||||
Op::BorR,
|
||||
Op::BorI,
|
||||
Op::SetR,
|
||||
Op::SetI,
|
||||
Op::GtIR,
|
||||
Op::GtRI,
|
||||
Op::GtRR,
|
||||
Op::EqIR,
|
||||
Op::EqRI,
|
||||
Op::EqRR,
|
||||
];
|
||||
|
||||
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
|
||||
enum Op {
|
||||
AddR,
|
||||
AddI,
|
||||
MulR,
|
||||
MulI,
|
||||
BanR,
|
||||
BanI,
|
||||
BorR,
|
||||
BorI,
|
||||
SetR,
|
||||
SetI,
|
||||
GtIR,
|
||||
GtRI,
|
||||
GtRR,
|
||||
EqIR,
|
||||
EqRI,
|
||||
EqRR,
|
||||
}
|
||||
|
||||
impl Op {
|
||||
fn process(&self, registers: Registers, instruction: Instruction) -> Registers {
|
||||
let mut result = registers.0.clone();
|
||||
|
||||
match self {
|
||||
Op::AddR => {
|
||||
result[instruction.c] = result[instruction.a] + result[instruction.b];
|
||||
}
|
||||
Op::AddI => {
|
||||
result[instruction.c] = result[instruction.a] + instruction.b as i32;
|
||||
}
|
||||
Op::MulR => {
|
||||
result[instruction.c] = result[instruction.a] * result[instruction.b];
|
||||
}
|
||||
Op::MulI => {
|
||||
result[instruction.c] = result[instruction.a] * instruction.b as i32;
|
||||
}
|
||||
Op::BanR => {
|
||||
result[instruction.c] = result[instruction.a].bitand(result[instruction.b]);
|
||||
}
|
||||
Op::BanI => {
|
||||
result[instruction.c] = result[instruction.a].bitand(instruction.b as i32);
|
||||
}
|
||||
Op::BorR => {
|
||||
result[instruction.c] = result[instruction.a].bitor(result[instruction.b]);
|
||||
}
|
||||
Op::BorI => {
|
||||
result[instruction.c] = result[instruction.a].bitor(instruction.b as i32);
|
||||
}
|
||||
Op::SetR => {
|
||||
result[instruction.c] = result[instruction.a];
|
||||
}
|
||||
Op::SetI => {
|
||||
result[instruction.c] = instruction.a as i32;
|
||||
}
|
||||
Op::GtIR => {
|
||||
result[instruction.c] = if instruction.a as i32 > result[instruction.b] {
|
||||
1
|
||||
} else {
|
||||
0
|
||||
}
|
||||
}
|
||||
Op::GtRI => {
|
||||
result[instruction.c] = if result[instruction.a] > instruction.b as i32 {
|
||||
1
|
||||
} else {
|
||||
0
|
||||
}
|
||||
}
|
||||
Op::GtRR => {
|
||||
result[instruction.c] = if result[instruction.a] > result[instruction.b] {
|
||||
1
|
||||
} else {
|
||||
0
|
||||
}
|
||||
}
|
||||
Op::EqIR => {
|
||||
result[instruction.c] = if instruction.a as i32 == result[instruction.b] {
|
||||
1
|
||||
} else {
|
||||
0
|
||||
}
|
||||
}
|
||||
Op::EqRI => {
|
||||
result[instruction.c] = if result[instruction.a] == instruction.b as i32 {
|
||||
1
|
||||
} else {
|
||||
0
|
||||
}
|
||||
}
|
||||
Op::EqRR => {
|
||||
result[instruction.c] = if result[instruction.a] == result[instruction.b] {
|
||||
1
|
||||
} else {
|
||||
0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Registers(result)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
struct Sample(Registers, Instruction, Registers);
|
||||
|
||||
#[derive(Eq, PartialEq, Copy, Clone, Debug)]
|
||||
struct Registers([i32; 4]);
|
||||
|
||||
impl From<Vec<&str>> for Registers {
|
||||
fn from(value: Vec<&str>) -> Self {
|
||||
let values: Vec<_> = value.iter().map(|x| x.parse().unwrap()).collect();
|
||||
Registers([values[0], values[1], values[2], values[3]])
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
struct Instruction {
|
||||
opcode: usize,
|
||||
a: usize,
|
||||
b: usize,
|
||||
c: usize,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use crate::tasks::day16::{matches_count, parse, Instruction, Op, Registers};
|
||||
|
||||
#[test]
|
||||
fn example1() {
|
||||
let input = "Before: [3, 2, 1, 1]\n\
|
||||
9 2 1 2\n\
|
||||
After: [3, 2, 2, 1]";
|
||||
assert_eq!(matches_count(parse(input)), 3);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[allow(non_snake_case)]
|
||||
fn test_AddR() {
|
||||
let op = Op::AddR;
|
||||
let result = op.process(
|
||||
Registers([3, 4, 3, 4]),
|
||||
Instruction {
|
||||
opcode: 0,
|
||||
a: 0,
|
||||
b: 1,
|
||||
c: 3,
|
||||
},
|
||||
);
|
||||
assert_eq!(7, result.0[3]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[allow(non_snake_case)]
|
||||
fn test_AddI() {
|
||||
let op = Op::AddI;
|
||||
let result = op.process(
|
||||
Registers([1, 2, 3, 4]),
|
||||
Instruction {
|
||||
opcode: 0,
|
||||
a: 0,
|
||||
b: 1337,
|
||||
c: 3,
|
||||
},
|
||||
);
|
||||
assert_eq!(1338, result.0[3]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[allow(non_snake_case)]
|
||||
fn test_MulR() {
|
||||
let op = Op::MulR;
|
||||
let result = op.process(
|
||||
Registers([1, 2, 3, 4]),
|
||||
Instruction {
|
||||
opcode: 0,
|
||||
a: 1,
|
||||
b: 2,
|
||||
c: 3,
|
||||
},
|
||||
);
|
||||
assert_eq!(6, result.0[3]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[allow(non_snake_case)]
|
||||
fn test_MulI() {
|
||||
let op = Op::MulI;
|
||||
let result = op.process(
|
||||
Registers([1, 2, 3, 4]),
|
||||
Instruction {
|
||||
opcode: 0,
|
||||
a: 1,
|
||||
b: 1337,
|
||||
c: 3,
|
||||
},
|
||||
);
|
||||
assert_eq!(2 * 1337, result.0[3]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[allow(non_snake_case)]
|
||||
fn test_BanR() {
|
||||
let op = Op::BanR;
|
||||
let result = op.process(
|
||||
Registers([0x10101, 0x10110, 3, 4]),
|
||||
Instruction {
|
||||
opcode: 0,
|
||||
a: 0,
|
||||
b: 1,
|
||||
c: 3,
|
||||
},
|
||||
);
|
||||
assert_eq!(0x10100, result.0[3]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[allow(non_snake_case)]
|
||||
fn test_BanI() {
|
||||
let op = Op::BanI;
|
||||
let result = op.process(
|
||||
Registers([0x10101, 2, 3, 4]),
|
||||
Instruction {
|
||||
opcode: 0,
|
||||
a: 0,
|
||||
b: 0x10110,
|
||||
c: 3,
|
||||
},
|
||||
);
|
||||
assert_eq!(0x10100, result.0[3]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[allow(non_snake_case)]
|
||||
fn test_BorR() {
|
||||
let op = Op::BorR;
|
||||
let result = op.process(
|
||||
Registers([0x10101, 0x10110, 3, 4]),
|
||||
Instruction {
|
||||
opcode: 0,
|
||||
a: 0,
|
||||
b: 1,
|
||||
c: 3,
|
||||
},
|
||||
);
|
||||
assert_eq!(0x10111, result.0[3]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[allow(non_snake_case)]
|
||||
fn test_BorI() {
|
||||
let op = Op::BorI;
|
||||
let result = op.process(
|
||||
Registers([0x10101, 2, 3, 4]),
|
||||
Instruction {
|
||||
opcode: 0,
|
||||
a: 0,
|
||||
b: 0x10110,
|
||||
c: 3,
|
||||
},
|
||||
);
|
||||
assert_eq!(0x10111, result.0[3]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[allow(non_snake_case)]
|
||||
fn test_SetR() {
|
||||
let op = Op::SetR;
|
||||
let result = op.process(
|
||||
Registers([1, 2, 3, 4]),
|
||||
Instruction {
|
||||
opcode: 0,
|
||||
a: 1,
|
||||
b: 1,
|
||||
c: 3,
|
||||
},
|
||||
);
|
||||
assert_eq!(2, result.0[3]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[allow(non_snake_case)]
|
||||
fn test_SetI() {
|
||||
let op = Op::SetI;
|
||||
let result = op.process(
|
||||
Registers([1, 2, 3, 4]),
|
||||
Instruction {
|
||||
opcode: 0,
|
||||
a: 1234,
|
||||
b: 1,
|
||||
c: 3,
|
||||
},
|
||||
);
|
||||
assert_eq!(1234, result.0[3]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[allow(non_snake_case)]
|
||||
fn test_GtIR_true() {
|
||||
let op = Op::GtIR;
|
||||
let result = op.process(
|
||||
Registers([1, 29, 3, 4]),
|
||||
Instruction {
|
||||
opcode: 0,
|
||||
a: 30,
|
||||
b: 1,
|
||||
c: 3,
|
||||
},
|
||||
);
|
||||
assert_eq!(1, result.0[3]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[allow(non_snake_case)]
|
||||
fn test_GtIR_false() {
|
||||
let op = Op::GtIR;
|
||||
let result = op.process(
|
||||
Registers([1, 1337, 3, 4]),
|
||||
Instruction {
|
||||
opcode: 0,
|
||||
a: 1337,
|
||||
b: 1,
|
||||
c: 3,
|
||||
},
|
||||
);
|
||||
assert_eq!(0, result.0[3]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[allow(non_snake_case)]
|
||||
fn test_GtRI_true() {
|
||||
let op = Op::GtRI;
|
||||
let result = op.process(
|
||||
Registers([1, 2, 3, 4]),
|
||||
Instruction {
|
||||
opcode: 0,
|
||||
a: 2,
|
||||
b: 1,
|
||||
c: 3,
|
||||
},
|
||||
);
|
||||
assert_eq!(1, result.0[3]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[allow(non_snake_case)]
|
||||
fn test_GtRI_false() {
|
||||
let op = Op::GtRI;
|
||||
let result = op.process(
|
||||
Registers([1, 2, 3, 4]),
|
||||
Instruction {
|
||||
opcode: 0,
|
||||
a: 2,
|
||||
b: 3,
|
||||
c: 3,
|
||||
},
|
||||
);
|
||||
assert_eq!(0, result.0[3]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[allow(non_snake_case)]
|
||||
fn test_GtRR_true() {
|
||||
let op = Op::GtRR;
|
||||
let result = op.process(
|
||||
Registers([1, 2, 3, 4]),
|
||||
Instruction {
|
||||
opcode: 0,
|
||||
a: 1,
|
||||
b: 0,
|
||||
c: 3,
|
||||
},
|
||||
);
|
||||
assert_eq!(1, result.0[3]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[allow(non_snake_case)]
|
||||
fn test_GtRR() {
|
||||
let op = Op::GtRR;
|
||||
let result = op.process(
|
||||
Registers([1, 2, 3, 4]),
|
||||
Instruction {
|
||||
opcode: 0,
|
||||
a: 1,
|
||||
b: 1,
|
||||
c: 3,
|
||||
},
|
||||
);
|
||||
assert_eq!(0, result.0[3]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[allow(non_snake_case)]
|
||||
fn test_EqIR_true() {
|
||||
let op = Op::EqIR;
|
||||
let result = op.process(
|
||||
Registers([1, 2, 3, 4]),
|
||||
Instruction {
|
||||
opcode: 0,
|
||||
a: 1,
|
||||
b: 0,
|
||||
c: 3,
|
||||
},
|
||||
);
|
||||
assert_eq!(1, result.0[3]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[allow(non_snake_case)]
|
||||
fn test_EqIR_false() {
|
||||
let op = Op::EqIR;
|
||||
let result = op.process(
|
||||
Registers([1, 2, 3, 4]),
|
||||
Instruction {
|
||||
opcode: 0,
|
||||
a: 1,
|
||||
b: 1,
|
||||
c: 3,
|
||||
},
|
||||
);
|
||||
assert_eq!(0, result.0[3]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[allow(non_snake_case)]
|
||||
fn test_EqRI_true() {
|
||||
let op = Op::EqRI;
|
||||
let result = op.process(
|
||||
Registers([1, 2, 3, 4]),
|
||||
Instruction {
|
||||
opcode: 0,
|
||||
a: 2,
|
||||
b: 3,
|
||||
c: 3,
|
||||
},
|
||||
);
|
||||
assert_eq!(1, result.0[3]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[allow(non_snake_case)]
|
||||
fn test_EqRI_false() {
|
||||
let op = Op::EqRI;
|
||||
let result = op.process(
|
||||
Registers([1, 2, 3, 4]),
|
||||
Instruction {
|
||||
opcode: 0,
|
||||
a: 1,
|
||||
b: 1,
|
||||
c: 3,
|
||||
},
|
||||
);
|
||||
assert_eq!(0, result.0[3]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[allow(non_snake_case)]
|
||||
fn test_EqRR_true() {
|
||||
let op = Op::EqRR;
|
||||
let result = op.process(
|
||||
Registers([1, 2, 3, 4]),
|
||||
Instruction {
|
||||
opcode: 0,
|
||||
a: 1,
|
||||
b: 1,
|
||||
c: 3,
|
||||
},
|
||||
);
|
||||
assert_eq!(1, result.0[3]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[allow(non_snake_case)]
|
||||
fn test_EqRR_false() {
|
||||
let op = Op::EqRR;
|
||||
let result = op.process(
|
||||
Registers([1, 2, 3, 4]),
|
||||
Instruction {
|
||||
opcode: 0,
|
||||
a: 1,
|
||||
b: 2,
|
||||
c: 3,
|
||||
},
|
||||
);
|
||||
assert_eq!(0, result.0[3]);
|
||||
}
|
||||
}
|
||||
198
src/tasks/day17.rs
Normal file
198
src/tasks/day17.rs
Normal file
@@ -0,0 +1,198 @@
|
||||
use bmp::Image;
|
||||
use itertools::Itertools;
|
||||
use regex::Regex;
|
||||
|
||||
use crate::utils;
|
||||
use std::{collections::HashMap, fmt::Display};
|
||||
|
||||
use Tile::*;
|
||||
fn horizontal(line: &str) -> Option<(i32, i32, i32)> {
|
||||
let regex = Regex::new(r"y=(?P<y>\d+), x=(?P<x1>\d+)..(?P<x2>\d+)").unwrap();
|
||||
regex.captures(line).map(|m| {
|
||||
(
|
||||
m.name("y").unwrap().as_str().parse::<i32>().unwrap(),
|
||||
m.name("x1").unwrap().as_str().parse::<i32>().unwrap(),
|
||||
m.name("x2").unwrap().as_str().parse::<i32>().unwrap(),
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
fn vertical(line: &str) -> Option<(i32, i32, i32)> {
|
||||
let regex = Regex::new(r"x=(?P<y>\d+), y=(?P<x1>\d+)..(?P<x2>\d+)").unwrap();
|
||||
regex.captures(line).map(|m| {
|
||||
(
|
||||
m.name("y").unwrap().as_str().parse::<i32>().unwrap(),
|
||||
m.name("x1").unwrap().as_str().parse::<i32>().unwrap(),
|
||||
m.name("x2").unwrap().as_str().parse::<i32>().unwrap(),
|
||||
)
|
||||
})
|
||||
}
|
||||
pub fn task1() {
|
||||
let input = utils::read_file("input/day17.txt");
|
||||
let mut clay_tiles: HashMap<Pos, Tile> =
|
||||
input.lines().fold(HashMap::new(), |mut tiles, line| {
|
||||
if let Some((x, y1, y2)) = vertical(line) {
|
||||
for y in y1..=y2 {
|
||||
tiles.insert(Pos(x, y), Clay);
|
||||
}
|
||||
}
|
||||
if let Some((y, x1, x2)) = horizontal(line) {
|
||||
for x in x1..=x2 {
|
||||
tiles.insert(Pos(x, y), Clay);
|
||||
}
|
||||
}
|
||||
tiles
|
||||
});
|
||||
let (y_min, y_max) = clay_tiles
|
||||
.keys()
|
||||
.map(|p| p.1)
|
||||
.minmax()
|
||||
.into_option()
|
||||
.unwrap();
|
||||
|
||||
flow(&mut clay_tiles, y_max, Pos(500, 0), Pos(500, 0));
|
||||
|
||||
let water_count = clay_tiles
|
||||
.iter()
|
||||
.filter(|(_, tile)| **tile == StuckWater || **tile == FallingWater)
|
||||
.filter(|(p, _)| (y_min..=y_max).contains(&p.1))
|
||||
.count();
|
||||
println!("part 1 water count: {water_count}");
|
||||
// print_tiles(&clay_tiles);
|
||||
// 30605 too low
|
||||
print_bmp(&clay_tiles);
|
||||
|
||||
let stuck_water = clay_tiles
|
||||
.iter()
|
||||
.filter(|(_, tile)| **tile == StuckWater)
|
||||
.filter(|(p, _)| (y_min..=y_max).contains(&p.1))
|
||||
.count();
|
||||
println!("part 2 water count: {stuck_water}");
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
fn print_tiles(tiles: &HashMap<Pos, Tile>) {
|
||||
let (x_min, x_max) = tiles.keys().map(|p| p.0).minmax().into_option().unwrap();
|
||||
let (_y_min, y_max) = tiles.keys().map(|p| p.1).minmax().into_option().unwrap();
|
||||
|
||||
for y in 0..=y_max {
|
||||
for x in x_min..=x_max {
|
||||
let s = match tiles.get(&Pos(x, y)) {
|
||||
Some(t) => format!("{t}"),
|
||||
None => " ".to_string(),
|
||||
};
|
||||
print!("{s}");
|
||||
}
|
||||
print!("\n");
|
||||
}
|
||||
}
|
||||
|
||||
fn print_bmp(tiles: &HashMap<Pos, Tile>) {
|
||||
let (x_min, x_max) = tiles.keys().map(|p| p.0).minmax().into_option().unwrap();
|
||||
let (y_min, y_max) = tiles.keys().map(|p| p.1).minmax().into_option().unwrap();
|
||||
|
||||
let mut img = Image::new((x_max - x_min + 1) as u32, (y_max - y_min + 1) as u32);
|
||||
for y in 0..=y_max {
|
||||
for x in x_min..=x_max {
|
||||
let color = match tiles.get(&Pos(x, y)) {
|
||||
Some(t) => match t {
|
||||
Clay => bmp::consts::BROWN,
|
||||
FallingWater => bmp::consts::LIGHT_BLUE,
|
||||
StuckWater => bmp::consts::DARK_BLUE,
|
||||
},
|
||||
None => bmp::consts::WHITE,
|
||||
};
|
||||
img.set_pixel((x - x_min) as u32, (y - y_min) as u32, color);
|
||||
}
|
||||
}
|
||||
img.save("final.bmp").unwrap();
|
||||
}
|
||||
|
||||
/// returns true iff going left/right and hit a wall
|
||||
fn flow(tiles: &mut HashMap<Pos, Tile>, y_max: i32, pos: Pos, from: Pos) -> bool {
|
||||
if pos.1 > y_max {
|
||||
return false;
|
||||
}
|
||||
if let Some(Clay) = tiles.get(&pos) {
|
||||
return true;
|
||||
}
|
||||
if let Some(StuckWater) = tiles.get(&pos) {
|
||||
return true;
|
||||
}
|
||||
if tiles.contains_key(&pos) {
|
||||
return false;
|
||||
}
|
||||
|
||||
tiles.insert(pos, FallingWater);
|
||||
// println!();
|
||||
// print_tiles(tiles);
|
||||
if flow(tiles, y_max, pos.down(), pos) {
|
||||
let bumped_left = flow(tiles, y_max, pos.left(), pos);
|
||||
let bumped_right = flow(tiles, y_max, pos.right(), pos);
|
||||
if from.down() == pos {
|
||||
if bumped_right && bumped_left {
|
||||
fill(tiles, pos);
|
||||
// println!();
|
||||
// print_tiles(tiles);
|
||||
return true;
|
||||
}
|
||||
} else if from.right() == pos && bumped_right {
|
||||
return true;
|
||||
} else if from.left() == pos && bumped_left {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
fn fill(tiles: &mut HashMap<Pos, Tile>, pos: Pos) {
|
||||
if let Some(FallingWater) = tiles.get(&pos) {
|
||||
tiles.insert(pos, StuckWater);
|
||||
fill(tiles, pos.left());
|
||||
fill(tiles, pos.right());
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Eq)]
|
||||
enum Tile {
|
||||
Clay,
|
||||
FallingWater,
|
||||
StuckWater,
|
||||
}
|
||||
|
||||
impl Display for Tile {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
let s = match self {
|
||||
Clay => "#",
|
||||
FallingWater => "|",
|
||||
StuckWater => "~",
|
||||
};
|
||||
f.write_str(s)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Eq, Hash, Clone, Copy)]
|
||||
struct Pos(i32, i32);
|
||||
|
||||
impl Pos {
|
||||
fn left(&self) -> Self {
|
||||
Pos(self.0 - 1, self.1)
|
||||
}
|
||||
fn right(&self) -> Self {
|
||||
Pos(self.0 + 1, self.1)
|
||||
}
|
||||
fn down(&self) -> Self {
|
||||
Pos(self.0, self.1 + 1)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn part1() {
|
||||
assert_eq!(horizontal("y=10, x=5..20"), Some((10, 5, 20)));
|
||||
assert_eq!(vertical("x=10, y=5..20"), Some((10, 5, 20)));
|
||||
}
|
||||
}
|
||||
145
src/tasks/day18.rs
Normal file
145
src/tasks/day18.rs
Normal file
@@ -0,0 +1,145 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
use itertools::Itertools;
|
||||
|
||||
use crate::utils;
|
||||
|
||||
pub fn task1() {
|
||||
let initial = load_initial_map();
|
||||
let fin = (0..10).fold(initial, |map, _| next_map(map));
|
||||
let (trees, lumberyards) = resource_value(fin);
|
||||
println!("Part 1 - {trees} x {lumberyards} = {}", trees * lumberyards);
|
||||
}
|
||||
pub fn task2() {
|
||||
let mut map = load_initial_map();
|
||||
|
||||
const MINUTES: i32 = 1000000000;
|
||||
let mut maps_at_time: HashMap<String, i32> = HashMap::new();
|
||||
let mut minute = 0;
|
||||
while minute < MINUTES {
|
||||
if let Some(time) = maps_at_time.get(&hash(&map)) {
|
||||
let delta = minute - time;
|
||||
let remaining_minutes = MINUTES - minute;
|
||||
let remaining_cycles = remaining_minutes / delta;
|
||||
minute += remaining_cycles * delta;
|
||||
}
|
||||
maps_at_time.insert(hash(&map), minute);
|
||||
minute += 1;
|
||||
map = next_map(map);
|
||||
}
|
||||
|
||||
let (trees, lumberyards) = resource_value(map);
|
||||
println!("Part 1 - {trees} x {lumberyards} = {}", trees * lumberyards);
|
||||
}
|
||||
|
||||
fn hash(map: &HashMap<Pos, char>) -> String {
|
||||
let mut result = String::new();
|
||||
let (x_min, x_max) = map.keys().map(|p| p.0).minmax().into_option().unwrap();
|
||||
let (_y_min, y_max) = map.keys().map(|p| p.1).minmax().into_option().unwrap();
|
||||
|
||||
for y in 0..=y_max {
|
||||
for x in x_min..=x_max {
|
||||
let s = map[&Pos(x, y)];
|
||||
result.push(s);
|
||||
}
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
fn resource_value(fin: HashMap<Pos, char>) -> (usize, usize) {
|
||||
let trees = fin.values().filter(|c| **c == '|').count();
|
||||
let lumberyards = fin.values().filter(|c| **c == '#').count();
|
||||
(trees, lumberyards)
|
||||
}
|
||||
|
||||
fn load_initial_map() -> HashMap<Pos, char> {
|
||||
let input = utils::read_file("input/day18.txt");
|
||||
let initial: HashMap<Pos, char> = input
|
||||
.lines()
|
||||
.enumerate()
|
||||
.flat_map(|(y, line)| {
|
||||
line.chars()
|
||||
.enumerate()
|
||||
.map(|(x, c)| (Pos(x as i32, y as i32), c))
|
||||
.collect_vec()
|
||||
})
|
||||
.collect();
|
||||
initial
|
||||
}
|
||||
|
||||
fn next_map(map: HashMap<Pos, char>) -> HashMap<Pos, char> {
|
||||
map.keys()
|
||||
.map(|p| {
|
||||
let old = map[p];
|
||||
let new = match old {
|
||||
'.' => {
|
||||
if neighbors(&map, *p)
|
||||
.into_iter()
|
||||
.filter(|c| *c == '|')
|
||||
.count()
|
||||
>= 3
|
||||
{
|
||||
'|'
|
||||
} else {
|
||||
'.'
|
||||
}
|
||||
}
|
||||
'|' => {
|
||||
if neighbors(&map, *p)
|
||||
.into_iter()
|
||||
.filter(|c| *c == '#')
|
||||
.count()
|
||||
>= 3
|
||||
{
|
||||
'#'
|
||||
} else {
|
||||
'|'
|
||||
}
|
||||
}
|
||||
'#' => {
|
||||
if neighbors(&map, *p).contains(&'#') && neighbors(&map, *p).contains(&'|') {
|
||||
'#'
|
||||
} else {
|
||||
'.'
|
||||
}
|
||||
}
|
||||
_ => panic!("unknown type"),
|
||||
};
|
||||
(*p, new)
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
fn printmap(map: &HashMap<Pos, char>) {
|
||||
println!();
|
||||
let (x_min, x_max) = map.keys().map(|p| p.0).minmax().into_option().unwrap();
|
||||
let (_y_min, y_max) = map.keys().map(|p| p.1).minmax().into_option().unwrap();
|
||||
|
||||
for y in 0..=y_max {
|
||||
for x in x_min..=x_max {
|
||||
let s = map[&Pos(x, y)];
|
||||
print!("{s}");
|
||||
}
|
||||
print!("\n");
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Hash, Eq, PartialEq, Clone, Copy)]
|
||||
struct Pos(i32, i32);
|
||||
|
||||
fn neighbors(map: &HashMap<Pos, char>, p: Pos) -> Vec<char> {
|
||||
[
|
||||
Pos(p.0 - 1, p.1 - 1),
|
||||
Pos(p.0 - 1, p.1),
|
||||
Pos(p.0 - 1, p.1 + 1),
|
||||
Pos(p.0, p.1 - 1),
|
||||
Pos(p.0, p.1 + 1),
|
||||
Pos(p.0 + 1, p.1 - 1),
|
||||
Pos(p.0 + 1, p.1),
|
||||
Pos(p.0 + 1, p.1 + 1),
|
||||
]
|
||||
.into_iter()
|
||||
.flat_map(|pos| map.get(&pos).map(|c| *c))
|
||||
.collect_vec()
|
||||
}
|
||||
243
src/tasks/day19.rs
Normal file
243
src/tasks/day19.rs
Normal file
@@ -0,0 +1,243 @@
|
||||
use std::ops::{BitAnd, BitOr};
|
||||
|
||||
pub fn task1() {
|
||||
let input = include_str!("../../input/day19.txt");
|
||||
let result = run1(input, 1);
|
||||
|
||||
println!("Day 19 part 1: {result}");
|
||||
}
|
||||
|
||||
pub fn task2() {
|
||||
let mut a = 1i64;
|
||||
let mut d = 948;
|
||||
if a == 1 {
|
||||
d += 10550400;
|
||||
a = 0;
|
||||
}
|
||||
|
||||
let mut f = 1;
|
||||
'outer: loop {
|
||||
let mut c = 1;
|
||||
'inner: loop {
|
||||
let b = f * c;
|
||||
if b == d {
|
||||
a = a + f;
|
||||
} else if b > d {
|
||||
// this is the important part: break the loop because otherwise we count and count
|
||||
// and count ... but cannot reach the b == d condition without resetting c.
|
||||
break 'inner;
|
||||
}
|
||||
c += 1;
|
||||
if c > d {
|
||||
break 'inner;
|
||||
}
|
||||
}
|
||||
f += 1;
|
||||
if f > d {
|
||||
break 'outer;
|
||||
}
|
||||
}
|
||||
|
||||
println!("Day 19 part 2: {a}");
|
||||
}
|
||||
|
||||
fn run1(input: &str, start_value: i32) -> i32 {
|
||||
let (config, program) = input.split_once("\n").unwrap();
|
||||
let ip_register: usize = config.split_once(" ").unwrap().1.parse().unwrap();
|
||||
|
||||
let program: Vec<Instruction> = program.lines().map(parse_instruction).collect();
|
||||
|
||||
let mut registers: Registers = [start_value, 0, 0, 0, 0, 0];
|
||||
let mut ip = 0;
|
||||
let mut count = 0;
|
||||
loop {
|
||||
//print!("ip={ip}, {registers:?}");
|
||||
|
||||
registers[ip_register] = ip as i32;
|
||||
let instruction = program.get(ip).unwrap();
|
||||
|
||||
if ip == 2 {
|
||||
println!("{registers:?}");
|
||||
}
|
||||
|
||||
//print!("{instruction:?}");
|
||||
|
||||
let op: Op = instruction.opcode;
|
||||
registers = op.process(registers, *instruction);
|
||||
|
||||
//println!("{registers:?}");
|
||||
|
||||
ip = registers[ip_register] as usize;
|
||||
ip += 1;
|
||||
|
||||
if program.get(ip).is_none() {
|
||||
break;
|
||||
}
|
||||
count += 1;
|
||||
}
|
||||
println!("executed instructions: {count}");
|
||||
registers[0]
|
||||
}
|
||||
|
||||
fn parse_instruction(instruction: &str) -> Instruction {
|
||||
let instruction: Vec<_> = instruction.split(" ").collect();
|
||||
let opcode = match instruction[0] {
|
||||
"addr" => Op::AddR,
|
||||
"addi" => Op::AddI,
|
||||
"mulr" => Op::MulR,
|
||||
"muli" => Op::MulI,
|
||||
"banr" => Op::BanR,
|
||||
"bani" => Op::BanI,
|
||||
"borr" => Op::BorR,
|
||||
"bori" => Op::BorI,
|
||||
"setr" => Op::SetR,
|
||||
"seti" => Op::SetI,
|
||||
"gtir" => Op::GtIR,
|
||||
"gtri" => Op::GtRI,
|
||||
"gtrr" => Op::GtRR,
|
||||
"eqir" => Op::EqIR,
|
||||
"eqri" => Op::EqRI,
|
||||
"eqrr" => Op::EqRR,
|
||||
&_ => {
|
||||
panic!("unknown op {}", instruction[0])
|
||||
}
|
||||
};
|
||||
let instruction = Instruction {
|
||||
opcode,
|
||||
a: instruction[1].parse().unwrap(),
|
||||
b: instruction[2].parse().unwrap(),
|
||||
c: instruction[3].parse().unwrap(),
|
||||
};
|
||||
instruction
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
|
||||
enum Op {
|
||||
AddR,
|
||||
AddI,
|
||||
MulR,
|
||||
MulI,
|
||||
BanR,
|
||||
BanI,
|
||||
BorR,
|
||||
BorI,
|
||||
SetR,
|
||||
SetI,
|
||||
GtIR,
|
||||
GtRI,
|
||||
GtRR,
|
||||
EqIR,
|
||||
EqRI,
|
||||
EqRR,
|
||||
}
|
||||
|
||||
impl Op {
|
||||
fn process(&self, registers: Registers, instruction: Instruction) -> Registers {
|
||||
let mut result = registers.clone();
|
||||
|
||||
match self {
|
||||
Op::AddR => {
|
||||
result[instruction.c] = result[instruction.a] + result[instruction.b];
|
||||
}
|
||||
Op::AddI => {
|
||||
result[instruction.c] = result[instruction.a] + instruction.b as i32;
|
||||
}
|
||||
Op::MulR => {
|
||||
result[instruction.c] = result[instruction.a] * result[instruction.b];
|
||||
}
|
||||
Op::MulI => {
|
||||
result[instruction.c] = result[instruction.a] * instruction.b as i32;
|
||||
}
|
||||
Op::BanR => {
|
||||
result[instruction.c] = result[instruction.a].bitand(result[instruction.b]);
|
||||
}
|
||||
Op::BanI => {
|
||||
result[instruction.c] = result[instruction.a].bitand(instruction.b as i32);
|
||||
}
|
||||
Op::BorR => {
|
||||
result[instruction.c] = result[instruction.a].bitor(result[instruction.b]);
|
||||
}
|
||||
Op::BorI => {
|
||||
result[instruction.c] = result[instruction.a].bitor(instruction.b as i32);
|
||||
}
|
||||
Op::SetR => {
|
||||
result[instruction.c] = result[instruction.a];
|
||||
}
|
||||
Op::SetI => {
|
||||
result[instruction.c] = instruction.a as i32;
|
||||
}
|
||||
Op::GtIR => {
|
||||
result[instruction.c] = if instruction.a as i32 > result[instruction.b] {
|
||||
1
|
||||
} else {
|
||||
0
|
||||
}
|
||||
}
|
||||
Op::GtRI => {
|
||||
result[instruction.c] = if result[instruction.a] > instruction.b as i32 {
|
||||
1
|
||||
} else {
|
||||
0
|
||||
}
|
||||
}
|
||||
Op::GtRR => {
|
||||
result[instruction.c] = if result[instruction.a] > result[instruction.b] {
|
||||
1
|
||||
} else {
|
||||
0
|
||||
}
|
||||
}
|
||||
Op::EqIR => {
|
||||
result[instruction.c] = if instruction.a as i32 == result[instruction.b] {
|
||||
1
|
||||
} else {
|
||||
0
|
||||
}
|
||||
}
|
||||
Op::EqRI => {
|
||||
result[instruction.c] = if result[instruction.a] == instruction.b as i32 {
|
||||
1
|
||||
} else {
|
||||
0
|
||||
}
|
||||
}
|
||||
Op::EqRR => {
|
||||
result[instruction.c] = if result[instruction.a] == result[instruction.b] {
|
||||
1
|
||||
} else {
|
||||
0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
type Registers = [i32; 6];
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
struct Instruction {
|
||||
opcode: Op,
|
||||
a: usize,
|
||||
b: usize,
|
||||
c: usize,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use crate::tasks::day19::run1;
|
||||
|
||||
#[test]
|
||||
fn example1() {
|
||||
let input = "#ip 0\n\
|
||||
seti 5 0 1\n\
|
||||
seti 6 0 2\n\
|
||||
addi 0 1 0\n\
|
||||
addr 1 2 3\n\
|
||||
setr 1 0 0\n\
|
||||
seti 8 0 4\n\
|
||||
seti 9 0 5";
|
||||
assert_eq!(run1(input, 0), 6);
|
||||
}
|
||||
}
|
||||
257
src/tasks/day20.rs
Normal file
257
src/tasks/day20.rs
Normal file
@@ -0,0 +1,257 @@
|
||||
use self::Tile::*;
|
||||
#[allow(unused_imports)]
|
||||
use crate::utils;
|
||||
use std::collections::VecDeque;
|
||||
use std::collections::{HashMap, HashSet};
|
||||
|
||||
pub fn task1() {
|
||||
let input = utils::read_file("input/day20.txt");
|
||||
// let input = "^ENNWSWW(NEWS|)SSSEEN(WNSE|)EE(SWEN|)NNN$".to_string();
|
||||
let input = &input[1..];
|
||||
let mut map: HashMap<Point, Tile> = HashMap::new();
|
||||
add_default_neighbors_for_room(&mut map, Point(0, 0));
|
||||
parse_input(&mut map, input, Point(0, 0));
|
||||
|
||||
// print_map(&map);
|
||||
|
||||
println!(
|
||||
"Most distant point: {:?}",
|
||||
longest_shortest_path(&map, Point(0, 0))
|
||||
);
|
||||
println!(
|
||||
"Rooms with minimal distance >= 1000: {}",
|
||||
count_long_distances(&map, Point(0, 0), 1000)
|
||||
);
|
||||
}
|
||||
|
||||
/// Returns the end points of the parsed input
|
||||
fn parse_input(map: &mut HashMap<Point, Tile>, input: &str, position: Point) -> HashSet<Point> {
|
||||
// println!("{}, {:?}", input, position);
|
||||
if input == "$" {
|
||||
println!("End of the road.");
|
||||
return vec![position].into_iter().collect();
|
||||
}
|
||||
let mut position = position;
|
||||
let mut input = input;
|
||||
let iterator = input.chars();
|
||||
for c in iterator {
|
||||
match c {
|
||||
'(' => {
|
||||
let (parts, rest) = split_parts(input);
|
||||
let mut middle_points: HashSet<Point> = HashSet::new();
|
||||
for part in parts {
|
||||
if !part.is_empty() {
|
||||
for x in parse_input(map, part, position) {
|
||||
middle_points.insert(x);
|
||||
}
|
||||
}
|
||||
}
|
||||
let mut end_points: HashSet<Point> = HashSet::new();
|
||||
for point in middle_points {
|
||||
if !rest.is_empty() {
|
||||
for x in parse_input(map, rest, point) {
|
||||
end_points.insert(x);
|
||||
}
|
||||
}
|
||||
}
|
||||
return end_points;
|
||||
}
|
||||
'N' => {
|
||||
position = Point(position.0, position.1 - 2);
|
||||
add_default_neighbors_for_room(map, position);
|
||||
map.insert(Point(position.0, position.1 + 1), Door);
|
||||
input = &input[1..];
|
||||
}
|
||||
'E' => {
|
||||
position = Point(position.0 + 2, position.1);
|
||||
add_default_neighbors_for_room(map, position);
|
||||
map.insert(Point(position.0 - 1, position.1), Door);
|
||||
input = &input[1..];
|
||||
}
|
||||
'S' => {
|
||||
position = Point(position.0, position.1 + 2);
|
||||
add_default_neighbors_for_room(map, position);
|
||||
map.insert(Point(position.0, position.1 - 1), Door);
|
||||
input = &input[1..];
|
||||
}
|
||||
'W' => {
|
||||
position = Point(position.0 - 2, position.1);
|
||||
add_default_neighbors_for_room(map, position);
|
||||
map.insert(Point(position.0 + 1, position.1), Door);
|
||||
input = &input[1..];
|
||||
}
|
||||
'$' => break,
|
||||
c => panic!(
|
||||
"Stumbled upon a '{}' when reading input where it shouldn't be",
|
||||
c
|
||||
),
|
||||
}
|
||||
}
|
||||
vec![position].into_iter().collect()
|
||||
}
|
||||
|
||||
/// Splits the input by '|', but only by those that are not enclosed by further parenthesises.
|
||||
/// The second return value is the rest after the closing parenthesis
|
||||
fn split_parts(input: &str) -> (Vec<&str>, &str) {
|
||||
// println!("Splitting '{}'", input);
|
||||
let mut count = 0;
|
||||
let mut closing_index = None::<usize>;
|
||||
let mut last_separator = 0;
|
||||
let mut parts = Vec::new();
|
||||
for (i, c) in input.chars().enumerate() {
|
||||
match c {
|
||||
'(' => count += 1,
|
||||
')' => {
|
||||
count -= 1;
|
||||
if count == 0 {
|
||||
closing_index = Some(i);
|
||||
|
||||
parts.push(&input[last_separator + 1..i]);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
'|' => {
|
||||
// println!("| at {} (depth {})", i, count);
|
||||
if count == 1 {
|
||||
parts.push(&input[last_separator + 1..i]);
|
||||
last_separator = i;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
let closing_index =
|
||||
closing_index.unwrap_or_else(|| panic!("No matching closing parenthesis in {}", input));
|
||||
(parts, &input[closing_index + 1..])
|
||||
}
|
||||
|
||||
fn add_default_neighbors_for_room(map: &mut HashMap<Point, Tile>, position: Point) {
|
||||
map.insert(position, Room);
|
||||
for p in position.diagonals() {
|
||||
map.insert(p, Wall);
|
||||
}
|
||||
for p in position.neighbors() {
|
||||
map.entry(p).or_insert(Unknown);
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
fn print_map(map: &HashMap<Point, Tile>) {
|
||||
let xmin = map.keys().min_by_key(|it| it.0).unwrap().0;
|
||||
let xmax = map.keys().max_by_key(|it| it.0).unwrap().0;
|
||||
let ymin = map.keys().min_by_key(|it| it.1).unwrap().1;
|
||||
let ymax = map.keys().max_by_key(|it| it.1).unwrap().1;
|
||||
|
||||
for y in ymin..=ymax {
|
||||
for x in xmin..=xmax {
|
||||
if x == 0 && y == 0 {
|
||||
print!("X")
|
||||
} else {
|
||||
print!(
|
||||
"{}",
|
||||
match map.get(&Point(x, y)) {
|
||||
None => " ",
|
||||
Some(Wall) => "#",
|
||||
Some(Room) => ".",
|
||||
Some(Unknown) => "#",
|
||||
Some(Door) => {
|
||||
if y % 2 == 0 {
|
||||
"|"
|
||||
} else {
|
||||
"-"
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
println!();
|
||||
}
|
||||
}
|
||||
|
||||
fn longest_shortest_path(map: &HashMap<Point, Tile>, start: Point) -> Option<(Point, usize)> {
|
||||
let mut distances: HashMap<Point, usize> = HashMap::with_capacity(map.len());
|
||||
let mut open: VecDeque<(usize, Point)> = VecDeque::new();
|
||||
let mut visited: HashSet<Point> = HashSet::new();
|
||||
open.push_back((0, start));
|
||||
visited.insert(start);
|
||||
while let Some((distance, predecessor)) = open.pop_front() {
|
||||
distances.insert(predecessor, distance);
|
||||
for p in predecessor.neighbors() {
|
||||
if let Some(Door) = map.get(&p) {
|
||||
let room = predecessor.next_room(&p);
|
||||
if !visited.contains(&room) {
|
||||
visited.insert(room);
|
||||
open.push_back((distance + 1, room));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if let Some((point, distance)) = distances.iter().max_by_key(|it| it.1) {
|
||||
Some((*point, *distance))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn count_long_distances(map: &HashMap<Point, Tile>, start: Point, threshold: usize) -> usize {
|
||||
let mut distances: HashMap<Point, usize> = HashMap::with_capacity(map.len());
|
||||
let mut open: VecDeque<(usize, Point)> = VecDeque::new();
|
||||
let mut visited: HashSet<Point> = HashSet::new();
|
||||
open.push_back((0, start));
|
||||
visited.insert(start);
|
||||
while let Some((distance, predecessor)) = open.pop_front() {
|
||||
distances.insert(predecessor, distance);
|
||||
for p in predecessor.neighbors() {
|
||||
if let Some(Door) = map.get(&p) {
|
||||
let room = predecessor.next_room(&p);
|
||||
if !visited.contains(&room) {
|
||||
visited.insert(room);
|
||||
open.push_back((distance + 1, room));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
distances
|
||||
.iter()
|
||||
.filter(|(_, distance)| **distance >= threshold)
|
||||
.count()
|
||||
}
|
||||
|
||||
#[derive(Eq, PartialEq, Hash, Clone, Copy, Debug)]
|
||||
struct Point(i32, i32);
|
||||
|
||||
impl Point {
|
||||
fn diagonals(&self) -> Vec<Point> {
|
||||
vec![
|
||||
Point(self.0 - 1, self.1 - 1),
|
||||
Point(self.0 - 1, self.1 + 1),
|
||||
Point(self.0 + 1, self.1 - 1),
|
||||
Point(self.0 + 1, self.1 + 1),
|
||||
]
|
||||
}
|
||||
|
||||
fn neighbors(&self) -> Vec<Point> {
|
||||
vec![
|
||||
Point(self.0 - 1, self.1),
|
||||
Point(self.0 + 1, self.1),
|
||||
Point(self.0, self.1 - 1),
|
||||
Point(self.0, self.1 + 1),
|
||||
]
|
||||
}
|
||||
|
||||
fn next_room(&self, other: &Self) -> Self {
|
||||
Point(
|
||||
self.0 + 2 * (other.0 - self.0),
|
||||
self.1 + 2 * (other.1 - self.1),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
enum Tile {
|
||||
Unknown,
|
||||
Room,
|
||||
Wall,
|
||||
Door,
|
||||
}
|
||||
229
src/tasks/day21.rs
Normal file
229
src/tasks/day21.rs
Normal file
@@ -0,0 +1,229 @@
|
||||
use std::collections::HashSet;
|
||||
use std::ops::{BitAnd, BitOr};
|
||||
|
||||
pub fn task1() {
|
||||
let input = include_str!("../../input/day21.txt");
|
||||
let result = run1(input, 3007673);
|
||||
println!("{result:?}");
|
||||
}
|
||||
|
||||
fn run1(input: &str, start_value: i64) -> (i64, usize) {
|
||||
let (config, program) = input.split_once("\n").unwrap();
|
||||
let ip_register: usize = config.split_once(" ").unwrap().1.parse().unwrap();
|
||||
|
||||
let program: Vec<Instruction> = program.lines().map(parse_instruction).collect();
|
||||
|
||||
let mut registers: Registers = [start_value, 0, 0, 0, 0, 0];
|
||||
let mut ip = 0;
|
||||
let mut count = 0usize;
|
||||
let mut seen: HashSet<_> = HashSet::new();
|
||||
let mut last = 0;
|
||||
loop {
|
||||
//print!("ip={ip}, {registers:?}");
|
||||
|
||||
registers[ip_register] = ip as i64;
|
||||
let instruction = program.get(ip).unwrap();
|
||||
|
||||
//print!("{instruction:?}");
|
||||
|
||||
let op: Op = instruction.opcode;
|
||||
registers = op.process(registers, *instruction);
|
||||
|
||||
//println!("{registers:?}");
|
||||
|
||||
ip = registers[ip_register] as usize;
|
||||
ip += 1;
|
||||
|
||||
// Part 1: uncomment this and print look at register 2 to find the value for register 0
|
||||
// that would cause the program to halt
|
||||
// if ip == 28 {
|
||||
// println!("Value in register 2: {}", registers[2]);
|
||||
// }
|
||||
// Part 2: 9969507 too high
|
||||
// 16774755 highest value
|
||||
// Store all values of register 2 at the possible exit point. Once you see one you already
|
||||
// saw: you've seen all (there is a loop). The one before that was the one it took the longest
|
||||
// to reach without seeing anything twice.
|
||||
if ip == 28 {
|
||||
if seen.contains(®isters[2]) {
|
||||
println!("First double: {registers:?}");
|
||||
println!("Last was {last}");
|
||||
break;
|
||||
} else {
|
||||
seen.insert(registers[2]);
|
||||
last = registers[2];
|
||||
}
|
||||
}
|
||||
|
||||
if program.get(ip).is_none() {
|
||||
println!("exit by leaving instruction space");
|
||||
break;
|
||||
}
|
||||
count += 1;
|
||||
}
|
||||
println!("executed instructions: {count}");
|
||||
(registers[0], count)
|
||||
}
|
||||
|
||||
fn parse_instruction(instruction: &str) -> Instruction {
|
||||
let instruction: Vec<_> = instruction.split(" ").collect();
|
||||
let opcode = match instruction[0] {
|
||||
"addr" => Op::AddR,
|
||||
"addi" => Op::AddI,
|
||||
"mulr" => Op::MulR,
|
||||
"muli" => Op::MulI,
|
||||
"banr" => Op::BanR,
|
||||
"bani" => Op::BanI,
|
||||
"borr" => Op::BorR,
|
||||
"bori" => Op::BorI,
|
||||
"setr" => Op::SetR,
|
||||
"seti" => Op::SetI,
|
||||
"gtir" => Op::GtIR,
|
||||
"gtri" => Op::GtRI,
|
||||
"gtrr" => Op::GtRR,
|
||||
"eqir" => Op::EqIR,
|
||||
"eqri" => Op::EqRI,
|
||||
"eqrr" => Op::EqRR,
|
||||
&_ => {
|
||||
panic!("unknown op {}", instruction[0])
|
||||
}
|
||||
};
|
||||
let instruction = Instruction {
|
||||
opcode,
|
||||
a: instruction[1].parse().unwrap(),
|
||||
b: instruction[2].parse().unwrap(),
|
||||
c: instruction[3].parse().unwrap(),
|
||||
};
|
||||
instruction
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
|
||||
enum Op {
|
||||
AddR,
|
||||
AddI,
|
||||
MulR,
|
||||
MulI,
|
||||
BanR,
|
||||
BanI,
|
||||
BorR,
|
||||
BorI,
|
||||
SetR,
|
||||
SetI,
|
||||
GtIR,
|
||||
GtRI,
|
||||
GtRR,
|
||||
EqIR,
|
||||
EqRI,
|
||||
EqRR,
|
||||
}
|
||||
|
||||
impl Op {
|
||||
fn process(&self, registers: Registers, instruction: Instruction) -> Registers {
|
||||
let mut result = registers.clone();
|
||||
|
||||
match self {
|
||||
Op::AddR => {
|
||||
result[instruction.c] = result[instruction.a] + result[instruction.b];
|
||||
}
|
||||
Op::AddI => {
|
||||
result[instruction.c] = result[instruction.a] + instruction.b as i64;
|
||||
}
|
||||
Op::MulR => {
|
||||
result[instruction.c] = result[instruction.a] * result[instruction.b];
|
||||
}
|
||||
Op::MulI => {
|
||||
result[instruction.c] = result[instruction.a] * instruction.b as i64;
|
||||
}
|
||||
Op::BanR => {
|
||||
result[instruction.c] = result[instruction.a].bitand(result[instruction.b]);
|
||||
}
|
||||
Op::BanI => {
|
||||
result[instruction.c] = result[instruction.a].bitand(instruction.b as i64);
|
||||
}
|
||||
Op::BorR => {
|
||||
result[instruction.c] = result[instruction.a].bitor(result[instruction.b]);
|
||||
}
|
||||
Op::BorI => {
|
||||
result[instruction.c] = result[instruction.a].bitor(instruction.b as i64);
|
||||
}
|
||||
Op::SetR => {
|
||||
result[instruction.c] = result[instruction.a];
|
||||
}
|
||||
Op::SetI => {
|
||||
result[instruction.c] = instruction.a as i64;
|
||||
}
|
||||
Op::GtIR => {
|
||||
result[instruction.c] = if instruction.a as i64 > result[instruction.b] {
|
||||
1
|
||||
} else {
|
||||
0
|
||||
}
|
||||
}
|
||||
Op::GtRI => {
|
||||
result[instruction.c] = if result[instruction.a] > instruction.b as i64 {
|
||||
1
|
||||
} else {
|
||||
0
|
||||
}
|
||||
}
|
||||
Op::GtRR => {
|
||||
result[instruction.c] = if result[instruction.a] > result[instruction.b] {
|
||||
1
|
||||
} else {
|
||||
0
|
||||
}
|
||||
}
|
||||
Op::EqIR => {
|
||||
result[instruction.c] = if instruction.a as i64 == result[instruction.b] {
|
||||
1
|
||||
} else {
|
||||
0
|
||||
}
|
||||
}
|
||||
Op::EqRI => {
|
||||
result[instruction.c] = if result[instruction.a] == instruction.b as i64 {
|
||||
1
|
||||
} else {
|
||||
0
|
||||
}
|
||||
}
|
||||
Op::EqRR => {
|
||||
result[instruction.c] = if result[instruction.a] == result[instruction.b] {
|
||||
1
|
||||
} else {
|
||||
0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
type Registers = [i64; 6];
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
struct Instruction {
|
||||
opcode: Op,
|
||||
a: usize,
|
||||
b: usize,
|
||||
c: usize,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use crate::tasks::day21::run1;
|
||||
|
||||
#[test]
|
||||
fn example1() {
|
||||
let input = "#ip 0\n\
|
||||
seti 5 0 1\n\
|
||||
seti 6 0 2\n\
|
||||
addi 0 1 0\n\
|
||||
addr 1 2 3\n\
|
||||
setr 1 0 0\n\
|
||||
seti 8 0 4\n\
|
||||
seti 9 0 5";
|
||||
assert_eq!(run1(input, 0).0, 6);
|
||||
}
|
||||
}
|
||||
246
src/tasks/day22.rs
Normal file
246
src/tasks/day22.rs
Normal file
@@ -0,0 +1,246 @@
|
||||
use crate::tasks::day22::Equipment::*;
|
||||
use core::cmp::Ordering;
|
||||
use std::collections::BinaryHeap;
|
||||
use std::collections::HashMap;
|
||||
use std::time::Instant;
|
||||
|
||||
pub fn both() {
|
||||
let start = Instant::now();
|
||||
let mut cave = Cave::create(3879, Node(8, 713, Torch));
|
||||
println!("#{:?}", Instant::now() - start);
|
||||
let x = Instant::now();
|
||||
println!("Sum of erosion indexes: {}", cave.erosion_sum());
|
||||
println!("#{:?}", Instant::now() - x);
|
||||
let x = Instant::now();
|
||||
println!("Shortest path length: {}", cave.shortest_path_length());
|
||||
println!("#{:?}", Instant::now() - x);
|
||||
println!("#Overall run time: {:?}", Instant::now() - start);
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Clone, Copy, Debug, Eq, Hash)]
|
||||
enum Equipment {
|
||||
Torch,
|
||||
Climbing,
|
||||
Neither,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||
struct Node(usize, usize, Equipment);
|
||||
|
||||
struct Cave {
|
||||
map: HashMap<(usize, usize), usize>,
|
||||
target: Node,
|
||||
depth: usize,
|
||||
}
|
||||
|
||||
impl Cave {
|
||||
fn create(depth: usize, target: Node) -> Self {
|
||||
if target.2 != Torch {
|
||||
panic!("A valid target point needs the torch equipped");
|
||||
}
|
||||
|
||||
let map = HashMap::with_capacity((target.0 + 1) * (target.1 + 1));
|
||||
|
||||
Cave { map, target, depth }
|
||||
}
|
||||
|
||||
fn erosion_sum(&mut self) -> usize {
|
||||
(0..=self.target.0)
|
||||
.map(|x| {
|
||||
(0..=self.target.1)
|
||||
.map(|y| self.field_type(x, y))
|
||||
.sum::<usize>()
|
||||
})
|
||||
.sum()
|
||||
}
|
||||
|
||||
fn field_type(&mut self, x: usize, y: usize) -> usize {
|
||||
self.erosion_index(x, y) % 3
|
||||
}
|
||||
|
||||
fn erosion_index(&mut self, x: usize, y: usize) -> usize {
|
||||
if let Some(value) = self.map.get(&(x, y)) {
|
||||
*value
|
||||
} else {
|
||||
let geo_index = match (x, y) {
|
||||
(0, 0) => 0,
|
||||
_ if self.target.0 == x && self.target.1 == y => 0,
|
||||
(x, 0) => x * 16807,
|
||||
(0, y) => y * 48271,
|
||||
(x, y) => self.erosion_index(x - 1, y) * self.erosion_index(x, y - 1),
|
||||
};
|
||||
let erosion_index = (geo_index + self.depth) % 20183;
|
||||
self.map.insert((x, y), erosion_index);
|
||||
erosion_index
|
||||
}
|
||||
}
|
||||
|
||||
fn shortest_path_length(&mut self) -> usize {
|
||||
self.map.reserve(
|
||||
std::cmp::max(self.target.0, self.target.1)
|
||||
* std::cmp::max(self.target.0, self.target.1)
|
||||
- self.map.len(),
|
||||
);
|
||||
let start = Node(0, 0, Torch);
|
||||
let mut open: BinaryHeap<State> = BinaryHeap::new();
|
||||
let mut distances: HashMap<Node, usize> = HashMap::new();
|
||||
// let mut rightmost = 0;
|
||||
// let mut lowest = 0;
|
||||
// let mut visited_counter = 0;
|
||||
|
||||
distances.insert(start, 0);
|
||||
open.push(State {
|
||||
cost: 0,
|
||||
position: start,
|
||||
});
|
||||
|
||||
// Examine the frontier with lower cost nodes first (min-heap)
|
||||
while let Some(State { cost, position }) = open.pop() {
|
||||
// if position.0 > rightmost {
|
||||
// rightmost = position.0;
|
||||
// }
|
||||
// if position.1 > lowest {
|
||||
// lowest = position.1;
|
||||
// }
|
||||
// visited_counter += 1;
|
||||
|
||||
// Alternatively we could have continued to find all shortest paths
|
||||
if position == self.target {
|
||||
// println!(
|
||||
// "Visited {} nodes ({}, {})",
|
||||
// visited_counter, rightmost, lowest
|
||||
// );
|
||||
return cost;
|
||||
}
|
||||
|
||||
// Important as we may have already found a better way
|
||||
if cost > *distances.entry(position).or_insert(usize::max_value()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// For each node we can reach, see if we can find a way with
|
||||
// a lower cost going through this node
|
||||
for edge in self.neighbors(position) {
|
||||
let next = State {
|
||||
cost: cost + edge.cost,
|
||||
position: edge.node,
|
||||
};
|
||||
|
||||
// If so, add it to the frontier and continue
|
||||
let current_distance = distances.entry(edge.node).or_insert(usize::max_value());
|
||||
if next.cost < *current_distance {
|
||||
open.push(next);
|
||||
// Relaxation, we have now found a better way
|
||||
*current_distance = next.cost;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unreachable!("There is always a path");
|
||||
}
|
||||
|
||||
fn neighbors(&mut self, position: Node) -> Vec<Edge> {
|
||||
let mut result = Vec::new();
|
||||
// add all variants of the current position
|
||||
result.push(Edge {
|
||||
cost: 7,
|
||||
node: self.other_node_for_region(position),
|
||||
});
|
||||
|
||||
// for any neighbor position: if it allows the same equipment and is within bounds: add it
|
||||
[
|
||||
(position.0 as i32 - 1, position.1 as i32),
|
||||
(position.0 as i32 + 1, position.1 as i32),
|
||||
(position.0 as i32, position.1 as i32 - 1),
|
||||
(position.0 as i32, position.1 as i32 + 1),
|
||||
]
|
||||
.iter()
|
||||
.filter_map(|(x, y)| {
|
||||
if *x >= 0 && *y >= 0 {
|
||||
Some(Node(*x as usize, *y as usize, position.2))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.for_each(|node| {
|
||||
if self.equipment_allowed_for_region(node.0, node.1, node.2) {
|
||||
result.push(Edge { cost: 1, node })
|
||||
}
|
||||
});
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
fn equipment_allowed_for_region(&mut self, x: usize, y: usize, equipment: Equipment) -> bool {
|
||||
let field_type = self.field_type(x, y);
|
||||
match field_type {
|
||||
// rocky
|
||||
0 => equipment == Torch || equipment == Climbing,
|
||||
// wet
|
||||
1 => equipment == Climbing || equipment == Neither,
|
||||
//narrow
|
||||
2 => equipment == Torch || equipment == Neither,
|
||||
_ => panic!("not a valid type!"),
|
||||
}
|
||||
}
|
||||
|
||||
fn other_node_for_region(&mut self, position: Node) -> Node {
|
||||
let field_type = self.field_type(position.0, position.1);
|
||||
Node(
|
||||
position.0,
|
||||
position.1,
|
||||
match field_type {
|
||||
0 => match position.2 {
|
||||
Climbing => Torch,
|
||||
Torch => Climbing,
|
||||
_ => panic!(),
|
||||
},
|
||||
1 => match position.2 {
|
||||
Climbing => Neither,
|
||||
Neither => Climbing,
|
||||
_ => panic!(),
|
||||
},
|
||||
2 => match position.2 {
|
||||
Torch => Neither,
|
||||
Neither => Torch,
|
||||
_ => panic!(),
|
||||
},
|
||||
_ => panic!("not a valid type"),
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Edge {
|
||||
cost: usize,
|
||||
node: Node,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
|
||||
struct State {
|
||||
cost: usize,
|
||||
position: Node,
|
||||
}
|
||||
|
||||
// The priority queue depends on `Ord`.
|
||||
// Explicitly implement the trait so the queue becomes a min-heap
|
||||
// instead of a max-heap.
|
||||
impl Ord for State {
|
||||
fn cmp(&self, other: &State) -> Ordering {
|
||||
// Notice that the we flip the ordering on costs.
|
||||
// In case of a tie we compare positions - this step is necessary
|
||||
// to make implementations of `PartialEq` and `Ord` consistent.
|
||||
other
|
||||
.cost
|
||||
.cmp(&self.cost)
|
||||
.then_with(|| self.position.0.cmp(&other.position.0))
|
||||
}
|
||||
}
|
||||
|
||||
// `PartialOrd` needs to be implemented as well.
|
||||
impl PartialOrd for State {
|
||||
fn partial_cmp(&self, other: &State) -> Option<Ordering> {
|
||||
Some(self.cmp(other))
|
||||
}
|
||||
}
|
||||
221
src/tasks/day23.rs
Normal file
221
src/tasks/day23.rs
Normal file
@@ -0,0 +1,221 @@
|
||||
use crate::utils;
|
||||
extern crate regex;
|
||||
use regex::Regex;
|
||||
use std::collections::BinaryHeap;
|
||||
|
||||
pub fn task1() {
|
||||
let input = utils::read_file("input/day23.txt");
|
||||
let regex =
|
||||
Regex::new(r"^pos=<(?P<x>-?\d+),(?P<y>-?\d+),(?P<z>-?\d+)>, r=(?P<range>\d+)$").unwrap();
|
||||
let bots: Vec<Bot> = input
|
||||
.lines()
|
||||
.map(|line| {
|
||||
let m = regex.captures(line).unwrap();
|
||||
let x = m["x"].parse::<isize>().unwrap();
|
||||
let y = m["y"].parse::<isize>().unwrap();
|
||||
let z = m["z"].parse::<isize>().unwrap();
|
||||
let range = m["range"].parse::<isize>().unwrap();
|
||||
|
||||
Bot {
|
||||
center: Point::new(x, y, z),
|
||||
range,
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
|
||||
let big_bot = bots.iter().max_by_key(|it| it.range).unwrap();
|
||||
println!("The bot with largest range is {:?}", big_bot);
|
||||
|
||||
let bots_in_range = bots
|
||||
.iter()
|
||||
.filter(|other| big_bot.distance(other) <= big_bot.range)
|
||||
.count();
|
||||
|
||||
println!("There are {} bots in range of the big bot.", bots_in_range);
|
||||
}
|
||||
|
||||
pub fn task2() {
|
||||
let input = utils::read_file("input/day23.txt");
|
||||
let regex =
|
||||
Regex::new(r"^pos=<(?P<x>-?\d+),(?P<y>-?\d+),(?P<z>-?\d+)>, r=(?P<range>\d+)$").unwrap();
|
||||
let bots: Vec<Bot> = input
|
||||
.lines()
|
||||
.map(|line| {
|
||||
let m = regex.captures(line).unwrap();
|
||||
let x = m["x"].parse::<isize>().unwrap();
|
||||
let y = m["y"].parse::<isize>().unwrap();
|
||||
let z = m["z"].parse::<isize>().unwrap();
|
||||
let range = m["range"].parse::<isize>().unwrap();
|
||||
|
||||
Bot {
|
||||
center: Point::new(x, y, z),
|
||||
range,
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
|
||||
let mut heap: BinaryHeap<Candidate> = BinaryHeap::new();
|
||||
heap.push(Candidate {
|
||||
count: bots.len(),
|
||||
cube: Cube::new(-1 << 32, -1 << 32, -1 << 32, 1 << 33),
|
||||
});
|
||||
let mut candidate_points: Vec<(Point, usize)> = Vec::new();
|
||||
let mut best_candidate_count = 0;
|
||||
|
||||
while let Some(Candidate { count, cube }) = heap.pop() {
|
||||
// println!("{:?}: {} ({})", cube, count, best_candidate_count);
|
||||
if count < best_candidate_count {
|
||||
break;
|
||||
}
|
||||
if cube.len == 1 {
|
||||
let count = bots
|
||||
.iter()
|
||||
.filter(|bot| bot.center.distance(&cube.base) <= bot.range)
|
||||
.count();
|
||||
if count > best_candidate_count {
|
||||
candidate_points.push((cube.base, count));
|
||||
println!("pushed with {}!", count);
|
||||
best_candidate_count = count;
|
||||
}
|
||||
} else {
|
||||
for child in cube.children() {
|
||||
heap.push(Candidate {
|
||||
count: bots.iter().filter(|bot| child.intersects(bot)).count(),
|
||||
cube: child,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let origin = Point::new(0, 0, 0);
|
||||
println!(
|
||||
"Found {} candidates - best is {}.",
|
||||
candidate_points.len(),
|
||||
best_candidate_count
|
||||
);
|
||||
let best = candidate_points
|
||||
.iter()
|
||||
.filter(|(_, count)| *count == best_candidate_count)
|
||||
.min_by_key(|(point, _)| origin.distance(point));
|
||||
|
||||
println!("{:?}", best);
|
||||
if let Some((best, _)) = best {
|
||||
println!("{}", best.x + best.y + best.z);
|
||||
}
|
||||
|
||||
// wrong: 37446460,43177892,57318660; 137943012; 102224079;
|
||||
}
|
||||
|
||||
#[derive(Eq, PartialEq)]
|
||||
struct Candidate {
|
||||
count: usize,
|
||||
cube: Cube,
|
||||
}
|
||||
|
||||
impl Ord for Candidate {
|
||||
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
|
||||
self.count.cmp(&other.count)
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd for Candidate {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
||||
Some(self.count.cmp(&other.count))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Bot {
|
||||
center: Point,
|
||||
range: isize,
|
||||
}
|
||||
|
||||
impl Bot {
|
||||
fn distance(&self, other: &Self) -> isize {
|
||||
self.dist(&other.center)
|
||||
}
|
||||
|
||||
fn dist(&self, p: &Point) -> isize {
|
||||
self.center.distance(p)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
||||
struct Point {
|
||||
x: isize,
|
||||
y: isize,
|
||||
z: isize,
|
||||
}
|
||||
|
||||
impl Point {
|
||||
fn new(x: isize, y: isize, z: isize) -> Self {
|
||||
Point { x, y, z }
|
||||
}
|
||||
|
||||
fn distance(&self, other: &Point) -> isize {
|
||||
(other.x - self.x).abs() + (other.y - self.y).abs() + (other.z - self.z).abs()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Eq, Debug)]
|
||||
struct Cube {
|
||||
base: Point,
|
||||
len: isize,
|
||||
}
|
||||
|
||||
impl Cube {
|
||||
fn new(x: isize, y: isize, z: isize, len: isize) -> Self {
|
||||
if len < 1 {
|
||||
panic!("The side length of a cube has to be at least 1");
|
||||
}
|
||||
if (len & (len - 1)) != 0 {
|
||||
panic!("The side length has to be a power of two");
|
||||
}
|
||||
Cube {
|
||||
base: Point::new(x, y, z),
|
||||
len,
|
||||
}
|
||||
}
|
||||
|
||||
fn children(&self) -> Vec<Self> {
|
||||
let l = self.len / 2;
|
||||
let x = self.base.x;
|
||||
let y = self.base.y;
|
||||
let z = self.base.z;
|
||||
vec![
|
||||
Cube::new(x + l, y + l, z, l),
|
||||
Cube::new(x + l, y + l, z + l, l),
|
||||
Cube::new(x + l, y, z, l),
|
||||
Cube::new(x + l, y, z + l, l),
|
||||
Cube::new(x, y + l, z, l),
|
||||
Cube::new(x, y + l, z + l, l),
|
||||
Cube::new(x, y, z, l),
|
||||
Cube::new(x, y, z + l, l),
|
||||
]
|
||||
}
|
||||
|
||||
fn intersects(&self, bot: &Bot) -> bool {
|
||||
((self.base.x - bot.center.x).abs()
|
||||
+ (self.base.x + self.len - bot.center.x).abs()
|
||||
+ (self.base.y - bot.center.y).abs()
|
||||
+ (self.base.y + self.len - bot.center.y).abs()
|
||||
+ (self.base.z - bot.center.z).abs()
|
||||
+ (self.base.z + self.len - bot.center.z).abs()
|
||||
- 3 * self.len)
|
||||
/ 2
|
||||
<= bot.range
|
||||
}
|
||||
}
|
||||
|
||||
mod test {
|
||||
#[test]
|
||||
fn intersection() {
|
||||
use super::*;
|
||||
let cube = Cube::new(0, 0, 0, 16);
|
||||
let bot = Bot {
|
||||
center: Point::new(8, 8, 8),
|
||||
range: 4,
|
||||
};
|
||||
assert!(cube.intersects(&bot));
|
||||
}
|
||||
}
|
||||
307
src/tasks/day24.rs
Normal file
307
src/tasks/day24.rs
Normal file
@@ -0,0 +1,307 @@
|
||||
use std::cmp::Reverse;
|
||||
use std::collections::HashMap;
|
||||
|
||||
use itertools::Itertools;
|
||||
|
||||
use crate::utils;
|
||||
|
||||
pub fn task1() {
|
||||
let input = utils::read_file("input/day24.txt");
|
||||
|
||||
let result = play(&input, 0);
|
||||
println!("Standing units after the game: {}", result.unwrap().1);
|
||||
}
|
||||
|
||||
pub fn task2() {
|
||||
let input = utils::read_file("input/day24.txt");
|
||||
|
||||
let immune_final_count = (0..)
|
||||
.map(|boost| play(&input, boost))
|
||||
.find(|result| result.map(|(team, _)| team) == Some(Team::ImmuneSystem))
|
||||
.unwrap()
|
||||
.unwrap()
|
||||
.1;
|
||||
|
||||
println!("Immune systems final count: {immune_final_count}");
|
||||
}
|
||||
|
||||
fn play(input: &str, boost: i64) -> Option<(Team, i64)> {
|
||||
let mut game = Game::create(&input, boost);
|
||||
|
||||
println!(
|
||||
"Immune start units: {}",
|
||||
game.groups
|
||||
.iter()
|
||||
.filter(|(_, it)| it.team == Team::ImmuneSystem)
|
||||
.map(|(_, it)| it.units)
|
||||
.sum::<i64>()
|
||||
);
|
||||
println!(
|
||||
"Infection start units: {}",
|
||||
game.groups
|
||||
.iter()
|
||||
.filter(|(_, it)| it.team == Team::Infection)
|
||||
.map(|(_, it)| it.units)
|
||||
.sum::<i64>()
|
||||
);
|
||||
|
||||
while !game.is_over() {
|
||||
game.round();
|
||||
if game.draw {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
|
||||
Some((game.winning_team(), game.remaining_units()))
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Game {
|
||||
groups: HashMap<usize, Group>,
|
||||
draw: bool,
|
||||
}
|
||||
|
||||
impl Game {
|
||||
fn remaining_units(&self) -> i64 {
|
||||
self.groups.values().map(|it| it.units).sum::<i64>()
|
||||
}
|
||||
|
||||
fn winning_team(&self) -> Team {
|
||||
let teams: Vec<Team> = self
|
||||
.groups
|
||||
.values()
|
||||
.map(|group| group.team)
|
||||
.unique()
|
||||
.collect();
|
||||
if teams.len() != 1 {
|
||||
panic!("No winning team. Remaining teams: {teams:?}");
|
||||
}
|
||||
teams[0]
|
||||
}
|
||||
|
||||
fn create(input: &str, boost: i64) -> Self {
|
||||
let mut groups = HashMap::new();
|
||||
let mut team = Team::ImmuneSystem;
|
||||
for (id, line) in input.lines().enumerate() {
|
||||
match line {
|
||||
"Immune System:" => {
|
||||
team = Team::ImmuneSystem;
|
||||
}
|
||||
"Infection:" => {
|
||||
team = Team::Infection;
|
||||
}
|
||||
"" => (),
|
||||
group => {
|
||||
if let Some(mut group) = Group::from_str(group, team, id) {
|
||||
if group.team == Team::ImmuneSystem {
|
||||
group.attack_damage += boost;
|
||||
}
|
||||
groups.insert(id, group);
|
||||
} else {
|
||||
panic!("bad group: {group}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Game {
|
||||
groups,
|
||||
draw: false,
|
||||
}
|
||||
}
|
||||
|
||||
fn round(&mut self) {
|
||||
let mut target: HashMap<usize, usize> = HashMap::new();
|
||||
// lock targets ordered by effective power
|
||||
let mut all_by_power: Vec<&Group> = self.groups.values().collect();
|
||||
all_by_power.sort_unstable_by_key(|a| Reverse((a.effective_power(), a.initiative)));
|
||||
// for group in all_by_power.iter() {
|
||||
// println!(
|
||||
// "{}: {} ({})",
|
||||
// group.id,
|
||||
// group.effective_power(),
|
||||
// group.initiative
|
||||
// );
|
||||
// }
|
||||
// println!("{:?}", all_by_power);
|
||||
for group in all_by_power.iter() {
|
||||
if let Some(t) = self
|
||||
.groups
|
||||
.values()
|
||||
.filter(|it| it.team != group.team)
|
||||
.filter(|it| !target.values().any(|t| *t == it.id))
|
||||
// .inspect(|it| {
|
||||
// println!(
|
||||
// "{} would deal {} damage to {}",
|
||||
// group.id,
|
||||
// group.compute_attack_damage_to(it),
|
||||
// it.id
|
||||
// )
|
||||
// })
|
||||
.max_by_key(|it| {
|
||||
(
|
||||
group.compute_attack_damage_to(it),
|
||||
it.effective_power(),
|
||||
it.initiative,
|
||||
)
|
||||
})
|
||||
{
|
||||
if group.compute_attack_damage_to(t) <= 0 {
|
||||
// println!(
|
||||
// "Didn't find a target where {:?} can deal positive damage.",
|
||||
// group
|
||||
// );
|
||||
continue;
|
||||
} else {
|
||||
target.insert(group.id, t.id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// attack ordered by initiative
|
||||
let mut all_ids_by_initiative: Vec<usize> = self.groups.values().map(|it| it.id).collect();
|
||||
all_ids_by_initiative.sort_unstable_by_key(|id| Reverse(self.groups[id].initiative));
|
||||
|
||||
self.draw = true;
|
||||
for active_id in all_ids_by_initiative {
|
||||
if !self.groups[&active_id].alive() {
|
||||
// was killed in this round
|
||||
// println!("Group {} already dead", active_id);
|
||||
continue;
|
||||
}
|
||||
if let Some(enemy_id) = target.get(&active_id) {
|
||||
let enemy = &self.groups[enemy_id];
|
||||
let damage: i64 = self.groups[&active_id].compute_attack_damage_to(enemy);
|
||||
let dying_units = damage / enemy.hp_each;
|
||||
self.groups.get_mut(enemy_id).unwrap().units -= dying_units;
|
||||
|
||||
if dying_units > 0 {
|
||||
self.draw = false;
|
||||
}
|
||||
// println!(
|
||||
// "{} dealt {} ({} units) damage to {}",
|
||||
// active_id, damage, dying_units, enemy_id
|
||||
// );
|
||||
}
|
||||
}
|
||||
|
||||
// clean up dead groups
|
||||
self.groups.retain(|_, it| it.alive());
|
||||
// println!("{:?}", self.groups);
|
||||
}
|
||||
|
||||
fn is_over(&self) -> bool {
|
||||
self.groups.iter().all(|(_, it)| it.team == Team::Infection)
|
||||
|| self
|
||||
.groups
|
||||
.iter()
|
||||
.all(|(_, it)| it.team == Team::ImmuneSystem)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
||||
enum Team {
|
||||
Infection,
|
||||
ImmuneSystem,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
struct Group {
|
||||
id: usize,
|
||||
team: Team,
|
||||
units: i64,
|
||||
hp_each: i64,
|
||||
weaknesses: Vec<String>,
|
||||
immunities: Vec<String>,
|
||||
attack_damage: i64,
|
||||
attack_type: String,
|
||||
initiative: u64,
|
||||
}
|
||||
|
||||
impl Group {
|
||||
fn from_str(input: &str, team: Team, id: usize) -> Option<Self> {
|
||||
// 801 units each with 4706 hit points (weak to radiation) with an attack that does 116 bludgeoning damage at initiative 1
|
||||
// 2347 units each with 3322 hit points with an attack that does 12 cold damage at initiative 2
|
||||
use regex::Regex;
|
||||
let regex = Regex::new(r"(\d+) units each with (\d+) hit points(.*)with an attack that does (\d+) (\w+) damage at initiative (\d+)").unwrap();
|
||||
if let Some(m) = regex.captures(input) {
|
||||
let units: i64 = m[1].parse().unwrap();
|
||||
let hp_each: i64 = m[2].parse().unwrap();
|
||||
let attack_damage: i64 = m[4].parse().unwrap();
|
||||
let attack_type = m[5].to_string();
|
||||
let initiative: u64 = m[6].parse().unwrap();
|
||||
let mut weaknesses: Vec<String> = Vec::new();
|
||||
let mut immunities: Vec<String> = Vec::new();
|
||||
let attributes = m[3].trim().trim_start_matches("(").trim_end_matches(")");
|
||||
for part in attributes.split("; ") {
|
||||
if let Some(stripped) = part.strip_prefix("weak to ") {
|
||||
weaknesses = stripped.split(", ").map(|it| it.to_string()).collect();
|
||||
} else if let Some(stripped) = part.strip_prefix("immune to ") {
|
||||
immunities = stripped.split(", ").map(|it| it.to_string()).collect();
|
||||
}
|
||||
}
|
||||
|
||||
let group = Group {
|
||||
id,
|
||||
team,
|
||||
units,
|
||||
hp_each,
|
||||
weaknesses,
|
||||
immunities,
|
||||
attack_damage,
|
||||
attack_type,
|
||||
initiative,
|
||||
};
|
||||
Some(group)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn alive(&self) -> bool {
|
||||
self.units > 0
|
||||
}
|
||||
|
||||
fn effective_power(&self) -> i64 {
|
||||
if !self.alive() {
|
||||
panic!("I have no power, im dead!")
|
||||
}
|
||||
self.units * self.attack_damage
|
||||
}
|
||||
|
||||
fn compute_attack_damage_to(&self, other: &Self) -> i64 {
|
||||
if self.alive() {
|
||||
if other.weaknesses.contains(&self.attack_type) {
|
||||
self.effective_power() * 2
|
||||
} else if other.immunities.contains(&self.attack_type) {
|
||||
0
|
||||
} else {
|
||||
self.effective_power()
|
||||
}
|
||||
} else {
|
||||
panic!("I'm not alive, I cannot attack anyone")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use crate::tasks::day24::play;
|
||||
|
||||
const INPUT: &str = "Immune System:
|
||||
17 units each with 5390 hit points (weak to radiation, bludgeoning) with an attack that does 4507 fire damage at initiative 2
|
||||
989 units each with 1274 hit points (immune to fire; weak to bludgeoning, slashing) with an attack that does 25 slashing damage at initiative 3
|
||||
|
||||
Infection:
|
||||
801 units each with 4706 hit points (weak to radiation) with an attack that does 116 bludgeoning damage at initiative 1
|
||||
4485 units each with 2961 hit points (immune to radiation; weak to fire, cold) with an attack that does 12 slashing damage at initiative 4";
|
||||
|
||||
#[test]
|
||||
fn example1() {
|
||||
assert_eq!(5216, play(INPUT, 0).unwrap().1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn example2() {
|
||||
assert_eq!(51, play(INPUT, 1570).unwrap().1);
|
||||
}
|
||||
}
|
||||
122
src/tasks/day25.rs
Normal file
122
src/tasks/day25.rs
Normal file
@@ -0,0 +1,122 @@
|
||||
use std::collections::VecDeque;
|
||||
|
||||
use crate::utils;
|
||||
|
||||
pub fn task1() {
|
||||
println!("{}", solve(&utils::read_file("input/day25.txt")));
|
||||
}
|
||||
|
||||
fn solve(input: &str) -> u32 {
|
||||
let mut points: Vec<STP> = input.lines().map(STP::from).collect();
|
||||
let mut constellations = 0;
|
||||
while let Some(next_origin) = points.pop() {
|
||||
constellations += 1;
|
||||
let mut queue = VecDeque::new();
|
||||
queue.push_back(next_origin);
|
||||
|
||||
while let Some(next) = queue.pop_front() {
|
||||
let (neighbors, remainder) = points.into_iter().partition(|p| next.is_neighbor_to(p));
|
||||
points = remainder;
|
||||
for n in neighbors {
|
||||
queue.push_back(n);
|
||||
}
|
||||
}
|
||||
}
|
||||
constellations
|
||||
}
|
||||
|
||||
#[derive(Hash, Eq, PartialEq, Debug)]
|
||||
struct STP(i32, i32, i32, i32);
|
||||
|
||||
impl STP {}
|
||||
|
||||
impl STP {
|
||||
fn distance(&self, other: &Self) -> u32 {
|
||||
((self.0 - other.0).abs()
|
||||
+ (self.1 - other.1).abs()
|
||||
+ (self.2 - other.2).abs()
|
||||
+ (self.3 - other.3).abs()) as u32
|
||||
}
|
||||
|
||||
fn is_neighbor_to(&self, other: &Self) -> bool {
|
||||
self.distance(other) <= 3
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&str> for STP {
|
||||
fn from(value: &str) -> Self {
|
||||
let mut split = value.split(",");
|
||||
|
||||
STP(
|
||||
split.next().unwrap().parse().unwrap(),
|
||||
split.next().unwrap().parse().unwrap(),
|
||||
split.next().unwrap().parse().unwrap(),
|
||||
split.next().unwrap().parse().unwrap(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use crate::tasks::day25::solve;
|
||||
|
||||
#[test]
|
||||
fn example1() {
|
||||
let input = "0,0,0,0
|
||||
3,0,0,0
|
||||
0,3,0,0
|
||||
0,0,3,0
|
||||
0,0,0,3
|
||||
0,0,0,6
|
||||
9,0,0,0
|
||||
12,0,0,0";
|
||||
assert_eq!(solve(input), 2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn example2() {
|
||||
let input = "-1,2,2,0
|
||||
0,0,2,-2
|
||||
0,0,0,-2
|
||||
-1,2,0,0
|
||||
-2,-2,-2,2
|
||||
3,0,2,-1
|
||||
-1,3,2,2
|
||||
-1,0,-1,0
|
||||
0,2,1,-2
|
||||
3,0,0,0";
|
||||
assert_eq!(solve(input), 4);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn example3() {
|
||||
let input = "1,-1,0,1
|
||||
2,0,-1,0
|
||||
3,2,-1,0
|
||||
0,0,3,1
|
||||
0,0,-1,-1
|
||||
2,3,-2,0
|
||||
-2,2,0,0
|
||||
2,-2,0,-1
|
||||
1,-1,0,-1
|
||||
3,2,0,2
|
||||
";
|
||||
assert_eq!(solve(input), 3);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn example4() {
|
||||
let input = "1,-1,-1,-2
|
||||
-2,-2,0,1
|
||||
0,2,1,3
|
||||
-2,3,-2,1
|
||||
0,2,3,-2
|
||||
-1,-1,1,-2
|
||||
0,-2,-1,0
|
||||
-2,2,3,-1
|
||||
1,2,2,0
|
||||
-1,-2,0,-2
|
||||
";
|
||||
assert_eq!(solve(input), 8);
|
||||
}
|
||||
}
|
||||
@@ -6,3 +6,20 @@ pub mod day05;
|
||||
pub mod day06;
|
||||
pub mod day07;
|
||||
pub mod day08;
|
||||
pub mod day09;
|
||||
pub mod day10;
|
||||
pub mod day11;
|
||||
pub mod day12;
|
||||
pub mod day13;
|
||||
pub mod day14;
|
||||
pub mod day15;
|
||||
pub mod day16;
|
||||
pub mod day17;
|
||||
pub mod day18;
|
||||
pub mod day19;
|
||||
pub mod day20;
|
||||
pub mod day21;
|
||||
pub mod day22;
|
||||
pub mod day23;
|
||||
pub mod day24;
|
||||
pub mod day25;
|
||||
|
||||
@@ -2,7 +2,7 @@ use std::fs::File;
|
||||
use std::io::prelude::*;
|
||||
|
||||
pub fn read_file(path: &str) -> String {
|
||||
let mut f = File::open(path).expect(&format!("file '{}' not found", path));
|
||||
let mut f = File::open(path).unwrap_or_else(|_| panic!("file '{}' not found", path));
|
||||
|
||||
let mut contents = String::new();
|
||||
f.read_to_string(&mut contents)
|
||||
|
||||
Reference in New Issue
Block a user