Compare commits

...

63 Commits

Author SHA1 Message Date
fc803d8a0f Day 24 part 2. 2023-11-14 19:35:00 +01:00
3a9379f877 Day 24 part 1. 2023-11-14 18:48:45 +01:00
241c417a77 intermediate 2023-11-14 16:56:16 +01:00
4cbe831115 Removed warnings. 2023-11-14 16:41:54 +01:00
a4c33ae3d2 Day 21 part 2. Shitty bitty. 2023-11-13 23:22:51 +01:00
48ad7e7a96 Day 21 part 1. 2023-11-13 19:52:52 +01:00
caf307bf2d Day 19 part 2 (manually reverse engineered the assembler instructions). 2023-11-12 23:12:46 +01:00
2792304040 Day 19 part 1. 2023-11-12 21:25:31 +01:00
42ead11aa0 Day 16 part 2. 2023-11-12 19:15:31 +01:00
8e1f42205c Day 16 part 1. 2023-11-12 16:14:45 +01:00
c4ae25d579 Updated dependencies. 2023-11-12 12:36:02 +01:00
f472ace665 Day 25 part 1. 2023-11-10 21:15:00 +01:00
a9b3c90a6c Fixed compiler warnings. 2023-11-10 19:17:51 +01:00
30ef81cfac Day 18 part 2 2023-05-27 01:45:15 +02:00
861e31efee Day 18 part 1 2023-05-27 01:00:21 +02:00
d6c728ccfe Day 17 part 2 2023-05-26 22:25:26 +02:00
8bc589488c Day 17 part 1 2023-05-26 22:23:19 +02:00
cfb3ae497e Reformatted 2023-05-26 10:02:22 +02:00
b922b808fc Day 17 stuff 2023-05-26 10:02:17 +02:00
5c4e9a9e9d Day 17 parsing 2023-05-25 23:01:57 +02:00
b480601ee8 clippy fixes
clippy fixes #2

clippy fixed #3

removed unnecessary stuff
2023-05-20 23:28:37 +02:00
ef2340eaae Migrated to rust edition 2021 2023-05-20 22:39:07 +02:00
Johannes
b2a5da3222 day23 part 2 correct intersection test (speed up by factor 2, yay!) 2019-01-03 11:43:38 +01:00
Johannes
9cbbf63eb1 day23 part 2 (with a shortcut that could potentially break some cases)
I'm only using a lower bound on the number of intersections a cube has.
2019-01-01 18:40:00 +01:00
Johannes
c162fcb6d9 day24 p1 wrong (example ok) 2018-12-29 16:43:39 +01:00
Johannes
097cfac516 day24 part1 input parsing 2018-12-26 23:30:39 +01:00
Johannes
2b51e67fc6 day23 hmmm 2018-12-26 22:27:36 +01:00
Johannes
6e438127ec day23 part1 2018-12-25 17:15:51 +01:00
Johannes
21dfc7f630 day22 little speed improvement 2018-12-25 14:32:50 +01:00
Johannes
719db128cf day22 with hashmaps
slower, but more flexible
2018-12-25 14:04:03 +01:00
Johannes
12f32ed232 removed warnings 2018-12-25 14:03:45 +01:00
Johannes
768d328e87 day22 2nd part 2018-12-24 17:19:50 +01:00
Johannes
31075fa449 day22 refactored part1 into extra struct 2018-12-24 15:49:00 +01:00
Johannes
d5aa1ddc74 day22 part1 2018-12-22 15:07:46 +01:00
Johannes Schaefer
8badd4a416 day20 part 2 2018-12-21 11:26:21 +01:00
Johannes
241ca8ea18 day20 part1 fast 2018-12-21 10:32:11 +01:00
Johannes
a35881fb01 day20 part 1 super slow 2018-12-21 10:03:06 +01:00
Johannes
0438a052d2 day20 WIP 2018-12-20 10:19:41 +01:00
Johannes
ba622fd408 day15 part 2 optimized
instead of senselessly trying to find the best starting point, just rely
on the order of neighbor point generation. Since we use a queue
to manage open points and he neighbors are added in the correct
order, they neighbor that has precedence due to reading order will
automatically be the one to be predecessor on a final path, if he is on
a shortest path.
2018-12-18 22:43:10 +01:00
Johannes
cef96d55be day15 part 2 2018-12-18 22:20:03 +01:00
Johannes
3f2ff6e5a2 day15 part1 done 2018-12-18 19:11:55 +01:00
Johannes Schaefer
ac3a741f0d day15 part1 combat with errors 2018-12-18 17:46:44 +01:00
Johannes Schaefer
2bf8edf315 day15 part1 movement 2018-12-18 16:59:41 +01:00
Johannes Schaefer
6f2e046080 day14 both parts 2018-12-17 17:45:35 +01:00
Johannes Schaefer
6f9ca4dfb6 2018-12-17 11:06:12 +01:00
Johannes
807bff7977 day13 part2 2018-12-16 01:37:37 +01:00
Johannes
c1c761f2ba day13 part 1 2018-12-16 01:14:09 +01:00
Johannes Schaefer
2fa6c40f33 day12 part 1 2018-12-14 14:09:57 +01:00
Johannes Schaefer
54103e8fa6 day11 part2 fast 2018-12-11 16:02:22 +01:00
Johannes Schaefer
fc328d82af day11 part2 2018-12-11 11:37:32 +01:00
Johannes Schaefer
267dfb8068 day11 part 1 2018-12-11 11:25:57 +01:00
Johannes
6d4bdccc6e day10 part 2 2018-12-11 09:35:19 +01:00
Johannes
4eb90ac047 day10 part 1 2018-12-10 20:51:13 +01:00
Johannes Schaefer
2cf9933300 day09 part 2 2018-12-10 15:16:06 +01:00
Johannes Schaefer
e5a3a1458a day09 part 1 2018-12-10 13:10:09 +01:00
Johannes Schaefer
d84e3bff27 day08 part 2 2018-12-09 21:34:43 +01:00
Johannes Schaefer
51418b709e day08 part 1 2018-12-09 21:17:29 +01:00
Johannes Schaefer
4946263a37 day07-1 2018-12-07 11:17:48 +01:00
Johannes Schaefer
cd16a42821 push to edition 2018 2018-12-07 09:53:18 +01:00
Johannes Schaefer
5ab8409b5b day06 both 2018-12-06 09:50:35 +01:00
Johannes
5fa344dd55 day05 part 2 prealloc vectors 2018-12-05 20:53:00 +01:00
Johannes Schaefer
d10d36498c day05 performance push part 2 through more efficient case insensitive comparison 2018-12-05 15:19:12 +01:00
Johannes Schaefer
32843531f8 take times 2018-12-05 15:15:18 +01:00
47 changed files with 13293 additions and 145 deletions

379
Cargo.lock generated
View File

@@ -1,161 +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)",
"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.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57"
dependencies = [
"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 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"

View File

@@ -2,7 +2,12 @@
name = "aoc_2018"
version = "0.1.0"
authors = ["Johannes <jschaef@mail.uni-paderborn.de>"]
edition = "2021"
[dependencies]
regex = "1.1.0"
chrono = "0.4.6"
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"

50
input/day06.txt Normal file
View File

@@ -0,0 +1,50 @@
152, 292
163, 90
258, 65
123, 147
342, 42
325, 185
69, 45
249, 336
92, 134
230, 241
74, 262
241, 78
299, 58
231, 146
239, 87
44, 157
156, 340
227, 226
212, 318
194, 135
235, 146
171, 197
160, 59
218, 205
323, 102
290, 356
244, 214
174, 250
70, 331
288, 80
268, 128
359, 98
78, 249
221, 48
321, 228
52, 225
151, 302
183, 150
142, 327
172, 56
72, 321
225, 298
265, 300
86, 288
78, 120
146, 345
268, 181
243, 235
262, 268
40, 60

101
input/day07.txt Normal file
View File

@@ -0,0 +1,101 @@
Step B must be finished before step K can begin.
Step F must be finished before step I can begin.
Step T must be finished before step U can begin.
Step R must be finished before step Z can begin.
Step N must be finished before step S can begin.
Step X must be finished before step Y can begin.
Step I must be finished before step Y can begin.
Step K must be finished before step L can begin.
Step U must be finished before step J can begin.
Step G must be finished before step L can begin.
Step W must be finished before step A can begin.
Step H must be finished before step Q can begin.
Step M must be finished before step L can begin.
Step P must be finished before step L can begin.
Step L must be finished before step A can begin.
Step V must be finished before step Y can begin.
Step Q must be finished before step Y can begin.
Step Z must be finished before step J can begin.
Step O must be finished before step D can begin.
Step Y must be finished before step A can begin.
Step J must be finished before step E can begin.
Step A must be finished before step E can begin.
Step C must be finished before step E can begin.
Step D must be finished before step E can begin.
Step S must be finished before step E can begin.
Step B must be finished before step R can begin.
Step U must be finished before step O can begin.
Step X must be finished before step I can begin.
Step C must be finished before step S can begin.
Step O must be finished before step S can begin.
Step J must be finished before step D can begin.
Step O must be finished before step E can begin.
Step Z must be finished before step O can begin.
Step J must be finished before step C can begin.
Step P must be finished before step Y can begin.
Step X must be finished before step S can begin.
Step O must be finished before step Y can begin.
Step J must be finished before step A can begin.
Step H must be finished before step C can begin.
Step P must be finished before step D can begin.
Step Z must be finished before step S can begin.
Step T must be finished before step Z can begin.
Step Y must be finished before step C can begin.
Step X must be finished before step H can begin.
Step R must be finished before step Y can begin.
Step T must be finished before step W can begin.
Step L must be finished before step O can begin.
Step G must be finished before step Z can begin.
Step H must be finished before step P can begin.
Step I must be finished before step U can begin.
Step H must be finished before step V can begin.
Step N must be finished before step Y can begin.
Step Q must be finished before step E can begin.
Step H must be finished before step D can begin.
Step P must be finished before step O can begin.
Step T must be finished before step I can begin.
Step W must be finished before step V can begin.
Step K must be finished before step M can begin.
Step R must be finished before step W can begin.
Step B must be finished before step T can begin.
Step U must be finished before step A can begin.
Step N must be finished before step H can begin.
Step F must be finished before step U can begin.
Step Q must be finished before step O can begin.
Step Y must be finished before step S can begin.
Step V must be finished before step O can begin.
Step W must be finished before step C can begin.
Step Y must be finished before step J can begin.
Step T must be finished before step V can begin.
Step N must be finished before step D can begin.
Step U must be finished before step Q can begin.
Step A must be finished before step C can begin.
Step U must be finished before step M can begin.
Step Q must be finished before step S can begin.
Step P must be finished before step V can begin.
Step B must be finished before step Z can begin.
Step W must be finished before step Q can begin.
Step L must be finished before step S can begin.
Step I must be finished before step P can begin.
Step G must be finished before step P can begin.
Step L must be finished before step C can begin.
Step K must be finished before step A can begin.
Step D must be finished before step S can begin.
Step I must be finished before step H can begin.
Step R must be finished before step M can begin.
Step Q must be finished before step D can begin.
Step K must be finished before step O can begin.
Step I must be finished before step C can begin.
Step N must be finished before step O can begin.
Step R must be finished before step X can begin.
Step P must be finished before step C can begin.
Step B must be finished before step Y can begin.
Step G must be finished before step E can begin.
Step L must be finished before step V can begin.
Step W must be finished before step Y can begin.
Step C must be finished before step D can begin.
Step M must be finished before step J can begin.
Step F must be finished before step N can begin.
Step T must be finished before step Q can begin.
Step I must be finished before step E can begin.
Step A must be finished before step D can begin.

1
input/day08.txt Normal file

File diff suppressed because one or more lines are too long

357
input/day10.txt Normal file
View 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
View File

@@ -0,0 +1,34 @@
initial state: ..##.#######...##.###...#..#.#.#..#.##.#.##....####..........#..#.######..####.#.#..###.##..##..#..#
#..#. => .
..#.. => .
..#.# => #
##.#. => .
.#... => #
#.... => .
##### => #
.#.## => .
#.#.. => .
#.### => #
.##.. => #
##... => .
#...# => #
####. => #
#.#.# => .
#..## => .
.#### => .
...## => .
..### => #
.#..# => .
##..# => #
.#.#. => .
..##. => .
###.. => .
###.# => #
#.##. => #
..... => .
.##.# => #
....# => .
##.## => #
...#. => #
.###. => .

150
input/day13.txt Normal file
View File

@@ -0,0 +1,150 @@
/----------------------------------------------------------------------------------------------------------\
| /---------------------\ /-----------------\ |
/-------------------------\ | /--------+-----------\ | | /----------\ | |
| /----------+----+----------------------------------------+--------+-----------+-------\ | | | | | |
| /------------+\ | | /-------------------------+--------+-\ | | | | | | | |
| | || | | /----+-------------------------+--------+-+---------+-------+-+-\ | | | | |
| | /--++--------\| /+---------+----+-------------------------+--------+\| | /--+-+-+---------+-+----------+-\ | |
| | | || /-++---++---------+----+-------------------------+--------+++---------+----+--+-+-+---------+-+----\ | | | |
| | | ||/-----+-++---++---------+----+--\ /------------------+--------+++---------+----+--+-+-+---------+-+----+-----+-+--+\ |
/---------+-+---------+--+++-----+-++---++---------+----+--+---+-\ | ||| | | | | | | | | | | || |
| | | | ||| | || || | | | | | /---------\ | ||| | | | | | | | | | | || |
| | | | ||| /+-++---++---------+----+--+---+-+--+---------+---+--------+++---------+----+--+-+\| | | | | | || |
| | | | ||| || || || | /+--+---+-+--+---------+---+--------+++------\ | | | ||| | \----+-----/ | || |
| /--+-+---------+--+++----++-++---++---------+---++--+---+-+--+-------\ | | ||| | | | | ||| | | | || |
| /---+--+-+---------+--+++----++-++---++->\ | || | | | | | | | ||| | | | | ||| | | | || |
| | | | | | ||| || || || | /---+---++--+---+-+--+-------+-+---+--------+++------+--+----+--+-+++---------+----\ | | || |
| | | | | | ||| || || || | v |/--++--+-\ | | | | | | ||| /---+--+----+--+-+++--------\| | | | || |
| | | | | |/-+++----++-++---++--+--+---++--++--+-+-+-+--+-------+\| | ||| | | | /--+--+-+++--------++----+-+-------+--++--\|
| | | | | /---++-+++----++-++---++--+--+---++--++--+-+-+-+--+--\ ||| | ||| | | | | | | ||| || | | | || ||
| | | | | | || ||| || || || | | || || | | | | | | ||| | ||| | /-+--+-+--+--+-+++--------++----+-+---\ | || ||
| | | | | | || ||| || || || | | || ||/-+-+-+-+--+--+----+++---+--------+++--+-+-+--+-+--+--+-+++--------++-\ | | | | || ||
| | | | | /--+---++-+++----++-++---++--+--+---++--+++-+-+-+-+\ | | /--+++---+--------+++--+-+-+>-+-+--+--+-+++--------++-+--+-+---+---+--++\ ||
| | | | | | /+---++-+++----++\|| \+--+--+---++--+++-+-+-+-++-+--+-+--+++---+--------+/| | | | | | |/-+-+++--------++-+--+-+---+-\ | ||| ||
| | | | | | || || ||| ||||| | | | || ||| | | | || | | | ||| | /------+-+--+-+-+--+-+--++-+-+++--------++-+\ | | | | | ||| ||
| | | | | | || \+-+++----+++/| \--+--+---++--+++-+-+-+-++-+--+-+--+++---+-+------+-+--+-+-+--+-+--++-+-+++--------++-++-+-+-<-+-+-+--+++-+/
| \---+--+-+--+-++----+-+++----+++-+-------/ | /++--+++-+-+-+-++-+--+\| ||| | | \-+--+-+-+--+-+--++-+-/|| || || | | | | | ||| |
| | | | | || | ||| ||| | | ||| ||| | | | || | ||| ||| | | | /+-+-+--+-+--++-+--++--------++-++-+-+--\| | | ||| |
| | | | | || | ||| ||| | | ||| ||| | | | || | ||| ||| | | | || | | | | || | || || || | | || | | ||| |
| | | | | || | ||| ||| | | ||| ||| | | | || | ||| ||| | | /-----+-++-+-+--+-+--++-+--++------\ || || | | || | | ||| |
| | | | |/++----+-+++----+++-+----------+--+++--+++-+-+-+-++-+--+++--+++---+-+--+-----+-++-+-+--+-+--++-+-\|| | || || | | || | | ||| |
| |/-+-+--++++----+-+++----+++-+----------+--+++--+++-+-+-+\|| | ||| ||| | | | | ||/+-+--+-+--++-+-+++-----\| || ||/+-+--++-+-+--+++\|
|/-----++-+-+--++++----+-+++----+++-+----------+--+++\ ||| | | |||| | ||| ||| | | | /---+-++++-+--+-+--++-+-+++-----++-++-++++-+--++-+-+--+++++\
|| || | | ||||/---+-+++----+++-+----------+\ |||| ||| | | |||| | ||| ||| \-+--+-+---+-++++-+--/ | || | ||| || || |||| | || | | ||||||
|| || | | ||||| | ||| |||/+----------++-++++-+++-+-+-++++-+--+++--+++-----+--+-+---+-++++-+----+--++-+-+++-----++-++-++++-+--++-+\| ||||||
|| || | | ||||| | ||| ||||| || ^||| ||| | | |||| | ||| ||| | | | | |||| | | || | ||| || || |||| | || ||| ||||||
|| || | | ||||| | ||| /+++++----------++-++++-+++-+-+-++++-+--+++--+++-----+--+-+---+-++++-+----+--++-+-+++-----++-++-++++\| || ||| ||||||
|| || | |/-+++++---+-+++-\ |||||| || |||| ||| | | |||| | ||| ||| | | | | |||| | | || | ||| || || |||||| || ||| ||||||
|| || | || ||||| | ||| | |||||| ||/++++-+++-+-+-++++-+-\||| ||| | | | /+-++++-+----+--++-+-+++-----++\|| |||||| || ||| ||||||
|| || | || ||||| | ||| | |||||| /-----+++++++-+++-+-+-++++-+-++++--+++-----+--+-+--++-++++-+----+--++-+-+++-----+++++-++++++--++-+++\ ||||||
|| || | || ||||| | ||| | |||||| | ||||||| ||| | | |||| | |||| ||| | | | || |||| | | || | ||| ||||| |||||| || |||| |||||v
|| || | || ||||| | ||| | |||||| /+-----+++++++-+++-+-+-++++-+-++++--+++-----+--+-+--++-++++-+----+--++\| ||| ||||| |||||| || |||| ||||||
|| || | || ||||| | ||| | |||||| || ||||||| ||| | | |||| | |||| ||| | | \--++-++++-+----+--++++-+++-----+++++-++++++--++-++++-+++++/
|| || | || ||||| | ||| | |||||| || ||||||| |||/+-+-++++-+-++++--+++----\| | || |||| | | |||| ||| ||||| |||||| || |||| |||||
|| || | || ||||| | ||| | |||||| || ||||||| \++++-+-++++-+-++++--+++----++--+----++-++++-/ | |||| ||| ||||| |||||| || |||| |||||
|| || \-++-+++++---+-+++-+-+++++/ || /+++++++--++++-+-++++-+-++++--+++----++--+----++-++++------+--++++-+++-----+++++-++++++--++\|||| |||||
|| || || ||||| | |||/+-+++++----++----++++++++--++++-+-++++-+-++++--+++--\ || |/---++-++++------+--++++-+++-----+++++-++++++-\||||||| |||||
|| || || ||||| | ||\++-+++++----++----++++++++--+++/ | |||| |/++++--+++--+-++\ || /-++-++++------+--++++-+++----\||||| |||||| |||||||| |||||
|| || || ||||| | || || ||||| || |||||||| ||| | |||| |||||| ||| | ||| || | || |||| | |||| ||| |||||\-++++++-++++++++-/||||
|| /--++---++-+++++---+-++-++-+++++--\ || |||||||| ||| /+-++++-++++++--+++--+-+++-++-+-++-++++------+--++++-+++----+++++\ |||||| |||||||| ||||
|| | || ||/+++++---+-++-++-+++++--+-++----++++++++--+++-++-++++-++++++--+++--+-+++-++-+-++\|||| | |||| ||| |||||| |||||| |||||||| ||||
|| | || |||||||| | || || ||||| | || |||||||| ||| || |||| |||||| ||| | ||| || | |||||\+------+--++++-+++----+/|||| |||||| |||||||| ||||
|| | || |||||||| |/++-++-+++++--+-++----++++++++--+++-++-++++-++++++--+++--+\||| || | ||||| | | |||| ||| | |||| |||||| |||||||| ||||
|| | || |||||||| |||| || ||||| | || /++++++++--+++-++-++++-++++++--+++--+++++-++-+-+++++-+--\ | |||| ||| | |||| |||||| |||||||| ||||
|| | || |||||||| ||^| || ||||| | || /-+++++++++--+++-++-++++-++++++--+++--+++++-++-+-+++++-+--+---+--++++-+++---\| |||| |||||| |||||||| ||||
|| | || |||||||| |||| || ||||| | || | ||||||||| ||| || |||| |||||| ||| ||||| || | ||||| | | | |||| ||| || |||| |||||| |||||||| ||||
|| | /++---++++++++---++++-++-+++++--+-++-+-+++++++++--+++-++-++++-++++++--+++-\||||| || | ||||| | | | |||| ||| || |||| |||||| |||||||| ||||
|| | ||| |\++++++---++++-+/ ||||| | || | ||||||||| ||| || |||| |||||| ||| |||||| ||/+-+++++-+--+---+--++++-+++---++\|||| |||||| |||||||| ||||
|| /+-+++---+-++++++---++++-+--+++++--+-++-+-+++++++++--+++-++-++++-++++++--+++-++++++-++++-+++++-+--+---+\ |||| ||| ||||||| |||||| |||||||| ||||
|| || |||/--+-++++++---++++-+--+++++--+-++-+-+++++++++--+++-++-++++-++++++--+++-++++++-++++\||||| | | || |||| ||| ||||||| |||||| |||||||| ||||
|| || |||| | |||||| |||| | ||||| | || | ||||||||| ||| || |||| |||||| ||| |||||| |||||||||| | | \+-++++-+++---+++++++-++++++-++++++++--+++/
|| || |||| | |||||| |||| | ||||| | || | ||||||||| ||| || |||| |||||| ||| |||||| |||||||||| | | | |||| ||| ||||||| |||||| |||||||| |||
|| || |||| | |||||| |||| | ||||| | || | ||||||||| \++-++-++++-++++++--+++-++++++-++++++/||| | | | |||| ||| |||||||/++++++-++++++++--+++-\
|| || |||| | |||||| |||| | ||||| | |\-+-+++++++++---++-++-++++-++++++--+++-++++++-++++++-+++-+--+----+-++++-+++->-++++++++++++++-+++++++/ ||| |
|| || |||| | |||||\---++++-+--+++++--+-+--+-+++/||||| || ||/++++-++++++-\||| |||||| |||||| ||| | | | |||| ||| |||||||||||||| ||||||| ||| |
|| || |||| | |||||/---++++-+--+++++--+-+-\| ||\-+++++---++-+++++++-++++++-++++-++++++-++++++-+++-+--+----+-++++-+++---+++++++++++/|| ||||||| ||| |
|| || |\++--+-++++++---++++-+--+++++--+-+-++-++--+++++---++-+++++++<++++++-+/|| |||||| \+++++-+++-+--+----+-++++-+++---+++/||||||\-++-+++++++---++/ |
|| || | || | |||||| |||| | ||||| | | || || ||||| || ||||||| |\++++-+-++-+++++/ ||||| ||| | | | |||| ||| ||| |||||| || ||||||| || |
|| || | || | |||||| /++++-+--+++++--+-+-++-++\ ||||| || ||||||| |/++++-+-++-+++++---+++++-+++-+--+----+-++++-+++---+++-++++++\ || ||||||| || |
|| ||/+-++--+-++++++--+++++-+--+++++--+-+-++-+++-+++++---++-+++++++-++++++\| || ||||| ||||| ||| | | | |||| ||| ||| ||||||| || ||||||| || |
|| |||| || | |||||| ||||| | ||||| | | || ||| ||||| || ||||||| |||||\++-++-+++++---+++++-+++-+--+----+-++++-+++---+++-+++++++-++-+++++++---+/ |
|| |||| || | |||||| ||||| | ||||| |/+-++-+++-+++++---++\||||||| ||||| || || ||||| ||||| ||| | | | |||| ||| ||| ||||||| || ||||||| | |
|| |||| || | |||||| /+++++-+--+++++--+++-++-+++-+++++---++++++++++-+++++-++-++-+++++---+++++-+++-+--+\ | |||| ||| ||| ||||||| || ||||||| | |
|| |||| || ^ |||||| |||||| | ||||| ||| || ||| ||||| /-++++++++++-+++++-++-++-+++++---+++++-+++-+--++\/-+-++++-+++---+++-+++++++-++-+++++++--\| |
|| |||| || | \+++++-++++++-+--+++++--+++-++-+++-+++++-+-++++++++++-+++++-++-++-+++++---+++++-/||/+--++++-+-++++-+++-\ ||| ||||||| || ||||||| || |
|| |||| || | \++++-++++++-+--+++++--+++-++-+++-+++++-+-+++++++++/ ||||| || || ||||| ||||| |||| |||| | |||| ||| | ||| ||||||| || ||||||| || |
|| |||| || | |||| |||||| | ||||| ||| |\-+++-+++++-+-+++++++++--+++++-++-++-+++++---+++++--++++--++++-+-++++-+++-+-/|| ||||||| || ||||||| || |
|| |||| || | |||| |||||| | ||||| |||/+--+++-+++++-+-+++++++++--+++++-++-++-+++++---+++++--++++--++++-+-++++-+++-+--++-+++++++-++-+++++++\ || |
|| |||| || | |||| |||||| | ||||| ||||| ||| ||||| | ||||||||| ||||| || || ||||| ||||| |||| |||| | |||| ||| | || ||||||| || |||||||| || |
|| |||| || /+---++++-++++++-+--+++++--+++++\ ||| ||||| | ||||||||| ||||| || || ||||| ||||| |||| |||| | |||| ||| | || ||||||| || |||||||| || |
|| |||| || || |||| |||||| | |\+++--++++++-+++-+++++-+-+++++++++--+++++-++-++-+++++---+++++--++++--++++-+-++++-+/| | || ||||||| || |||||||| || |
|| |||| \+-++---++++-++++++-+--+-+++--++++++-+++-+++++-+-+++++++/| ||||| || || ||||| ||||| |||| |||| | |||| | | | || ||||||| || |||||||| || |
|| |||| | || |||| |||||| | \-+++--++++++-+++-+++++-+-+++++++-+--+++++-++-++-+++++---+++++--++++--++++-+-++++-+-+-+--++-+++++++-/| |||||||| || |
|| |||| | || |||| |||||| | ||| |||||| ||| ||||| | ||||||| | ||||| || || ||||\---+++++--++++--++++-+-++++-+-+-+--++-+++++/| | |||||||| || |
|| |||| /+-++---++++-++++++-+----+++--++++++\||| ||||| | ||||||| | ||||| || || |||| ||||| |||| |||| | \+++-+-+-+--++-+++++-+--+-++++++/| || |
|| |||| || || |||| |||||| | ||| |||||||||| ||||| | ||||||| | ||||| || || |||| ||||| |||| |||| | ||| | | | || ||||| | | |||||| | || |
|| |||| || || |||| |||||| | ||| |||||||||| ||||| | ||||||| | ||||| || || |||| ||||| |||| |||| | ||| | | | || ||||| | | |||||| | || |
|| |||| || || |||| |||||| | ||| |||||||||| ||||| | ||||||| | ||||| || || |||| ||||\--++++--++++-+--+++-+-+-+--++-/|||| | | |||||| | || |
|| |||| || || |||| |||||| | ||| |||||||||| ||||| | ||||||| | ||||| || || |||| |||| |||| |||| | ||| | | | || |||| | | |||||| | || |
|| |||| || || |||| |||||| | ||| |||||||||| ||||| | ||||||| | ||||| || || |||| |||| |\++--++++-+--+++-+-+-+--++--/||| | | |||||| | || |
|| |||| || || |||| |||||| | ||| |||||||||| |\+++-+-+++++++-+--++++/ || || |||| /-++++---+-++--++++-+--+++-+-+-+--++---+++-+--+-++++++-+-++--\|
|| |||| || || |||| |||||| | ||| |||||||||| | ||| | ||||||| | |||| || || |||| | |||| | || |||| | ||| | | | || ||| | | |||||| | || ||
|| |||| || || |||| |||||| | ||| |||||||||| | ||| | ||||||| | /++++--++-++-++++--+-++++---+-++--++++-+--+++-+-+-+--++---+++-+--+-++++++-+\|| ||
|| ||||/++-++---++++-++++++-+---\\++--++++++++++-+-+++-+-+++++++-+-+++++--++-++-++++--+-++++---+-++--++++-+--+++-+-+-+--++---+++-+--/ |||||| |||| ||
|| ||||||| || |||| |||||| | | || |||||||||| | ||| | ||||||\-+-+++++--++-++-++++--+-++++---+-++--++++-+--+++-+-+-+--++---+++-+----++++++-+++/ ||
|| ||||||| || |||| \+++++-+---+-++--++++++++++-+-+++-+-++++++--+-+++++--++-++-++++--+-++++---+-++--+/|| | ||| | | | || ||| | |||||| ||| ||
|| ||||||| || |||| ||||| | | || |||||||||| | ||| | |||||| | ||||| || || |||| | |||| | |^ | || | ||| | | | || |\+-+----++++++-+++---+/
|| |||\+++-++---++++--+++++-+---+-++--++++++++++-+-+++-+-++++++--+-+++++--++-++-/||| | |||| | || | || | ||| | | | || | | | |||||| ||| |
|| ||| ||| || |||| ||||| | | || |\++++++++-+-+++-+-++/||| | ||||| || || ||| | |||| | || | || | ||| | | | || | v | |||||| ||| |
|| ||| ||| || |||| |||\+-+---+-++--+-++++++++-+-+++-+-++-+++--+-+++++--++-++--+++--+-++++---+-++--+-++-+--++/ | | | || | | | |||||| ||| |
|| ||| ||| || |||| ||| | | | || | |||||||| | ||| | || ||| | |\+++--++-+/ ||| | |||| | || |/++-+--++--+-+-+--++---+-+-+-\ |||||| ||| |
|| ||| ||| || |||| ||| | | | || | |||||||| | ||| | || ||\--+-+-+++--+/ | ||| | |||| | || |||| | || | | |/-++---+-+-+-+--++++++-+++-\ |
|| ||| |||/++---++++--+++-+\| | || | |||||||| | ||| | \+-++---+-+-+++--+--+---+++--+-++++---+-++--++++-+--++--+-+-++-++---+-//+-+--++++++-+++-+\|
|| ||| |||||| |||| ||| ||| | || | |||||||| | ||| | | || | | ||| | | ||| | |||| | || |||| | || | | || || | || | |||||| ||| |||
\+-+++-++++++---++++--+++-+++---+-++--+-++++++++-+-+++-+--+-++---/ | ||| | | ||| | |||| | || |||| | ||/-+-+-++-++---+\ || | |||||| ||| |||
| |\+-++++++---++++--+++-+++---+-++--/ ||||||\+-+-+++-+--+-++-----+-+++--+--+---+++--+-++++---+-++--++++-+--+++-+-+-++-++---++-++-+--+++/|| ||| |||
| | | |||||\---++++--+++-/|| | || |||||| | | ||| | | || | ||| | | ||| | |||| /-+-++--++++-+--+++-+-+-++-++---++-++-+--+++-++\||| |||
| | | ||||| /++++--+++--++---+-++----++++++-+-+\\++-+--+-++-----+-+++--+--+---+++--+-++++-+-+-++--++++-+--+++-+-/ || || || || | ||| |||||| |||
| | | ||||| |||\+--+++--++---+-++----++++++-+-++-++-+--+-++-----+-++/ | | |||/-+-++++-+-+-++--++++\| ||| | || || || || | ||| |||||| |||
| | | ||||| ^|| | ||\--++---+-++----++++++-+-++-++-+--+-++-----+-++---+--+---+/|| | |||| | \-++--++++++--+++-+---++-++---++-++-+--+/| |||||| |||
| | | ||||\---+++-+--++---++---+-++----+++/|| | || || | |/++-----+-++---+--+---+-++-+\|||| | || |||||| ||| | || || || || | | | |||||| |||
| | | |||| ||| | || || | || \++-++-+-++-++-+--++++-----+-++---+--+---+-++-++++++-+---++--++++++--+/| | || || || \+-+--+-+-++++++-+/|
| | | |||| ||| | || || | || || || | || || | \+++-----+-++---+--+---+-/| |||||| | || |||||| | | | || || || | | | | |||||| | |
| | | |||| ||| | |\---++---+-++-----++-++-+-++-++-+---+++-----+-++---+--/ | | |||||| | || |||||| | | | || || || | | | | |||||| | |
| | | |\++----+++-+--+----++---+-++-----++-/| | || \+>+---++/ \-++---+------+--+-++++++-+---++--++++++--+-+-+---++-++---++--+-+--+-+-++++/| | |
| | | | || ||\-+--+----++---+-/| || | | || | | || || | | | |||||| | || |||||| | | | || || || | | | | |||| | | |
| | | | || /-++--+--+----++---+--+-----++--+-+-++--+\| || || | | | |||||| | || |||||| | | | || || /++--+-+--+-+-++++-+-+\|
| | | | || | || |/-+----++---+--+-----++--+-+-++--+++---++--------++---+------+--+-++++++-+--\|| |||||| | | | || || ||| | | | | |||| | |||
| | | | || | || || | || | | || | ^ || ||| || || | | | |||||| | ||| |||||| | | | || || ||| | | | | |||| | |||
| | | | || | || || | || | | || | | || ||| || || | | | |||||| | ||\--++++++--+-+-+---++-++--+++--+-+--+-/ |||| | |||
| | | | || | \+--++-+----++---+--+-----++--+-+-+/ ||| || /------++---+------+--+-++++++-+--++<--++++++--+-+-+---++-++--+++--+-+--+---++++-+-+++-\
| | | | || | | || | || | | || | | | ||| || | || | | | |||\++-+--++---++++++--+-+-+---++-+/ ||| | | | |||| | ||| |
\-+-+-+-++--+--+--++-+----++---+--+-----++--+-+-+---/|| || | || | | | ||| || | || |||||| | | | |\-+---+++--+-+--+---++++-+-/|| |
| | | || | | || | || | | || | | \----++---++-+------+/ | | | ||| || | || |\++++--+-+-+---+--+---+++--+-/ | |||| | || |
| | | || | | || | || | | || | | || || | | | | | ||| || | || | |||| \-+-+---+--+---+++--+----+---/||| | || |
| \-+-++--+--+--++-+----++---+--+-----++--+-+------++---++-+------+----/ | | ||| || | |\---+-++++----+-+---/ | ||| | | ||| | || |
| | || | | || | || | | || | | || || | | | | ||| || | | /+-++++----+-+------+---+++--+----+---\||| | || |
| | || | | || | || | | || | | || || | | | | ||| || | | || |\++----+-+------+---+++--+----+---++++-/ || |
| | || | | || | || | \-----++--+-+------++---++-+------+-----------+--+-+++-++-+--+---++-+-++----+-+------+---+++--+----+---+/|| || |
| | || | | || | || | || | | |\---++-+------+-----------+--+-+++-++-+--+---++-/ || | | | ||| | | | || || |
| | || | | || | || | || \-+------+----++-+------+-----------+--+-+++-++-+--+---+/ || \-+------+---++/ | | | || || |
| | || | | || | || | || | | |\-+------+-----------+--+-+++-++-+--+---+----++------+------+---+/ | | | || || |
| | || | | || | || | || | | | | | | \-+++-++-+--+---+----/| | | | | | | || || |
| | || | | || \----++---+--------++----/ | | | | | /+++-++-+--+---+-----+------+------+---+\ | | | || || |
| | || | | \+------++---+--------+/ /-----+----+--+------+-----------+--\|\++-++-+--+---+-----+------+------+---++---+----+---+-++----+/ |
| | |\--+--+---+------/| | \------+-----+----+--+------+-----------+--++-++-++-+--+---+-----+------+------+---++---+----+---+-+/ | |
| | | | \---+-------+---+--->-----------+-----+----+--+------+-----------+--++-++-++-+--+---+-----+------/ | \+---+----+---+-+-----/ |
| | | | | | | | | | | | | || || || | | | | | | | | | | |
| | | | \-------+---+---------------+-----+----+--+------+-----------+--++-++-++-+--/ | | | | | | | | |
| | | \--------------+---+---------------+-----/ | | | | || || || \------+-----+-------------+----+---+----+---+-/ |
| | | | | | \--+------+-----------+--++-/| || | | | | | | | |
| | | | | | | | | || | \+--------+-----+-------------/ | | | | |
| | | | | | | | | || | | | | | | | | |
\---+-+------------------+---+---------------+-------------+------+-----------+--++--+--+--------+-----/ | | | | |
| \------------------+---+---------------+-------------+------+-----------+--++--+--/ | | | | | |
| | | \-------------+------+-----------+--/| \-----------+------------------------+---+----/ | |
| | | | \-----------+---+--------------+------------------------+---/ | |
| \---+-----------------------------+------------------/ \--------------+------------------------/ | |
\------------------------/ | | | |
| \-------------------------------------/ |
\--------------------------------------------------------------------------------------/

32
input/day15.txt Normal file
View 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

File diff suppressed because it is too large Load Diff

1470
input/day17.txt Normal file

File diff suppressed because it is too large Load Diff

50
input/day18.txt Normal file
View File

@@ -0,0 +1,50 @@
|#..|#...|..|.#..|###|.....#.|.......||#..|....||.
#||..##.#........||#...##.|..###.|.||...|.#.|.|.#.
##.#.###....##....|..||#.||##.|.###|........||.##.
#.|.||#...|..####......|.#|#..#.#|##...||..#..|...
.....#..#.|.####..#..#...|||...||.|...#......#..|.
.|..#..#.......|...#.|...|.##....|#|..#|###..#..#.
.##..#..##..|.#|||.##..|..#.##..|....#..#|.##|.|#.
|#..|#...|...|.|.......#.#......|...|.#.|||.|||#.#
|....#...|..#..#.....#.|..#.#..|#|.#|...|..|#..|#|
.#...##..|#.##......##...#|||..|.....#.|..|...|..#
#.....|..|...||.|.|.....|....#|..|#...#|...#.....#
...|...###.||......|..#|..|...|.##|........#|#|..|
|.|.#.#......||#|||..|#....|#.|...#|..|.|.#|#.|.|.
###.#.|....|.......##.#|###.|#.#..#.|.#...#...###.
|###...|.....#.|.##..#...|#.#.|.##.#........#..|..
|.||.|...##...##|......#..|.##.##|..#..|#..#.##...
#....|#.....|...|...|............#..#|.....|.#.|.#
...#..|..|||#.|.......#|...#...##|.......####.|...
.#..|..#..|....||#.##.....|||...#..|.#..|.#..|..##
....#...##.........#....|..#.......#...|.....##.#.
|...|...|....#|####||###..|.|..|.||.#......#.|#...
.#.#|.|.|....#.....||...||..|...##.#..|.|.#......|
..|.......|||.|..#.#......|.|..##.||....|###....#.
##....#.......#.|#.##.........|.|....#...|.#|.|.#|
|#.##...|||||#.##.#...#.|#...|.||.|...|..#...#..|.
...#||..#.......||..|.###.#.|#......||..|.#.....#.
#..|.||#.#...|..........#.....#...#...###||.#.....
#..#.|###|#|..|##...##.#......#|.#.#|..#.......|#.
.|.....|.|..#.###|.#|.##.....|.|..|..|..#..|...##.
.|........#...#..|.|..||#....|....#..|.|........|#
....#.|...#|||...#......#...##......|#....#.||.#..
.|.....|....#......#.|#.|.|.|..#.#.|..##.#||.....#
.....#...|.#|..#..#|#.#|.|..|.#........#|..#|....#
|.||..##...|#.#||..|..#.|..|..#..|..#.|.#|.#...|#.
...|#.###...#..|#..##..||....#.||..#.|.|#.#..|..||
......|#|.#.#|.|....#..##|##|#...|.#.|.#....##|#..
#..||.....#....#....#.#.....|.....#....|....|...#.
.#....#.##..........|.||.#.....#|#|||.#..#|......|
..||..|....#..........#.|...#|.|#.|#..|#||.#...|#|
..#..#.#|......#|.....||.#..##.|.#..#.||...|.|||..
.#....|....#.|#...#..||..||.##..#.||....|.#|....|.
..#|.|.....#....#..|..||..#..##.|.||..||||#.#..|.|
.|#.|.||........#|.#|#....||..#||#...|..........##
..#|.|..|||..###..|||.#..#.#||||.#.|##...|#......|
..|...#|...|.#.#|.#...#.|..||##.#..#.|...#.#.#|#..
#..#..|##.#|......#...|#|##..#.|...#.#.....#..##..
..#.|..###|.|#.|........|.....|.....#..|.|.#...|.#
..#|.|#.#.|#..|....|#...|.....|........|.|##.|#||#
#.....##.#..#..#...|#||.#.#.#..|....|||.|.|......#
...#|#....|.#.#..##.|.....#....|.|||..##.|.#.|.##.

37
input/day19.txt Normal file
View 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

File diff suppressed because one or more lines are too long

32
input/day21.txt Normal file
View 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

File diff suppressed because it is too large Load Diff

23
input/day24.txt Normal file
View 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

File diff suppressed because it is too large Load Diff

View File

@@ -1,4 +1,5 @@
extern crate chrono;
extern crate itertools;
extern crate regex;
pub mod tasks;

View File

@@ -1,4 +1,3 @@
fn main() {
// aoc_2018::tasks::day05::task1();
aoc_2018::tasks::day05::task2();
aoc_2018::tasks::day24::task2();
}

View File

@@ -1,5 +1,5 @@
use crate::utils;
use std::collections::HashSet;
use utils;
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);
}

View File

@@ -1,6 +1,6 @@
use crate::utils;
use std::collections::HashMap;
use std::collections::HashSet;
use 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();

View File

@@ -1,6 +1,6 @@
use crate::utils;
use regex::Regex;
use std::collections::HashMap;
use 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);
}

View File

@@ -1,8 +1,8 @@
use crate::utils;
use chrono::prelude::*;
use chrono::Duration;
use chrono::NaiveDateTime;
use std::collections::HashMap;
use 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;

View File

@@ -1,15 +1,19 @@
use utils;
use crate::utils;
use std::time::Instant;
pub fn task1() {
let mut input = utils::read_file("input/day05.txt");
let start = Instant::now();
input = reduce(input.as_str());
println!("resulting polymer: {}", input);
println!("Duration: {:?}", Instant::now() - start);
println!("RESULT: {}", input.len());
}
pub fn task2() {
let input = utils::read_file("input/day05.txt");
let start = Instant::now();
let input = reduce(&input);
let best = "abcdefghijklmnopqrstuvwxyz"
.chars()
.map(|c| {
@@ -18,20 +22,23 @@ pub fn task2() {
reduce(
&input
.chars()
.filter(|ch| ch.to_lowercase().next().unwrap() != c)
.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);
println!("Best: {} (length {})", best.0, best.1);
}
fn reduce(input: &str) -> String {
input
.chars()
.fold(Vec::<char>::new(), |mut stack, c| {
.fold(Vec::<char>::with_capacity(input.len()), |mut stack, c| {
let last: Option<char>;
{
if let Some(c) = stack.last() {
@@ -42,13 +49,7 @@ fn reduce(input: &str) -> String {
}
if let Some(last) = last {
if c.is_lowercase()
&& last.is_uppercase()
&& c == last.to_lowercase().next().unwrap()
|| last.is_lowercase()
&& c.is_uppercase()
&& last == c.to_lowercase().next().unwrap()
{
if c.eq_ignore_ascii_case(&last) && c != last {
stack.pop();
} else {
stack.push(c);
@@ -57,6 +58,7 @@ fn reduce(input: &str) -> String {
stack.push(c);
}
stack
}).iter()
})
.iter()
.collect()
}

150
src/tasks/day06.rs Normal file
View File

@@ -0,0 +1,150 @@
use std::cmp::Ordering::{Equal, Greater, Less};
use crate::utils;
pub fn task1() {
use self::Bla::*;
let input = utils::read_file("input/day06.txt");
let coordinates: Vec<(u16, u16)> = input
.lines()
.map(|line| {
let mut split = line.split(", ");
(
split.next().unwrap().parse().unwrap(),
split.next().unwrap().parse().unwrap(),
)
})
.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;
let mut area: Vec<Vec<Bla>> = Vec::new();
for _ in 0..max_x {
let mut vec = Vec::new();
for _ in 0..max_y {
vec.push(Bla::None);
}
area.push(vec);
}
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;
*cell = match *cell {
None => Single(d, (*a, *b)),
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))
} else {
Multi(dd)
}
}
}
}
}
}
let occupation = coordinates
.iter()
.enumerate()
.map(|(_, (a, b))| {
let count = area
.iter()
.flatten()
.filter(|entry| {
if let Single(_, (x, y)) = entry {
a == x && b == y
} else {
false
}
})
.count();
let infinite = area[0].iter().any(|bla| bla.belongs_to_point(*a, *b))
|| area[area.len() - 1]
.iter()
.any(|bla| bla.belongs_to_point(*a, *b))
|| area.iter().any(|line| line[0].belongs_to_point(*a, *b))
|| area
.iter()
.any(|line| line[line.len() - 1].belongs_to_point(*a, *b));
// println!("{} has size {} (infinite: {:?})", i, count, infinite);
(count, infinite)
})
.collect::<Vec<_>>();
println!(
"Overall occupation: {} of {}",
occupation.iter().map(|(count, _)| *count).sum::<usize>(),
area.len() * area[0].len()
);
let result = occupation
.iter()
.filter(|(_, infinite)| !infinite)
.max_by_key(|x| x.0);
println!("{:?}", result); // 5224 too high
}
#[derive(Debug)]
enum Bla {
None,
/// distance, node
Single(u16, (u16, u16)),
/// distance
Multi(u16),
}
impl Bla {
fn belongs_to_point(&self, x: u16, y: u16) -> bool {
match self {
Bla::Single(_, (a, b)) => *a == x && *b == y,
_ => false,
}
}
}
pub fn task2() {
let input = utils::read_file("input/day06.txt");
let coordinates: Vec<(u16, u16)> = input
.lines()
.map(|line| {
let mut split = line.split(", ");
(
split.next().unwrap().parse().unwrap(),
split.next().unwrap().parse().unwrap(),
)
})
.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;
let result: usize = (0..max_x)
.map(|x| {
(0..max_y)
.map(|y| {
coordinates
.iter()
.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)
.count()
})
.sum();
println!("Part 2: {}", result);
}

42
src/tasks/day07.rs Normal file
View File

@@ -0,0 +1,42 @@
use crate::utils;
use std::collections::{HashMap, HashSet};
pub fn task1() {
let input = utils::read_file("input/day07.txt");
let mut tasks: HashSet<char> = HashSet::new();
let dependencies: Vec<(char, char)> = input
.lines()
.map(|line| (line.chars().nth(5).unwrap(), line.chars().nth(36).unwrap()))
.collect();
let mut depends_on: HashMap<char, HashSet<char>> = HashMap::new();
for (a, b) in dependencies {
depends_on.entry(b).or_insert(HashSet::new()).insert(a);
tasks.insert(a);
tasks.insert(b);
}
let mut open: HashSet<char> = tasks
.iter()
.filter(|task| !depends_on.contains_key(task))
.copied()
.collect();
let mut result = String::new();
while !open.is_empty() {
let next = *open.iter().min().unwrap();
open.remove(&next);
result.push(next);
let newly_open: HashSet<char> = depends_on
.iter()
.filter(|(_task, deps)| deps.iter().all(|dep| result.chars().any(|c| c == *dep)))
.map(|(task, _)| *task)
.collect();
open = open.union(&newly_open).copied().collect();
for c in newly_open {
depends_on.remove(&c);
}
}
println!("{}", result);
}

61
src/tasks/day08.rs Normal file
View File

@@ -0,0 +1,61 @@
use crate::utils;
pub fn both() {
let input: Vec<usize> = utils::read_file("input/day08.txt")
.split(' ')
.map(|x| x.parse().unwrap())
.collect();
let (tree, _) = Node::extract_from(&input);
println!("Metadata sum: {}", tree.metadata_sum());
println!("Task2 sum: {}", tree.task2());
}
struct Node {
metadata: Vec<usize>,
children: Vec<Node>,
}
impl Node {
fn extract_from(input: &[usize]) -> (Self, &[usize]) {
let mut rest_input = &input[2..];
let mut num_children: usize = input[0];
let num_meta: usize = input[1];
let mut children = Vec::new();
while num_children > 0 {
let (node, rest) = Node::extract_from(rest_input);
children.push(node);
rest_input = rest;
num_children -= 1;
}
let metadata = rest_input[..num_meta].to_vec();
(Node { metadata, children }, &rest_input[num_meta..])
}
fn metadata_sum(&self) -> usize {
self.metadata.iter().sum::<usize>()
+ self
.children
.iter()
.map(|child| {
let s: usize = child.metadata_sum();
s
})
.sum::<usize>()
}
fn task2(&self) -> usize {
if !self.children.is_empty() {
self.metadata
.iter()
.map(|meta| match self.children.get(*meta - 1) {
Some(child) => child.task2(),
None => 0,
})
.sum()
} else {
self.metadata_sum()
}
}
}

94
src/tasks/day09.rs Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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(&current) {
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
View 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
View 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
View 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
View 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
View 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
View 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(&registers[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
View 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
View 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
View 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
View 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);
}
}

View File

@@ -3,3 +3,23 @@ pub mod day02;
pub mod day03;
pub mod day04;
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;

View File

@@ -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)