Compare commits
58 Commits
864e4f7446
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| 3c1a48fe51 | |||
| 0f9d48314e | |||
| 14fc032ffc | |||
| 0089f4337c | |||
| c8cef9c0ce | |||
| 420b6152fb | |||
| 79ea3c29d0 | |||
| e87d31c941 | |||
| 6e06599c33 | |||
| 3b829649f3 | |||
| 922f2a483c | |||
| 4002297ede | |||
| 9a34cca688 | |||
| 358e185501 | |||
| eeda13a0d6 | |||
| 1686c8a28c | |||
| 7724b14053 | |||
| 6ba67d568c | |||
| 3c72884fac | |||
| 3992bf2e58 | |||
| 357c5d42cc | |||
| f5e98e2851 | |||
|
|
126833bbaa | ||
|
|
333d99539d | ||
|
|
49b43a4fed | ||
|
|
39e2e27533 | ||
|
|
d18cfca5ed | ||
|
|
91e7a8f3fc | ||
|
|
ece3b0ee29 | ||
|
|
a5019f1afb | ||
|
|
d590b1ad1a | ||
|
|
c726b9090f | ||
|
|
7b51854bb2 | ||
|
|
51f16fa7ad | ||
|
|
3f6aec0d67 | ||
|
|
73b612d25b | ||
|
|
73e4d50c51 | ||
|
|
ddd215c9a2 | ||
|
|
2040bc00aa | ||
|
|
f2117fd2a8 | ||
|
|
e8b911fac0 | ||
|
|
71d068ab2c | ||
|
|
83dce003d8 | ||
|
|
9a2531b982 | ||
|
|
b67ed69f7d | ||
|
|
ad3b71b159 | ||
|
|
eb7467f615 | ||
|
|
8849191a6b | ||
|
|
009d1b8f86 | ||
|
|
f28caa727d | ||
|
|
0f17084f18 | ||
|
|
d3ef4235a0 | ||
|
|
3917746851 | ||
|
|
17e0eea8dc | ||
|
|
2dc626e227 | ||
|
|
676fb13a59 | ||
|
|
da5cf69b1b | ||
|
|
0db2018217 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,3 +1,4 @@
|
||||
/target
|
||||
**/*.rs.bk
|
||||
.vscode
|
||||
.idea
|
||||
136
Cargo.lock
generated
136
Cargo.lock
generated
@@ -1,25 +1,149 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "aho-corasick"
|
||||
version = "0.7.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "aoc_2019"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"itertools 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"itertools",
|
||||
"mod_exp",
|
||||
"modinverse",
|
||||
"num-integer",
|
||||
"regex",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
||||
|
||||
[[package]]
|
||||
name = "either"
|
||||
version = "1.5.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bb1f6b1ce1c140482ea30ddd3335fc0024ac7ee112895426e0a629a6c20adfe3"
|
||||
|
||||
[[package]]
|
||||
name = "itertools"
|
||||
version = "0.8.2"
|
||||
version = "0.10.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a9a9d19fa1e79b6215ff29b9d6880b706147f16e9b1dbb1e4e5947b5b02bc5e3"
|
||||
dependencies = [
|
||||
"either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"either",
|
||||
]
|
||||
|
||||
[metadata]
|
||||
"checksum either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "bb1f6b1ce1c140482ea30ddd3335fc0024ac7ee112895426e0a629a6c20adfe3"
|
||||
"checksum itertools 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f56a2d0bc861f9165be4eb3442afd3c236d8a98afd426f65d92324ae1091a484"
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a"
|
||||
|
||||
[[package]]
|
||||
name = "mod_exp"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bb4a3fad6af79fcf8d1417b2f6359d814a173fb413a1bd48ba04208b42b0d8b0"
|
||||
dependencies = [
|
||||
"num",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "modinverse"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2f62f577f148cc1a9466e7065a22e59466a7d537cceba5e77e57181d0f706633"
|
||||
dependencies = [
|
||||
"num-integer",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b8536030f9fea7127f841b45bb6243b27255787fb4eb83958aa1ef9d2fdc0c36"
|
||||
dependencies = [
|
||||
"num-complex",
|
||||
"num-integer",
|
||||
"num-iter",
|
||||
"num-rational",
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-complex"
|
||||
version = "0.2.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b6b19411a9719e753aff12e5187b74d60d3dc449ec3f4dc21e3989c3f554bc95"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-integer"
|
||||
version = "0.1.44"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-iter"
|
||||
version = "0.1.43"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7d03e6c028c5dc5cac6e2dec0efda81fc887605bb3d884578bb6d6bf7514e252"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"num-integer",
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-rational"
|
||||
version = "0.2.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5c000134b5dbf44adc5cb772486d335293351644b801551abe8f75c84cfa4aef"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"num-integer",
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
version = "0.2.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.5.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1a11647b6b25ff05a515cb92c365cec08801e83423a235b51e231e1808747286"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
"regex-syntax",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-syntax"
|
||||
version = "0.6.25"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b"
|
||||
|
||||
@@ -2,9 +2,13 @@
|
||||
name = "aoc_2019"
|
||||
version = "0.1.0"
|
||||
authors = ["Johannes <jschaef@mail.uni-paderborn.de>"]
|
||||
edition = "2018"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
itertools = "0.8.2"
|
||||
itertools = "0.10.3"
|
||||
regex = "1.5.5"
|
||||
num-integer = "0.1.44"
|
||||
modinverse = "0.1.1"
|
||||
mod_exp = "1.0.1"
|
||||
|
||||
1
input/day07.txt
Normal file
1
input/day07.txt
Normal file
@@ -0,0 +1 @@
|
||||
3,8,1001,8,10,8,105,1,0,0,21,42,63,76,101,114,195,276,357,438,99999,3,9,101,2,9,9,102,5,9,9,1001,9,3,9,1002,9,5,9,4,9,99,3,9,101,4,9,9,102,5,9,9,1001,9,5,9,102,2,9,9,4,9,99,3,9,1001,9,3,9,1002,9,5,9,4,9,99,3,9,1002,9,2,9,101,5,9,9,102,3,9,9,101,2,9,9,1002,9,3,9,4,9,99,3,9,101,3,9,9,102,2,9,9,4,9,99,3,9,1001,9,2,9,4,9,3,9,102,2,9,9,4,9,3,9,101,2,9,9,4,9,3,9,102,2,9,9,4,9,3,9,101,1,9,9,4,9,3,9,1001,9,2,9,4,9,3,9,1001,9,1,9,4,9,3,9,1001,9,2,9,4,9,3,9,1001,9,2,9,4,9,3,9,1001,9,1,9,4,9,99,3,9,102,2,9,9,4,9,3,9,1001,9,2,9,4,9,3,9,102,2,9,9,4,9,3,9,1002,9,2,9,4,9,3,9,1001,9,1,9,4,9,3,9,102,2,9,9,4,9,3,9,1002,9,2,9,4,9,3,9,102,2,9,9,4,9,3,9,1002,9,2,9,4,9,3,9,102,2,9,9,4,9,99,3,9,102,2,9,9,4,9,3,9,102,2,9,9,4,9,3,9,1002,9,2,9,4,9,3,9,1001,9,2,9,4,9,3,9,1002,9,2,9,4,9,3,9,1001,9,1,9,4,9,3,9,1002,9,2,9,4,9,3,9,1002,9,2,9,4,9,3,9,101,2,9,9,4,9,3,9,1001,9,2,9,4,9,99,3,9,1001,9,1,9,4,9,3,9,101,2,9,9,4,9,3,9,102,2,9,9,4,9,3,9,1001,9,2,9,4,9,3,9,1001,9,1,9,4,9,3,9,102,2,9,9,4,9,3,9,1001,9,2,9,4,9,3,9,1001,9,2,9,4,9,3,9,102,2,9,9,4,9,3,9,1001,9,2,9,4,9,99,3,9,102,2,9,9,4,9,3,9,101,1,9,9,4,9,3,9,1002,9,2,9,4,9,3,9,1002,9,2,9,4,9,3,9,1002,9,2,9,4,9,3,9,101,2,9,9,4,9,3,9,1001,9,2,9,4,9,3,9,101,2,9,9,4,9,3,9,1002,9,2,9,4,9,3,9,101,2,9,9,4,9,99
|
||||
1
input/day09.txt
Normal file
1
input/day09.txt
Normal file
@@ -0,0 +1 @@
|
||||
1102,34463338,34463338,63,1007,63,34463338,63,1005,63,53,1102,1,3,1000,109,988,209,12,9,1000,209,6,209,3,203,0,1008,1000,1,63,1005,63,65,1008,1000,2,63,1005,63,904,1008,1000,0,63,1005,63,58,4,25,104,0,99,4,0,104,0,99,4,17,104,0,99,0,0,1101,0,0,1020,1101,34,0,1004,1101,0,26,1008,1102,1,37,1011,1101,39,0,1018,1102,587,1,1022,1101,1,0,1021,1102,22,1,1012,1101,0,33,1014,1101,24,0,1016,1101,0,752,1029,1101,36,0,1002,1101,35,0,1006,1101,32,0,1009,1102,38,1,1003,1102,584,1,1023,1101,0,20,1001,1102,892,1,1025,1102,29,1,1000,1101,411,0,1026,1102,1,901,1024,1101,0,761,1028,1101,23,0,1017,1102,30,1,1013,1101,0,27,1015,1102,28,1,1005,1101,408,0,1027,1101,25,0,1007,1102,31,1,1019,1101,0,21,1010,109,5,1207,-2,39,63,1005,63,199,4,187,1105,1,203,1001,64,1,64,1002,64,2,64,109,12,21102,40,1,-1,1008,1016,40,63,1005,63,229,4,209,1001,64,1,64,1106,0,229,1002,64,2,64,109,-5,1207,-5,24,63,1005,63,249,1001,64,1,64,1106,0,251,4,235,1002,64,2,64,109,-14,2102,1,6,63,1008,63,32,63,1005,63,271,1106,0,277,4,257,1001,64,1,64,1002,64,2,64,109,2,1202,1,1,63,1008,63,20,63,1005,63,303,4,283,1001,64,1,64,1106,0,303,1002,64,2,64,109,7,2108,34,2,63,1005,63,319,1106,0,325,4,309,1001,64,1,64,1002,64,2,64,109,6,2101,0,-6,63,1008,63,24,63,1005,63,349,1001,64,1,64,1105,1,351,4,331,1002,64,2,64,109,4,21107,41,42,0,1005,1017,369,4,357,1105,1,373,1001,64,1,64,1002,64,2,64,109,5,21101,42,0,-5,1008,1017,41,63,1005,63,397,1001,64,1,64,1106,0,399,4,379,1002,64,2,64,109,9,2106,0,-4,1106,0,417,4,405,1001,64,1,64,1002,64,2,64,109,-20,21108,43,43,0,1005,1011,435,4,423,1105,1,439,1001,64,1,64,1002,64,2,64,109,-15,2102,1,8,63,1008,63,34,63,1005,63,465,4,445,1001,64,1,64,1105,1,465,1002,64,2,64,109,3,1201,6,0,63,1008,63,28,63,1005,63,491,4,471,1001,64,1,64,1106,0,491,1002,64,2,64,109,18,21108,44,46,0,1005,1017,511,1001,64,1,64,1106,0,513,4,497,1002,64,2,64,109,12,1205,-8,527,4,519,1105,1,531,1001,64,1,64,1002,64,2,64,109,-17,1208,-3,32,63,1005,63,553,4,537,1001,64,1,64,1105,1,553,1002,64,2,64,109,-13,1208,10,31,63,1005,63,573,1001,64,1,64,1105,1,575,4,559,1002,64,2,64,109,17,2105,1,7,1105,1,593,4,581,1001,64,1,64,1002,64,2,64,109,-8,2107,19,-7,63,1005,63,615,4,599,1001,64,1,64,1105,1,615,1002,64,2,64,109,4,1206,8,629,4,621,1106,0,633,1001,64,1,64,1002,64,2,64,109,-2,2101,0,-6,63,1008,63,34,63,1005,63,655,4,639,1105,1,659,1001,64,1,64,1002,64,2,64,109,10,1205,0,671,1105,1,677,4,665,1001,64,1,64,1002,64,2,64,109,-21,2107,26,8,63,1005,63,693,1106,0,699,4,683,1001,64,1,64,1002,64,2,64,109,19,1201,-9,0,63,1008,63,30,63,1005,63,719,1105,1,725,4,705,1001,64,1,64,1002,64,2,64,109,9,1206,-6,741,1001,64,1,64,1106,0,743,4,731,1002,64,2,64,109,-5,2106,0,6,4,749,1001,64,1,64,1105,1,761,1002,64,2,64,109,-14,1202,-1,1,63,1008,63,27,63,1005,63,781,1105,1,787,4,767,1001,64,1,64,1002,64,2,64,109,1,21107,45,44,5,1005,1014,807,1001,64,1,64,1105,1,809,4,793,1002,64,2,64,109,8,21101,46,0,0,1008,1017,46,63,1005,63,835,4,815,1001,64,1,64,1106,0,835,1002,64,2,64,109,-26,2108,20,10,63,1005,63,857,4,841,1001,64,1,64,1106,0,857,1002,64,2,64,109,24,21102,47,1,-5,1008,1010,46,63,1005,63,881,1001,64,1,64,1106,0,883,4,863,1002,64,2,64,109,6,2105,1,3,4,889,1001,64,1,64,1105,1,901,4,64,99,21102,27,1,1,21101,915,0,0,1105,1,922,21201,1,29830,1,204,1,99,109,3,1207,-2,3,63,1005,63,964,21201,-2,-1,1,21101,0,942,0,1105,1,922,21202,1,1,-1,21201,-2,-3,1,21102,1,957,0,1105,1,922,22201,1,-1,-2,1105,1,968,21201,-2,0,-2,109,-3,2106,0,0
|
||||
24
input/day10.txt
Normal file
24
input/day10.txt
Normal file
@@ -0,0 +1,24 @@
|
||||
##.##..#.####...#.#.####
|
||||
##.###..##.#######..##..
|
||||
..######.###.#.##.######
|
||||
.#######.####.##.#.###.#
|
||||
..#...##.#.....#####..##
|
||||
#..###.#...#..###.#..#..
|
||||
###..#.##.####.#..##..##
|
||||
.##.##....###.#..#....#.
|
||||
########..#####..#######
|
||||
##..#..##.#..##.#.#.#..#
|
||||
##.#.##.######.#####....
|
||||
###.##...#.##...#.######
|
||||
###...##.####..##..#####
|
||||
##.#...#.#.....######.##
|
||||
.#...####..####.##...##.
|
||||
#.#########..###..#.####
|
||||
#.##..###.#.######.#####
|
||||
##..##.##...####.#...##.
|
||||
###...###.##.####.#.##..
|
||||
####.#.....###..#.####.#
|
||||
##.####..##.#.##..##.#.#
|
||||
#####..#...####..##..#.#
|
||||
.##.##.##...###.##...###
|
||||
..###.########.#.###..#.
|
||||
1
input/day11.txt
Normal file
1
input/day11.txt
Normal file
@@ -0,0 +1 @@
|
||||
3,8,1005,8,361,1106,0,11,0,0,0,104,1,104,0,3,8,102,-1,8,10,101,1,10,10,4,10,108,0,8,10,4,10,1001,8,0,28,2,1104,18,10,1006,0,65,3,8,102,-1,8,10,1001,10,1,10,4,10,108,1,8,10,4,10,1001,8,0,57,1,1101,5,10,2,108,15,10,2,102,12,10,3,8,1002,8,-1,10,101,1,10,10,4,10,108,0,8,10,4,10,102,1,8,91,2,1005,4,10,2,1107,10,10,1006,0,16,2,109,19,10,3,8,1002,8,-1,10,1001,10,1,10,4,10,1008,8,1,10,4,10,101,0,8,129,1,104,3,10,1,1008,9,10,1006,0,65,1,104,5,10,3,8,1002,8,-1,10,101,1,10,10,4,10,108,1,8,10,4,10,102,1,8,165,1,1106,11,10,1,1106,18,10,1,8,11,10,1,4,11,10,3,8,1002,8,-1,10,101,1,10,10,4,10,108,1,8,10,4,10,1001,8,0,203,2,1003,11,10,1,1105,13,10,1,101,13,10,3,8,102,-1,8,10,101,1,10,10,4,10,108,0,8,10,4,10,101,0,8,237,2,7,4,10,1006,0,73,1,1003,7,10,1006,0,44,3,8,102,-1,8,10,1001,10,1,10,4,10,108,1,8,10,4,10,101,0,8,273,2,108,14,10,3,8,102,-1,8,10,101,1,10,10,4,10,108,0,8,10,4,10,102,1,8,299,1,1107,6,10,1006,0,85,1,1107,20,10,1,1008,18,10,3,8,1002,8,-1,10,1001,10,1,10,4,10,1008,8,0,10,4,10,1001,8,0,337,2,107,18,10,101,1,9,9,1007,9,951,10,1005,10,15,99,109,683,104,0,104,1,21102,1,825594852248,1,21101,378,0,0,1105,1,482,21101,0,387240006552,1,21101,0,389,0,1106,0,482,3,10,104,0,104,1,3,10,104,0,104,0,3,10,104,0,104,1,3,10,104,0,104,1,3,10,104,0,104,0,3,10,104,0,104,1,21101,0,29032025091,1,21101,436,0,0,1106,0,482,21101,29033143299,0,1,21102,1,447,0,1105,1,482,3,10,104,0,104,0,3,10,104,0,104,0,21101,988669698916,0,1,21101,0,470,0,1106,0,482,21101,0,709052072804,1,21102,1,481,0,1106,0,482,99,109,2,21202,-1,1,1,21101,0,40,2,21101,0,513,3,21101,503,0,0,1106,0,546,109,-2,2105,1,0,0,1,0,0,1,109,2,3,10,204,-1,1001,508,509,524,4,0,1001,508,1,508,108,4,508,10,1006,10,540,1101,0,0,508,109,-2,2105,1,0,0,109,4,1202,-1,1,545,1207,-3,0,10,1006,10,563,21102,0,1,-3,21202,-3,1,1,22101,0,-2,2,21102,1,1,3,21101,582,0,0,1105,1,587,109,-4,2106,0,0,109,5,1207,-3,1,10,1006,10,610,2207,-4,-2,10,1006,10,610,21202,-4,1,-4,1106,0,678,22102,1,-4,1,21201,-3,-1,2,21202,-2,2,3,21102,629,1,0,1106,0,587,22102,1,1,-4,21101,0,1,-1,2207,-4,-2,10,1006,10,648,21102,0,1,-1,22202,-2,-1,-2,2107,0,-3,10,1006,10,670,21202,-1,1,1,21101,670,0,0,105,1,545,21202,-2,-1,-2,22201,-4,-2,-4,109,-5,2106,0,0
|
||||
4
input/day12.txt
Normal file
4
input/day12.txt
Normal file
@@ -0,0 +1,4 @@
|
||||
<x=19, y=-10, z=7>
|
||||
<x=1, y=2, z=-3>
|
||||
<x=14, y=-4, z=1>
|
||||
<x=8, y=7, z=-6>
|
||||
1
input/day13.txt
Normal file
1
input/day13.txt
Normal file
File diff suppressed because one or more lines are too long
54
input/day14.txt
Normal file
54
input/day14.txt
Normal file
@@ -0,0 +1,54 @@
|
||||
156 ORE => 6 TLFQZ
|
||||
1 SZFV => 5 TNXGD
|
||||
1 BQLJ, 3 VNKPF => 8 BQXZ
|
||||
43 FPRFS, 5 CQJT, 20 LDKTQ, 48 ZPBLH, 21 MFVG, 43 WLWZQ, 1 ZWZQ, 11 PQZJP, 56 CTJGD, 35 SGDVW => 1 FUEL
|
||||
11 BQXZ, 1 PRCSN => 7 DVFD
|
||||
7 VWXB, 2 PRCSN, 24 VJSR, 9 MDWCG, 4 MFVG => 4 ZWZQ
|
||||
32 BQXZ, 5 XDSHP, 16 KTXJR, 7 VJSR, 3 MDWCG, 11 KZFZG, 3 NVBN => 5 ZPBLH
|
||||
2 BQLJ, 2 RSKH, 3 VWXB => 2 GWXCF
|
||||
6 PRCSN, 1 NCRZ => 8 VJSR
|
||||
5 TMQLD => 9 VDQL
|
||||
9 MZQZS, 1 FLRB => 5 BQLJ
|
||||
4 KLHS => 5 PQZJP
|
||||
1 WJTS, 1 NCRZ, 27 XDSHP => 8 MFVG
|
||||
1 FNXMV, 30 FPKM => 8 RDMDL
|
||||
1 TNXGD, 21 XBCLW, 5 CWNV => 3 RSKH
|
||||
4 KQFPJ => 2 NCRZ
|
||||
10 CWNV, 8 HSXW => 9 FNXMV
|
||||
2 TNXGD, 4 CWNV, 13 VJSR => 8 KTXJR
|
||||
3 NCRZ, 1 GWXCF, 8 NVBN, 6 MDWCG, 3 VWXB, 4 KTXJR, 4 DVFD, 3 QXCV => 9 FPRFS
|
||||
5 MZQZS, 9 TBVRN => 7 SZFV
|
||||
37 GWXCF, 15 RDMDL, 2 MDWCG => 7 CQJT
|
||||
1 VDQL, 2 HSXW => 4 NVBN
|
||||
18 QHMTL, 7 FLRB, 1 SZFV => 3 FPKM
|
||||
6 VDQL => 1 FNCN
|
||||
3 QPHT => 7 LDKTQ
|
||||
1 TLFQZ => 8 FWFR
|
||||
7 VDQL, 8 KZFZG => 3 HSXW
|
||||
9 TBVRN => 7 MZQZS
|
||||
1 FLRB, 44 VNKPF, 1 LVZF => 8 QXCV
|
||||
1 WLWZQ, 3 TBVRN, 4 TLFQZ => 9 KQFPJ
|
||||
1 BQLJ, 1 PRCSN, 8 DHTNG => 5 VWXB
|
||||
1 XDSHP, 6 NVBN => 1 BDGC
|
||||
8 PRCSN, 1 DHTNG => 2 WJTS
|
||||
19 DHTNG, 22 WLWZQ => 9 LVZF
|
||||
185 ORE => 7 WLWZQ
|
||||
1 TMQLD, 1 MZQZS => 8 KZFZG
|
||||
111 ORE => 4 TBVRN
|
||||
31 VDQL, 14 MZQZS => 7 XBCLW
|
||||
6 VDQL, 3 KVPK => 9 SGDVW
|
||||
1 FNCN => 6 QMKT
|
||||
1 FNCN, 3 TMQLD => 7 VNKPF
|
||||
2 QPHT => 6 VQXCJ
|
||||
2 LDKTQ, 3 VQXCJ => 5 FLRB
|
||||
1 FNCN, 3 FPKM, 1 SZFV => 2 DHTNG
|
||||
1 KZFZG => 9 QHMTL
|
||||
141 ORE => 5 QPHT
|
||||
16 TNXGD => 9 CWNV
|
||||
1 KQFPJ, 29 FWFR => 2 KVPK
|
||||
1 TNXGD, 7 KLHS => 2 XDSHP
|
||||
7 WJTS => 6 MDWCG
|
||||
3 BDGC, 3 XDSHP, 1 NCRZ => 4 CTJGD
|
||||
3 QMKT => 6 PRCSN
|
||||
24 FWFR => 2 TMQLD
|
||||
8 VNKPF => 3 KLHS
|
||||
1
input/day15.txt
Normal file
1
input/day15.txt
Normal file
@@ -0,0 +1 @@
|
||||
3,1033,1008,1033,1,1032,1005,1032,31,1008,1033,2,1032,1005,1032,58,1008,1033,3,1032,1005,1032,81,1008,1033,4,1032,1005,1032,104,99,1001,1034,0,1039,1002,1036,1,1041,1001,1035,-1,1040,1008,1038,0,1043,102,-1,1043,1032,1,1037,1032,1042,1106,0,124,1001,1034,0,1039,102,1,1036,1041,1001,1035,1,1040,1008,1038,0,1043,1,1037,1038,1042,1105,1,124,1001,1034,-1,1039,1008,1036,0,1041,102,1,1035,1040,1002,1038,1,1043,101,0,1037,1042,1105,1,124,1001,1034,1,1039,1008,1036,0,1041,102,1,1035,1040,1001,1038,0,1043,101,0,1037,1042,1006,1039,217,1006,1040,217,1008,1039,40,1032,1005,1032,217,1008,1040,40,1032,1005,1032,217,1008,1039,33,1032,1006,1032,165,1008,1040,33,1032,1006,1032,165,1101,0,2,1044,1106,0,224,2,1041,1043,1032,1006,1032,179,1102,1,1,1044,1105,1,224,1,1041,1043,1032,1006,1032,217,1,1042,1043,1032,1001,1032,-1,1032,1002,1032,39,1032,1,1032,1039,1032,101,-1,1032,1032,101,252,1032,211,1007,0,42,1044,1106,0,224,1102,0,1,1044,1106,0,224,1006,1044,247,1001,1039,0,1034,1001,1040,0,1035,1001,1041,0,1036,1001,1043,0,1038,102,1,1042,1037,4,1044,1106,0,0,6,28,51,33,63,27,52,11,53,13,96,8,87,11,23,65,43,11,13,9,37,66,68,40,19,41,6,90,28,19,38,86,38,22,7,44,36,23,17,1,16,54,36,74,14,79,2,14,83,10,38,19,62,66,27,56,33,52,47,98,41,39,77,83,48,29,49,15,80,59,9,72,79,55,24,66,50,24,27,56,37,41,13,72,35,13,64,70,5,66,78,37,78,24,43,93,22,41,30,58,14,45,6,27,44,48,40,52,31,12,3,72,7,14,59,35,17,63,34,79,93,17,54,98,35,21,91,25,32,77,10,31,88,17,35,79,96,11,83,15,48,9,19,64,24,65,86,32,71,22,88,55,31,18,88,68,34,40,94,1,71,24,40,44,28,43,4,98,21,80,17,53,2,94,6,43,59,23,66,63,12,30,45,39,93,41,85,43,51,18,99,59,86,40,36,26,94,33,41,28,66,79,81,11,61,46,32,72,71,47,39,22,69,60,36,50,12,44,28,41,79,17,6,74,8,56,39,33,67,23,20,51,12,7,26,57,1,92,80,11,52,19,5,54,13,41,56,37,22,57,43,18,97,27,83,30,3,77,85,66,64,17,99,27,25,95,40,81,97,13,35,46,14,25,63,36,72,87,20,96,29,2,69,90,27,27,91,52,14,14,73,55,4,73,19,85,39,84,23,23,90,40,5,88,53,77,8,92,11,82,66,6,27,84,53,38,93,34,37,58,20,43,25,73,78,30,17,92,54,38,26,67,16,30,28,79,77,26,3,15,82,59,34,34,18,44,34,33,83,35,90,31,58,44,16,18,65,8,70,90,32,46,21,41,54,39,43,93,23,99,11,43,50,98,33,34,53,54,53,16,39,88,53,36,69,85,26,44,38,62,98,6,79,26,35,49,67,22,11,74,35,80,4,50,18,54,4,10,4,58,4,46,20,15,77,73,11,41,58,85,39,87,37,73,36,36,67,28,12,17,34,53,38,89,96,34,39,67,64,33,81,37,74,88,20,84,94,53,39,57,73,13,76,1,35,14,73,29,29,23,73,52,16,85,87,33,48,13,2,93,78,7,17,60,49,13,36,89,40,25,44,55,26,81,37,31,84,31,62,2,66,77,23,88,11,81,9,63,46,19,35,54,17,85,24,1,86,28,72,1,1,61,27,38,81,8,67,82,3,11,77,35,62,83,20,28,61,37,37,92,22,72,76,37,52,17,62,68,38,53,2,57,82,67,25,11,59,3,49,97,1,40,91,75,7,85,98,33,90,1,37,57,14,34,67,65,20,85,10,18,86,20,52,84,24,20,70,10,64,16,64,2,15,85,36,28,7,87,47,44,9,29,54,83,28,37,81,68,18,12,80,26,98,97,25,86,69,39,70,22,23,72,15,56,94,27,14,13,8,50,73,90,24,95,14,41,57,22,67,25,80,46,39,84,80,19,22,63,53,45,62,21,84,36,69,41,44,96,38,92,21,23,64,35,11,75,57,88,6,7,90,10,36,19,68,78,23,62,34,49,4,80,38,2,70,48,39,55,20,22,39,8,90,64,38,39,47,41,63,72,5,10,72,88,35,50,5,66,30,80,74,23,97,39,98,19,17,85,38,34,62,37,25,58,15,93,37,13,71,72,72,4,84,40,92,61,88,9,7,62,59,87,17,36,39,43,21,11,16,58,16,58,20,66,18,83,33,66,62,90,32,74,15,58,62,43,16,66,22,90,2,68,30,54,18,59,22,50,12,60,35,66,77,51,36,64,89,82,21,85,0,0,21,21,1,10,1,0,0,0,0,0,0
|
||||
1
input/day17.txt
Normal file
1
input/day17.txt
Normal file
@@ -0,0 +1 @@
|
||||
1,330,331,332,109,3132,1102,1,1182,16,1101,1467,0,24,101,0,0,570,1006,570,36,101,0,571,0,1001,570,-1,570,1001,24,1,24,1105,1,18,1008,571,0,571,1001,16,1,16,1008,16,1467,570,1006,570,14,21102,58,1,0,1106,0,786,1006,332,62,99,21102,1,333,1,21102,73,1,0,1106,0,579,1101,0,0,572,1101,0,0,573,3,574,101,1,573,573,1007,574,65,570,1005,570,151,107,67,574,570,1005,570,151,1001,574,-64,574,1002,574,-1,574,1001,572,1,572,1007,572,11,570,1006,570,165,101,1182,572,127,1001,574,0,0,3,574,101,1,573,573,1008,574,10,570,1005,570,189,1008,574,44,570,1006,570,158,1105,1,81,21101,0,340,1,1106,0,177,21101,0,477,1,1105,1,177,21101,514,0,1,21102,176,1,0,1106,0,579,99,21102,1,184,0,1106,0,579,4,574,104,10,99,1007,573,22,570,1006,570,165,1002,572,1,1182,21102,1,375,1,21101,0,211,0,1106,0,579,21101,1182,11,1,21102,1,222,0,1106,0,979,21102,388,1,1,21102,233,1,0,1105,1,579,21101,1182,22,1,21101,244,0,0,1106,0,979,21102,1,401,1,21101,255,0,0,1105,1,579,21101,1182,33,1,21102,266,1,0,1105,1,979,21102,1,414,1,21102,1,277,0,1105,1,579,3,575,1008,575,89,570,1008,575,121,575,1,575,570,575,3,574,1008,574,10,570,1006,570,291,104,10,21102,1,1182,1,21101,313,0,0,1105,1,622,1005,575,327,1101,0,1,575,21102,1,327,0,1106,0,786,4,438,99,0,1,1,6,77,97,105,110,58,10,33,10,69,120,112,101,99,116,101,100,32,102,117,110,99,116,105,111,110,32,110,97,109,101,32,98,117,116,32,103,111,116,58,32,0,12,70,117,110,99,116,105,111,110,32,65,58,10,12,70,117,110,99,116,105,111,110,32,66,58,10,12,70,117,110,99,116,105,111,110,32,67,58,10,23,67,111,110,116,105,110,117,111,117,115,32,118,105,100,101,111,32,102,101,101,100,63,10,0,37,10,69,120,112,101,99,116,101,100,32,82,44,32,76,44,32,111,114,32,100,105,115,116,97,110,99,101,32,98,117,116,32,103,111,116,58,32,36,10,69,120,112,101,99,116,101,100,32,99,111,109,109,97,32,111,114,32,110,101,119,108,105,110,101,32,98,117,116,32,103,111,116,58,32,43,10,68,101,102,105,110,105,116,105,111,110,115,32,109,97,121,32,98,101,32,97,116,32,109,111,115,116,32,50,48,32,99,104,97,114,97,99,116,101,114,115,33,10,94,62,118,60,0,1,0,-1,-1,0,1,0,0,0,0,0,0,1,0,10,0,109,4,1202,-3,1,587,20102,1,0,-1,22101,1,-3,-3,21101,0,0,-2,2208,-2,-1,570,1005,570,617,2201,-3,-2,609,4,0,21201,-2,1,-2,1105,1,597,109,-4,2105,1,0,109,5,2102,1,-4,630,20102,1,0,-2,22101,1,-4,-4,21101,0,0,-3,2208,-3,-2,570,1005,570,781,2201,-4,-3,653,20101,0,0,-1,1208,-1,-4,570,1005,570,709,1208,-1,-5,570,1005,570,734,1207,-1,0,570,1005,570,759,1206,-1,774,1001,578,562,684,1,0,576,576,1001,578,566,692,1,0,577,577,21101,702,0,0,1105,1,786,21201,-1,-1,-1,1105,1,676,1001,578,1,578,1008,578,4,570,1006,570,724,1001,578,-4,578,21101,0,731,0,1106,0,786,1106,0,774,1001,578,-1,578,1008,578,-1,570,1006,570,749,1001,578,4,578,21101,0,756,0,1105,1,786,1105,1,774,21202,-1,-11,1,22101,1182,1,1,21102,1,774,0,1106,0,622,21201,-3,1,-3,1106,0,640,109,-5,2106,0,0,109,7,1005,575,802,21002,576,1,-6,20101,0,577,-5,1105,1,814,21101,0,0,-1,21101,0,0,-5,21102,1,0,-6,20208,-6,576,-2,208,-5,577,570,22002,570,-2,-2,21202,-5,45,-3,22201,-6,-3,-3,22101,1467,-3,-3,1201,-3,0,843,1005,0,863,21202,-2,42,-4,22101,46,-4,-4,1206,-2,924,21102,1,1,-1,1105,1,924,1205,-2,873,21101,0,35,-4,1105,1,924,2102,1,-3,878,1008,0,1,570,1006,570,916,1001,374,1,374,2102,1,-3,895,1102,2,1,0,1201,-3,0,902,1001,438,0,438,2202,-6,-5,570,1,570,374,570,1,570,438,438,1001,578,558,921,21001,0,0,-4,1006,575,959,204,-4,22101,1,-6,-6,1208,-6,45,570,1006,570,814,104,10,22101,1,-5,-5,1208,-5,37,570,1006,570,810,104,10,1206,-1,974,99,1206,-1,974,1102,1,1,575,21101,0,973,0,1106,0,786,99,109,-7,2105,1,0,109,6,21101,0,0,-4,21102,0,1,-3,203,-2,22101,1,-3,-3,21208,-2,82,-1,1205,-1,1030,21208,-2,76,-1,1205,-1,1037,21207,-2,48,-1,1205,-1,1124,22107,57,-2,-1,1205,-1,1124,21201,-2,-48,-2,1106,0,1041,21102,1,-4,-2,1105,1,1041,21101,0,-5,-2,21201,-4,1,-4,21207,-4,11,-1,1206,-1,1138,2201,-5,-4,1059,1202,-2,1,0,203,-2,22101,1,-3,-3,21207,-2,48,-1,1205,-1,1107,22107,57,-2,-1,1205,-1,1107,21201,-2,-48,-2,2201,-5,-4,1090,20102,10,0,-1,22201,-2,-1,-2,2201,-5,-4,1103,2101,0,-2,0,1106,0,1060,21208,-2,10,-1,1205,-1,1162,21208,-2,44,-1,1206,-1,1131,1106,0,989,21102,1,439,1,1105,1,1150,21101,0,477,1,1106,0,1150,21102,1,514,1,21102,1,1149,0,1105,1,579,99,21101,1157,0,0,1106,0,579,204,-2,104,10,99,21207,-3,22,-1,1206,-1,1138,1201,-5,0,1176,2102,1,-4,0,109,-6,2106,0,0,8,9,36,1,7,1,36,1,1,13,30,1,7,1,5,1,30,1,7,1,5,1,7,11,12,1,7,1,5,1,7,1,9,1,12,1,7,1,5,1,7,1,1,13,8,1,7,1,5,1,7,1,1,1,7,1,3,1,8,1,7,1,5,1,7,1,1,1,7,1,3,1,8,1,7,1,5,1,7,1,1,1,7,1,3,10,5,9,1,13,3,1,3,1,14,1,1,1,7,1,5,1,1,1,3,1,3,1,3,1,8,9,5,9,1,1,3,1,3,1,3,1,8,1,5,1,7,1,1,1,7,1,3,1,3,1,3,1,8,1,5,1,7,1,1,1,7,1,3,1,3,1,3,1,8,1,5,1,7,1,1,1,7,1,3,1,3,1,3,1,8,1,5,1,7,1,1,1,7,9,3,1,8,1,5,1,7,1,1,1,11,1,7,1,8,1,5,1,7,1,1,11,1,9,8,1,5,1,7,1,11,1,18,13,1,1,11,1,24,1,5,1,1,1,11,1,24,9,11,1,30,1,13,1,30,1,13,1,30,1,13,1,30,1,13,9,22,1,21,1,22,11,11,1,32,1,11,1,32,1,11,1,32,1,11,1,32,1,11,1,32,1,11,1,32,1,11,1,32,1,11,1,32,13,2
|
||||
81
input/day18.txt
Normal file
81
input/day18.txt
Normal file
@@ -0,0 +1,81 @@
|
||||
#################################################################################
|
||||
#.#...#.....#...............#.....#v....#.........#p....#...#...................#
|
||||
#.#.#.#.#.#.#M#############.#.###.#####.#####.###.#.###.#.#.#################.#.#
|
||||
#..n#...#.#...#.#...........#...#.......#.....#.....#.#...#...#.......#...#...#.#
|
||||
#########.#####.#.###########.#.#######.#.###########.#######.#C#####.#.#.#.###.#
|
||||
#.........#.#.....#.........#.#.#.......#...........#...........#...#.#.#...#...#
|
||||
#.#########.#.#########.#####.#W###.###############.###.#########.###.#.#####.###
|
||||
#.Y...#...#...#.......#z......#...#.#...#...#.....#..d#.#.#..x..#...#.#.#...#.#.#
|
||||
#####.#.#.#.###.#.###.#####.#####.#.#.#.#.#.#.###.###.#.#.#.###.#.#.#.#.#.#.#.#.#
|
||||
#.....#.#...#...#.#.#.....#...#...#.#.#.#.#...#.......#...#.#...#.#.....#.#...#.#
|
||||
#.#######.#######.#.#####.#####.#####.#.#.#############.###.#.###.#########.###.#
|
||||
#...#...#.#...#...#.#...#.....#...B...#.#.....#...#.....#...#.#.....#....t#.....#
|
||||
#.#.#.#.#.#.#.#.###.#.#.#####.#.#######.#.###.#.#.###.###.###.#.#####.###.#####N#
|
||||
#.#...#.#...#.#.#.....#...#...#.#...#...#...#.#.#...#.#...#...#...#...#.#...#.#.#
|
||||
#.#####.#####.#.#########.#.###.#.#.#.#.###.#.#.###.###.###.#######.###.###.#.#.#
|
||||
#.#...#.#.......#...#.....#...#...#.#.#.#.#.#...#.#.....#...#.....#.#...#...#.#.#
|
||||
#.#.###.#########.#.#.###.###.#####.#.#.#.#.#####.#######.###.###.#.#.###.###.#.#
|
||||
#.#...#.#...#.....#.#...#...#.#...#.#.#.#.#.#.....#.....#...#.#.#...#...#.#...#.#
|
||||
#.###.#.#.#.#.#####.#.#.#####.#.###.#.###.#.#.###.###.#.###.#.#.#####.#.#J#E###.#
|
||||
#.....#.#.#...#...#.#.#.....#.#.....#...#.#.#.#.......#.#...#.#...#...#...#.....#
|
||||
#######.#.#####.###.#######.#.#########.#.#.#.#########.#.###.#.#.#.#########.###
|
||||
#.......#.#.....#.I.#.....#.............#...#...#.....#.#...#.#.#.#.........#...#
|
||||
#.#######.###.###.#.#####.#.###########.#.###.#.###.###.###.#####.#########.###.#
|
||||
#.......#...#.#...#.....#.#.#.......#...#.#...#.#...#.....#.........#.....#.#...#
|
||||
#.#####.###.#.#.#######.#.###.#####.#.###.#####.#.###.#######.#####.#.###.#.###.#
|
||||
#.#...#...#.#.#.......#.#.....#.#...#...#.#...#.#...#u#.....#...#...#.#.#.#...#.#
|
||||
#.###.#.###.#.#######.#.#######.#.#####.#.#.#.#.#.#.#.#.#.#.###.#####.#.#.###.#.#
|
||||
#...#.#...#.....#.....#.#.....#...#...#.#...#.#.#.#...#.#.#...#.#.....#.#.#...#.#
|
||||
###.#.###.#####.#.#####.#.#.#.#.###.#.#.#####.#.#.#####.#.#.###.#.#####.#.#.###.#
|
||||
#...#...#.......#.#.....#.#.#.#.....#.#.#.....#.#.#.....#.#.#...#.....#.#.#.#..k#
|
||||
#.###.###########.#.#######.#.#######.#.#.#####.###.#####.###.#.#####.#.#.#.#.###
|
||||
#...#...........#.#.....#...#.......#.#.#...#.........#...#...#.#.....#.#...#.#.#
|
||||
###.#.###.###.###.#####.#.#.#######.#.#.###.#.#########.#.#.###.#.#####.#####.#.#
|
||||
#.#.#...#...#.#...#...#.#.#.#.....#.#.#.#.#.#...#.......#.#.#...#...#.....#...#.#
|
||||
#.#.###.###.#.#.###.#.#.#.###.###.###.###.#.#####.#######.#.#.#####.#.#.#.#.###.#
|
||||
#.#.#.....#.#.#.....#g#...#...#.#...#...#.#.......#...#...#.#...#.#.#.#.#.#.....#
|
||||
#.#.#######.#.#######.###.#.###.###.###.#.#########.###.###.###.#.#.#.#.#######.#
|
||||
#...#.....#.#.#.....#.#...#.......#.#...#.....#.......#.#.#...#...#.#.#.......#.#
|
||||
#.###.###.#.#.#.###.#.###########.#.#.###.###.#.#####.#.#.###.#####.#.#######.#.#
|
||||
#.....#.....#...#...#.A...........#.........#.......#.R.....#.......#.......#...#
|
||||
#######################################.@.#######################################
|
||||
#.....#.........#...........#......r#...........#.#...#.............#.......#...#
|
||||
###.###.#.#######.#.#######.#.#####.###.#.#.###.#.#.#.#.#######.###.#.#####.###.#
|
||||
#...#...#.........#...#...#.#.....#.....#.#...#...#.#...#...#...#.#.#.....#.....#
|
||||
#.###.###############.#.###.#.###.#####.#.###.#####.#######.#.###.#.#####.#######
|
||||
#.....#.......#.#.....#...#.#.#...#.....#.#.#.#.....#.......#.#...#.....#.......#
|
||||
#.#######.###.#.#.#######.#.###.#.#######.#.#.#.#########.###.#.#######G#.#####.#
|
||||
#.....#...#.#...#.#.......#...#.#.#.....#...#.#.#.....#..a#...#.#.....#.#i....#.#
|
||||
#####.#.###.###.#.###.#.#####.#.###.###.#####.#.###.#.#.#.#.###.#.###.#.#######.#
|
||||
#...#.#.#.....#.#...#.#.#.....#.....#...#...#.......#...#.#.#.....#.#.........#.#
|
||||
#.#.#.#.#.#####.###.#.###.###########.###.#.#.#############.#.#####.#########.#.#
|
||||
#.#.#.#.#.......#...#.....#.....#...#...#.#.#.#.............#.......#...#.....O.#
|
||||
#.#.#.#.#########.#######.#.###.#.#.###.#.#.###.###########.#########.#.#######.#
|
||||
#.#.#e#.........#.#.....#...#...#.#.....#.#.#...#...........#.......#.#.....#...#
|
||||
###.#.#########.#.#.###.#####P###.#######.#.#.#########.#####.#####.#.#####.#.###
|
||||
#...#.......#...#...#.#.#...#...#...#...#.#...#.......#.#w....#f..#...#...#.#...#
|
||||
#.#.#######.#.#######.#.#.#####.#.#.#.#.#.#.###.#####.###.###.#.#.#####.#.#.#####
|
||||
#.#.#...#...#.........#.#...#...#.#...#.#.#.#.......#.#...#...#.#...#...#.#.#...#
|
||||
#.#.#.###.#######.###.#.#.#.#.###.#####.#.###.#######.#.#######.###.#.###.#.#.#.#
|
||||
#.#...#...#.....#...#.#.#.#...#..o..#...#...#...#...#.#...#...F.#...#...#.#...#.#
|
||||
#.#####.###.###.###.###.#####.#####.#.#.#.#.#.###.#.#.###.#.#####L###.#.#.#####.#
|
||||
#.......#...#.#.#...#.#.....#.....#.#.#.#.#...#...#.#.#...#...#...#...#.#.....#.#
|
||||
#K#######.#.#.#.#.###.#####.#####X###.#.#######.###.#.#.#######.#####.#.#######.#
|
||||
#....j..#.#.#.....#...#.....#...#...#.#.#.......#...#.#.....#...#.S.#.#.........#
|
||||
#######.###.#####.#.###.#####.#.###.#.###.#######.###.#####.#.###.#.#.###########
|
||||
#.....#...#.....#.#...#.......#...#.#...#.....#.#.#.......#.#l....#.#.#...#.....#
|
||||
#T#.#####.#####.#####.#.#########.#.###.#.###.#.#.#####.#.#.#######.#.#.###.###.#
|
||||
#.#.....#.#.....#.....#.#.......#.#.#...#c#.#.#.....#...#.#...Z.#...#.#.....#...#
|
||||
#.###.###.#.#.###.#####.#.#####.#.#.#.#.#.#.#.#####.#.#######.###.###.#.#####.#.#
|
||||
#...#...#...#.#...#...#...#...#.#.#.#.#.#...#.....#...#.....#.#s..#...#.#.#...#.#
|
||||
###.###.#.#####.###.###.###.#.###.#.#.###.#######.###.#.#.###.#.###.###Q#.#.#####
|
||||
#.#.#.#.#.#...#...#...#.#...#.....#.#...#.#.....#.#...#.#.#...#.V.#.#...#.#.....#
|
||||
#.#.#.#.#.#.#.###.#.#.#.#.#########.###.#.#.###.#.#####.#.#.#####.#.#.###.#####.#
|
||||
#...#.#...#.#...#.#.#.#.#...#...#...#...#.#...#y..#...#.#.#.......#.#.#.......#.#
|
||||
#.###.#####.###.#.###.#.###.#.###.###.#.#####.#####.#.#.#.#########.#.#.#.#####.#
|
||||
#.#.....#...#.#...#...#.#...#.#.D.#.U.#.#.....#...#.#.#.#.......#...#..b#.#.....#
|
||||
#.#####.#.###.#####.###.#.###.#.###.###.#.#####.#.#.#.#.#######.#.#######.#.###.#
|
||||
#.H...#.#...#...........#.#...#.#.....#.#m......#...#...#.......#.#...#...#.#...#
|
||||
#####.#.###.#############.#.#.#.#####.#.#.###############.#######.#.#.#####.#.###
|
||||
#..q......#...............#.#.........#.#...............#...........#.......#..h#
|
||||
#################################################################################
|
||||
1
input/day19.txt
Normal file
1
input/day19.txt
Normal file
@@ -0,0 +1 @@
|
||||
109,424,203,1,21101,0,11,0,1105,1,282,21101,18,0,0,1105,1,259,2101,0,1,221,203,1,21101,31,0,0,1105,1,282,21102,38,1,0,1106,0,259,20101,0,23,2,21201,1,0,3,21101,1,0,1,21101,0,57,0,1105,1,303,2101,0,1,222,21001,221,0,3,21001,221,0,2,21101,259,0,1,21101,0,80,0,1106,0,225,21102,117,1,2,21102,91,1,0,1105,1,303,2101,0,1,223,20102,1,222,4,21102,1,259,3,21101,0,225,2,21102,1,225,1,21101,0,118,0,1105,1,225,21001,222,0,3,21102,1,77,2,21102,133,1,0,1105,1,303,21202,1,-1,1,22001,223,1,1,21102,1,148,0,1105,1,259,2102,1,1,223,21002,221,1,4,20101,0,222,3,21102,20,1,2,1001,132,-2,224,1002,224,2,224,1001,224,3,224,1002,132,-1,132,1,224,132,224,21001,224,1,1,21102,195,1,0,106,0,109,20207,1,223,2,20102,1,23,1,21101,0,-1,3,21101,0,214,0,1106,0,303,22101,1,1,1,204,1,99,0,0,0,0,109,5,1202,-4,1,249,21201,-3,0,1,21201,-2,0,2,22101,0,-1,3,21102,250,1,0,1106,0,225,22101,0,1,-4,109,-5,2105,1,0,109,3,22107,0,-2,-1,21202,-1,2,-1,21201,-1,-1,-1,22202,-1,-2,-2,109,-3,2106,0,0,109,3,21207,-2,0,-1,1206,-1,294,104,0,99,21202,-2,1,-2,109,-3,2105,1,0,109,5,22207,-3,-4,-1,1206,-1,346,22201,-4,-3,-4,21202,-3,-1,-1,22201,-4,-1,2,21202,2,-1,-1,22201,-4,-1,1,21202,-2,1,3,21102,1,343,0,1105,1,303,1106,0,415,22207,-2,-3,-1,1206,-1,387,22201,-3,-2,-3,21202,-2,-1,-1,22201,-3,-1,3,21202,3,-1,-1,22201,-3,-1,2,21202,-4,1,1,21102,384,1,0,1106,0,303,1105,1,415,21202,-4,-1,-4,22201,-4,-3,-4,22202,-3,-2,-2,22202,-2,-4,-4,22202,-3,-2,-3,21202,-4,-1,-2,22201,-3,-2,1,22101,0,1,-4,109,-5,2105,1,0
|
||||
109
input/day20.txt
Normal file
109
input/day20.txt
Normal file
@@ -0,0 +1,109 @@
|
||||
V W A S Q A K
|
||||
D V A H R Y N
|
||||
#################################.#########.###.#.###.#########.#####.#################################
|
||||
#...........#.#...#...#.#...#...........#.....#.....#.........#.....#...............#.......#.........#
|
||||
#.###.#.###.#.###.#.###.###.###.#.#.#####.###.#####.#######.#######.#######.#########.#.#####.#.#####.#
|
||||
#.#...#.#.#...#...#...#.#.......#.#...#.....#.#.....#.......#.....#.#.#...#.#...#.#.#.#.#.#.#.#...#...#
|
||||
#########.#.#####.#.###.###.#.#####.###.#.#######.###.#.#####.###.#.#.#.#.#.#.###.#.###.#.#.###.#####.#
|
||||
#...#...#...#.#.#.....#.....#.....#...#.#.....#.....#.#...#.#...#.#.#...#...#.#...............#.#.#.#.#
|
||||
#.#.###.###.#.#.#.#####.###.#.#.#######.#######.#####.#####.#.#.#.#.#.#######.#.#######.###.#.#.#.#.###
|
||||
#.#.......................#.#.#...#.....#...#.....#.......#...#.#...#.............#.#.....#.#.#.....#.#
|
||||
#.###.#####.#####.#####.#####.#########.#.###.###.###.#.#######.###########.###.###.###.#.#####.###.#.#
|
||||
#.#...#.....#.#...#.....#.#...#...#.......#...#...#.#.#...#.#...#...#.....#.#.#.......#.#.#.......#...#
|
||||
#.###########.###########.###.#.#######.#.###.###.#.###.###.#.###.#.#.###.#.#.#####.###.#.#.###.#######
|
||||
#.#.#...#.#.#...#.#.............#.#...#.#...#.#.#.....#.#.#.......#.#.#.......#.#...#...#.#.#...#.....#
|
||||
###.#.###.#.#.###.#.###.###.#.#.#.#.###.#######.#.#.###.#.#.#.#.###.#.###.#.###.###.#.###.#####.#####.#
|
||||
#...............#.#.#...#...#.#.....#...#...#...#.#.#.....#.#.#.#.#.#.#.#.#.......#.#.#.#.#.#...#.....#
|
||||
#.#######.###.###.#########.#.#.#####.###.#####.###.#.###########.#.#.#.#.#.#.###.#####.###.###.###.###
|
||||
#.#.#.#.#...#...#.#.#.......#.#.....#.......#...#.#.#.#.....#...#.#.#...#.#.#...#.#...#.....#.#.......#
|
||||
###.#.#.#####.#.#.#.#####.#########.#####.#####.#.#.#.###.#.###.#.#.#.#####.#.#######.###.###.#.#.#####
|
||||
#.#.....#.#.#.#.....#.#.....#.......#...#...#.....#.#...#.#.#.....#.#...#...#.#.........#.#...#.#.#.#.#
|
||||
#.#.#####.#.###.#####.#######.#######.#.###.#.#.#.#.###.#.#.#.###.#.#.###########.#.#####.###.#.###.#.#
|
||||
#.....#.#.#.......#...#.#...#.......#.#...#.#.#.#.#.#.#...#.#...#...#...#...#.#...#.#.#.#.#.#.#...#.#.#
|
||||
###.###.#.#####.#####.#.#.#.#.#######.###.#.#.#.###.#.#####.###.#.###.###.###.#.###.#.#.#.#.#.#.###.#.#
|
||||
#.....#...#.#...#...#.#.#.#.......#.....#...#.#.....#...#...#...#.#.#.#.#.#.......#...#...............#
|
||||
###.#.###.#.###.#.###.#.#######.#.###.#.#####.#######.#.#.#.#.###.#.#.#.#.###.###############.#.###.###
|
||||
#...#.#.............#.#.#.......#...#.#.....#.....#...#...#.#...#.#.........#...#.....#.#.#.#.#...#.#.#
|
||||
###.#######.#.###.###.#.#####.#########.#####.#######.#######.#########.#######.###.###.#.#.###.#####.#
|
||||
#.....#...#.#...#.#.....# E O X A X L #.#...#...#.#.....#...#.#
|
||||
#.#.###.#####.###.#####.# N C E Y B O #.###.###.#.#.#####.###.#
|
||||
#.#.....#.#.#.#...#.....# #.#.#.#.#.#.#...#...#...#
|
||||
#.#.###.#.#.###.#.#.###.# #.#.#.#.#.#.#.#####.###.#
|
||||
#.#.#.#...#.#...#...#...# #...............#.#.#.#.#
|
||||
#####.#.#.#.###.#####.### #.#.#.#.#.#.###.#.#.#.#.#
|
||||
#.#.....#.....#...#...#.# #.#.#.#.#.#.#...#.....#..UW
|
||||
#.###.###.#.#.###.#.###.# #.###.#####.#.###.#.#.#.#
|
||||
DK......#.#.#.#.....#......VG EJ....#.#.....#.#...#.#...#
|
||||
#####.#.###.###.###.##### #############.#.#.#####.#
|
||||
#.....#...#.#...#...#....SY #...#...#...#...#.#.#...#
|
||||
#########.#####.#####.### #.###.#####.#####.#.#####
|
||||
LO......#.....#.#.#...#...# #.........#.....#.#.....#
|
||||
#.###.#####.#.###.#####.# #.#.###.###.###.###.###.#
|
||||
#.#.....................# #.#.#.......#.#...#.#.#..XJ
|
||||
#.#########.###.######### #.#####.#.###.###.#.#.###
|
||||
#.#.#.....#...#.#.......# VD....#...#.#.......#.....#
|
||||
#.#.###.#.#########.###.# #.#.###.#####.#####.###.#
|
||||
#.#.#...#.........#...#..WV #.#.#...#.#...........#.#
|
||||
###.###.#####.###.###.### #####.###.###############
|
||||
XE........#...#.#.........# HX....#...#...#...#.....#.#
|
||||
###########.############# #.###.#####.#.###.###.#.#
|
||||
#...#.#...#.........#...# #...#.#.#.#...#.....#.#..XB
|
||||
#.#.#.#.#.#.###.###.###.# #.#####.#.###.###.#.#.#.#
|
||||
#.#.....#...#.#.#.......# #.#.#.....#.#...#.#.#.#.#
|
||||
#.#####.#####.#########.# #.#.#####.#.#.#.###.#.#.#
|
||||
#.#.....#.......#.#.....# #.............#.....#...#
|
||||
#.#########.###.#.#.##### ###.#.#.###.#.#######.###
|
||||
HX..#.#.#...#...#.#........OW XY..#.#.#.#...#.#.....#.#.#
|
||||
###.#.###.#.############# #.#######.#.###.###.###.#
|
||||
#.#.....#.#.#.#.#.#...#.# #...#.....#.#...#...#...#
|
||||
#.#.#####.#.#.#.#.#.#.#.# ###.###########.#.###.#.#
|
||||
#...#.......#.....#.#....QR #.#.#.#.#.......#.#...#..AG
|
||||
#.#.###.#.#######.#.##### #.#.#.#.#####.###.#.###.#
|
||||
WB..#.#...#...#.....#...#.# #...............#...#...#
|
||||
###.#.#.#######.#.###.#.# #.###.###.#.#######.#####
|
||||
#.#...#.........#.....#.# #.#...#...#.#.#...#.#...#
|
||||
#.#####################.# #########.###.###.###.#.#
|
||||
#.......................# #...#...#.#.#...#.....#..DF
|
||||
#.###.#.#.#####.#######.# ###.#.#.###.###.#.###.#.#
|
||||
EN..#...#.#...#...#.#...#.# ZH......#.............#.#.#
|
||||
#######.#.#.#.###.#.#.#.# ###.###.#######.#.###.###
|
||||
#...#.#.#.#.#.#.....#...# DF..#.#.....#.....#.#...#.#
|
||||
###.#.###.###.###.#.##### #.#####.###############.#
|
||||
#.......#...#.#...#......KN #.#...#.#...#.....#.#...#
|
||||
###.#.#########.######### #.###.###.#######.#.#.#.#
|
||||
#...#.#.#.#...#.#.......# #.....................#..GL
|
||||
#.#.###.#.###.#####.#.### #########################
|
||||
#.#...#.......#...#.#....AG WW..#.................#...#
|
||||
#.#.#.#.#########.#.#.### #.#.###.###.#.#####.#.#.#
|
||||
ZH..#.#.#.#.#...#.....#.#.# #.....#...#.#...#.....#..RP
|
||||
#####.#.#.#.###.#.#.#.#.# ###.###.#####.#.###.###.#
|
||||
#...............#.#.#...# #...#.#...#...#.#.....#.#
|
||||
###.###.###.#.#.#.###.### X S U R W D G ###.#.#.#.###.###.###.###
|
||||
#...#.#...#.#.#.#.#...#.# J H W P B K L #.#...#.#.#.#.#.#.#.....#
|
||||
#####.#.###.#.###.#####.#######.#######.#####.###.#####.###########.#.#########.#.#.###.#.#.#.#####.#.#
|
||||
#.#.....#.#.#...#...#.#.....#.#.....#...#.........#.........#.......#.........#...#...#.#.#.......#.#.#
|
||||
#.###.#.#.#.#########.#.#####.#.#######.#####.###.#.#.#.#####.#####.#.###.#######.#####.#.###.###.#.#.#
|
||||
#.#...#.#.......#...............#.#...#.....#.#.#.#.#.#.#...#.#...#.#.#...#...#.#.....#...#.....#.#.#.#
|
||||
#.###.###.#########.#.#.#####.###.#.###.#.###.#.#####.#####.#.#.#.#######.###.#.###.#####.###.#########
|
||||
#.......#.#.#.....#.#.#.#.............#.#.#.........#...#.....#.#.....#.........#...#.#...#...........#
|
||||
#.###.###.#.#.#########.#####.#####.#####.###.#######.###.#.#.#.###.###.###.###.#####.#####.#.#.#####.#
|
||||
#.#.....#.....#.....#...#.#.#.....#.#.......#.#.#...#...#.#.#...#...#.....#.#...........#.#.#.#.....#.#
|
||||
#######.###.###.#######.#.#.#.#.#######.###.#.#.#.###.###########.#######.###########.#.#.#####.#####.#
|
||||
#.......#...........#.#.#.....#.#.#...#.#...#.....#.......#.#...#.#...#.........#...#.#.....#.......#.#
|
||||
#.#.#####.#.#.#.#.#.#.###.###.###.#.###.#.#.#.#######.#####.###.#.#.#.#.#########.###########.###.#####
|
||||
#.#.#.#...#.#.#.#.#.#.#.#.#.#.........#.#.#.#.#.#.#.....#...#.......#.#...#.................#.#.......#
|
||||
###.#.###.###.###.#.#.#.###.#.#.###########.#.#.#.###.###.###.###.#######.#.#####.#.#.###.#######.#.###
|
||||
#.......#...#...#.#.......#...#.#.......#...#.....#.#.....#.#.#.....#...........#.#.#...#.....#...#.#.#
|
||||
###.#####.#####.#.#.#.#####.#.#####.###.###.###.###.#.#####.#######.#.###.###.###.#######.###.###.###.#
|
||||
#.....#...#.....#.#.#.#...#.#.....#.#...#.#.#.....#.....#.....#.....#.#...#...#.......#...#.....#.....#
|
||||
###.#####.###.###########.#####.#######.#.#.#.#.#####.#######.#.#####.#####.#######.###.#.#####.###.###
|
||||
#...#.#.....#.#.#.......#.......#...#.#.....#.#.#...#.....#.#.......#...#.#.#.#.#.#...#.#.#.#.#...#...#
|
||||
#####.#########.###.###.#####.#####.#.###.###.#####.#.#####.#######.#.###.###.#.#.#.#######.#.#########
|
||||
#.#.......#.#.#.....#.#.............#.....#.#.....#.#...#.....#.....#.#...#.#.#.#.#...#...#...........#
|
||||
#.###.#####.#.#.#####.#####.#.#.###.#.#####.#.#.#.#.#.###.#.#####.###.#.#.#.#.#.#.#####.#####.#####.###
|
||||
#...............#.#.#.......#.#...#.#.......#.#.#...#.#...#.#.#.#...#...#.................#.......#...#
|
||||
#.#.#.#.#.#####.#.#.#.#.#.#.#.#####.#.#.###.#.#####.#.#.###.#.#.###.#.###.#.#.###.#.#.#.#####.#########
|
||||
#.#.#.#.#.#.....#.....#.#.#.#.#.....#.#.#...#.#.....#...#...#.......#.#...#.#.#...#.#.#...............#
|
||||
###############################.###.#####.#####.#.#######.###.#########.###############################
|
||||
X Z V O O S W E
|
||||
Y Z G C W Y W J
|
||||
19
input/day20_example1.txt
Normal file
19
input/day20_example1.txt
Normal file
@@ -0,0 +1,19 @@
|
||||
A
|
||||
A
|
||||
#######.#########
|
||||
#######.........#
|
||||
#######.#######.#
|
||||
#######.#######.#
|
||||
#######.#######.#
|
||||
##### B ###.#
|
||||
BC...## C ###.#
|
||||
##.## ###.#
|
||||
##...DE F ###.#
|
||||
##### G ###.#
|
||||
#########.#####.#
|
||||
DE..#######...###.#
|
||||
#.#########.###.#
|
||||
FG..#########.....#
|
||||
###########.#####
|
||||
Z
|
||||
Z
|
||||
37
input/day20_example2.txt
Normal file
37
input/day20_example2.txt
Normal file
@@ -0,0 +1,37 @@
|
||||
Z L X W C
|
||||
Z P Q B K
|
||||
###########.#.#.#.#######.###############
|
||||
#...#.......#.#.......#.#.......#.#.#...#
|
||||
###.#.#.#.#.#.#.#.###.#.#.#######.#.#.###
|
||||
#.#...#.#.#...#.#.#...#...#...#.#.......#
|
||||
#.###.#######.###.###.#.###.###.#.#######
|
||||
#...#.......#.#...#...#.............#...#
|
||||
#.#########.#######.#.#######.#######.###
|
||||
#...#.# F R I Z #.#.#.#
|
||||
#.###.# D E C H #.#.#.#
|
||||
#.#...# #...#.#
|
||||
#.###.# #.###.#
|
||||
#.#....OA WB..#.#..ZH
|
||||
#.###.# #.#.#.#
|
||||
CJ......# #.....#
|
||||
####### #######
|
||||
#.#....CK #......IC
|
||||
#.###.# #.###.#
|
||||
#.....# #...#.#
|
||||
###.### #.#.#.#
|
||||
XF....#.# RF..#.#.#
|
||||
#####.# #######
|
||||
#......CJ NM..#...#
|
||||
###.#.# #.###.#
|
||||
RE....#.# #......RF
|
||||
###.### X X L #.#.#.#
|
||||
#.....# F Q P #.#.#.#
|
||||
###.###########.###.#######.#########.###
|
||||
#.....#...#.....#.......#...#.....#.#...#
|
||||
#####.#.###.#######.#######.###.###.#.#.#
|
||||
#.......#.......#.#.#.#.#...#...#...#.#.#
|
||||
#####.###.#####.#.#.#.#.###.###.#.###.###
|
||||
#.......#.....#.#...#...............#...#
|
||||
#############.#.#.###.###################
|
||||
A O F N
|
||||
A A D M
|
||||
1
input/day21.txt
Normal file
1
input/day21.txt
Normal file
File diff suppressed because one or more lines are too long
100
input/day22.txt
Normal file
100
input/day22.txt
Normal file
@@ -0,0 +1,100 @@
|
||||
deal with increment 3
|
||||
deal into new stack
|
||||
cut -2846
|
||||
deal with increment 33
|
||||
cut -8467
|
||||
deal into new stack
|
||||
deal with increment 46
|
||||
cut 6752
|
||||
deal with increment 63
|
||||
deal into new stack
|
||||
deal with increment 70
|
||||
deal into new stack
|
||||
deal with increment 14
|
||||
cut -1804
|
||||
deal with increment 68
|
||||
cut -4936
|
||||
deal with increment 15
|
||||
cut -3217
|
||||
deal with increment 49
|
||||
cut -1694
|
||||
deal with increment 58
|
||||
cut -6918
|
||||
deal with increment 13
|
||||
cut -4254
|
||||
deal with increment 4
|
||||
deal into new stack
|
||||
cut 5490
|
||||
deal into new stack
|
||||
deal with increment 35
|
||||
deal into new stack
|
||||
deal with increment 7
|
||||
cut 854
|
||||
deal with increment 46
|
||||
cut -8619
|
||||
deal with increment 32
|
||||
deal into new stack
|
||||
cut -6319
|
||||
deal with increment 31
|
||||
cut 1379
|
||||
deal with increment 66
|
||||
cut -7328
|
||||
deal with increment 55
|
||||
cut -6326
|
||||
deal with increment 10
|
||||
deal into new stack
|
||||
cut 4590
|
||||
deal with increment 18
|
||||
cut -9588
|
||||
deal with increment 5
|
||||
cut 3047
|
||||
deal with increment 24
|
||||
cut -1485
|
||||
deal into new stack
|
||||
deal with increment 53
|
||||
cut 5993
|
||||
deal with increment 54
|
||||
cut -5935
|
||||
deal with increment 49
|
||||
cut -3349
|
||||
deal into new stack
|
||||
deal with increment 28
|
||||
cut -4978
|
||||
deal into new stack
|
||||
deal with increment 30
|
||||
cut -1657
|
||||
deal with increment 50
|
||||
cut 3732
|
||||
deal with increment 30
|
||||
cut 6838
|
||||
deal with increment 30
|
||||
deal into new stack
|
||||
cut -3087
|
||||
deal with increment 42
|
||||
deal into new stack
|
||||
deal with increment 68
|
||||
cut 3376
|
||||
deal with increment 51
|
||||
cut -3124
|
||||
deal with increment 57
|
||||
deal into new stack
|
||||
cut -158
|
||||
deal into new stack
|
||||
cut -3350
|
||||
deal with increment 33
|
||||
deal into new stack
|
||||
cut 3387
|
||||
deal with increment 54
|
||||
cut 1517
|
||||
deal with increment 20
|
||||
cut -3981
|
||||
deal with increment 64
|
||||
cut 6264
|
||||
deal with increment 3
|
||||
deal into new stack
|
||||
deal with increment 5
|
||||
cut 232
|
||||
deal with increment 29
|
||||
deal into new stack
|
||||
cut -5147
|
||||
deal with increment 51
|
||||
1
input/day23.txt
Normal file
1
input/day23.txt
Normal file
File diff suppressed because one or more lines are too long
5
input/day24.txt
Normal file
5
input/day24.txt
Normal file
@@ -0,0 +1,5 @@
|
||||
..#.#
|
||||
#####
|
||||
.#...
|
||||
...#.
|
||||
##...
|
||||
1
input/day25.txt
Normal file
1
input/day25.txt
Normal file
File diff suppressed because one or more lines are too long
@@ -1 +0,0 @@
|
||||
3,225,1,225,6,6,1100,1,238,225,104,0,1102,68,5,225,1101,71,12,225,1,117,166,224,1001,224,-100,224,4,224,102,8,223,223,101,2,224,224,1,223,224,223,1001,66,36,224,101,-87,224,224,4,224,102,8,223,223,101,2,224,224,1,223,224,223,1101,26,51,225,1102,11,61,224,1001,224,-671,224,4,224,1002,223,8,223,1001,224,5,224,1,223,224,223,1101,59,77,224,101,-136,224,224,4,224,1002,223,8,223,1001,224,1,224,1,223,224,223,1101,11,36,225,1102,31,16,225,102,24,217,224,1001,224,-1656,224,4,224,102,8,223,223,1001,224,1,224,1,224,223,223,101,60,169,224,1001,224,-147,224,4,224,102,8,223,223,101,2,224,224,1,223,224,223,1102,38,69,225,1101,87,42,225,2,17,14,224,101,-355,224,224,4,224,102,8,223,223,1001,224,2,224,1,224,223,223,1002,113,89,224,101,-979,224,224,4,224,1002,223,8,223,1001,224,7,224,1,224,223,223,1102,69,59,225,4,223,99,0,0,0,677,0,0,0,0,0,0,0,0,0,0,0,1105,0,99999,1105,227,247,1105,1,99999,1005,227,99999,1005,0,256,1105,1,99999,1106,227,99999,1106,0,265,1105,1,99999,1006,0,99999,1006,227,274,1105,1,99999,1105,1,280,1105,1,99999,1,225,225,225,1101,294,0,0,105,1,0,1105,1,99999,1106,0,300,1105,1,99999,1,225,225,225,1101,314,0,0,106,0,0,1105,1,99999,7,677,677,224,1002,223,2,223,1006,224,329,1001,223,1,223,1007,226,226,224,1002,223,2,223,1006,224,344,1001,223,1,223,1108,226,677,224,102,2,223,223,1005,224,359,1001,223,1,223,1107,226,677,224,1002,223,2,223,1006,224,374,101,1,223,223,1107,677,226,224,1002,223,2,223,1006,224,389,101,1,223,223,7,226,677,224,1002,223,2,223,1005,224,404,101,1,223,223,1008,677,226,224,102,2,223,223,1005,224,419,101,1,223,223,1008,226,226,224,102,2,223,223,1006,224,434,101,1,223,223,107,226,226,224,1002,223,2,223,1005,224,449,1001,223,1,223,108,226,677,224,102,2,223,223,1005,224,464,101,1,223,223,1108,677,226,224,102,2,223,223,1005,224,479,101,1,223,223,1007,226,677,224,102,2,223,223,1006,224,494,101,1,223,223,107,677,677,224,102,2,223,223,1005,224,509,101,1,223,223,108,677,677,224,102,2,223,223,1006,224,524,1001,223,1,223,8,226,677,224,102,2,223,223,1005,224,539,101,1,223,223,107,677,226,224,102,2,223,223,1005,224,554,1001,223,1,223,8,226,226,224,102,2,223,223,1006,224,569,1001,223,1,223,7,677,226,224,1002,223,2,223,1005,224,584,1001,223,1,223,1108,226,226,224,102,2,223,223,1005,224,599,1001,223,1,223,1107,677,677,224,1002,223,2,223,1006,224,614,1001,223,1,223,1007,677,677,224,1002,223,2,223,1006,224,629,1001,223,1,223,108,226,226,224,102,2,223,223,1005,224,644,1001,223,1,223,8,677,226,224,1002,223,2,223,1005,224,659,1001,223,1,223,1008,677,677,224,1002,223,2,223,1006,224,674,1001,223,1,223,4,223,99,226
|
||||
@@ -1,5 +1,7 @@
|
||||
extern crate core;
|
||||
|
||||
mod tasks;
|
||||
|
||||
fn main() {
|
||||
tasks::day05::run();
|
||||
tasks::day22::run();
|
||||
}
|
||||
|
||||
@@ -1,19 +1,35 @@
|
||||
use std::collections::HashMap;
|
||||
use std::path::Path;
|
||||
|
||||
pub type RAM = HashMap<usize, i128>;
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn run() {
|
||||
let input = std::fs::read_to_string("input/day05.txt").unwrap();
|
||||
let ram: Vec<i32> = input
|
||||
let ram: RAM = input
|
||||
.split(",")
|
||||
.map(|s| s.parse::<i32>().unwrap())
|
||||
.enumerate()
|
||||
.map(|(i, s)| (i, s.parse::<i128>().unwrap()))
|
||||
.collect();
|
||||
task1(ram.clone());
|
||||
task2(ram.clone());
|
||||
}
|
||||
|
||||
struct IntCodeComputer {
|
||||
input_storage: Vec<i32>,
|
||||
output_storage: Vec<i32>,
|
||||
pub fn load_ram<P: AsRef<Path>>(path: P) -> RAM {
|
||||
let input = std::fs::read_to_string(path).unwrap();
|
||||
input
|
||||
.split(",")
|
||||
.enumerate()
|
||||
.map(|(i, s)| (i, s.parse::<i128>().unwrap()))
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub struct IntCodeComputer {
|
||||
input_storage: Vec<i128>,
|
||||
output_storage: Vec<i128>,
|
||||
pc: usize,
|
||||
ram: Vec<i32>,
|
||||
ram: RAM,
|
||||
relative_base_offset: i128,
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Debug)]
|
||||
@@ -26,35 +42,44 @@ enum OpCode {
|
||||
JumpIfFalse,
|
||||
LessThan,
|
||||
Equals,
|
||||
AdjustRelBase,
|
||||
Terminate,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum OpParam {
|
||||
Immediate(i32),
|
||||
Immediate(i128),
|
||||
Memory(usize),
|
||||
Relative(i128),
|
||||
}
|
||||
|
||||
impl OpParam {
|
||||
fn from(val: i32, type_number: i32) -> Self {
|
||||
fn from(val: i128, type_number: i128) -> Self {
|
||||
match type_number {
|
||||
0 => OpParam::Memory(val as usize),
|
||||
1 => OpParam::Immediate(val),
|
||||
2 => OpParam::Relative(val),
|
||||
_ => unreachable!("unexpected parameter"),
|
||||
}
|
||||
}
|
||||
|
||||
fn retrieve(&self, memory: &Vec<i32>) -> i32 {
|
||||
fn retrieve(&self, memory: &RAM, relative_base_offset: i128) -> i128 {
|
||||
match self {
|
||||
OpParam::Immediate(v) => *v,
|
||||
OpParam::Memory(i) => memory[*i],
|
||||
OpParam::Memory(i) => memory.get_default(*i),
|
||||
OpParam::Relative(i) => memory.get_default((relative_base_offset + *i) as usize),
|
||||
}
|
||||
}
|
||||
|
||||
fn store(&self, memory: &mut Vec<i32>, value: i32) {
|
||||
fn store(&self, memory: &mut RAM, value: i128, relative_base_offset: i128) {
|
||||
match self {
|
||||
OpParam::Immediate(_) => panic!("cannot save to immediate position"),
|
||||
OpParam::Memory(i) => memory[*i] = value,
|
||||
OpParam::Memory(i) => {
|
||||
memory.insert(*i, value);
|
||||
}
|
||||
OpParam::Relative(i) => {
|
||||
memory.insert((relative_base_offset + *i) as usize, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -66,9 +91,9 @@ struct Op {
|
||||
}
|
||||
|
||||
impl Op {
|
||||
fn from(pc: usize, memory: &Vec<i32>) -> Self {
|
||||
fn from(pc: usize, memory: &RAM) -> Self {
|
||||
//opcode: 123xx -> 1, 2, 3: parameter type for parameters 1-3, xx = actual op code
|
||||
let mut opcode = memory[pc];
|
||||
let mut opcode = memory.get_default(pc);
|
||||
let p_type1 = opcode / 10_000;
|
||||
opcode %= 10_000;
|
||||
let p_type2 = opcode / 1000;
|
||||
@@ -79,57 +104,61 @@ impl Op {
|
||||
1 => Op {
|
||||
opcode: OpCode::Add,
|
||||
params: vec![
|
||||
OpParam::from(memory[pc + 1], p_type3),
|
||||
OpParam::from(memory[pc + 2], p_type2),
|
||||
OpParam::from(memory[pc + 3], p_type1),
|
||||
OpParam::from(memory.get_default(pc + 1), p_type3),
|
||||
OpParam::from(memory.get_default(pc + 2), p_type2),
|
||||
OpParam::from(memory.get_default(pc + 3), p_type1),
|
||||
],
|
||||
},
|
||||
2 => Op {
|
||||
opcode: OpCode::Multiply,
|
||||
params: vec![
|
||||
OpParam::from(memory[pc + 1], p_type3),
|
||||
OpParam::from(memory[pc + 2], p_type2),
|
||||
OpParam::from(memory[pc + 3], p_type1),
|
||||
OpParam::from(memory.get_default(pc + 1), p_type3),
|
||||
OpParam::from(memory.get_default(pc + 2), p_type2),
|
||||
OpParam::from(memory.get_default(pc + 3), p_type1),
|
||||
],
|
||||
},
|
||||
3 => Op {
|
||||
opcode: OpCode::Input,
|
||||
params: vec![OpParam::from(memory[pc + 1], p_type3)],
|
||||
params: vec![OpParam::from(memory.get_default(pc + 1), p_type3)],
|
||||
},
|
||||
4 => Op {
|
||||
opcode: OpCode::Output,
|
||||
params: vec![OpParam::from(memory[pc + 1], p_type3)],
|
||||
params: vec![OpParam::from(memory.get_default(pc + 1), p_type3)],
|
||||
},
|
||||
5 => Op {
|
||||
opcode: OpCode::JumpIfTrue,
|
||||
params: vec![
|
||||
OpParam::from(memory[pc + 1], p_type3),
|
||||
OpParam::from(memory[pc + 2], p_type2),
|
||||
OpParam::from(memory.get_default(pc + 1), p_type3),
|
||||
OpParam::from(memory.get_default(pc + 2), p_type2),
|
||||
],
|
||||
},
|
||||
6 => Op {
|
||||
opcode: OpCode::JumpIfFalse,
|
||||
params: vec![
|
||||
OpParam::from(memory[pc + 1], p_type3),
|
||||
OpParam::from(memory[pc + 2], p_type2),
|
||||
OpParam::from(memory.get_default(pc + 1), p_type3),
|
||||
OpParam::from(memory.get_default(pc + 2), p_type2),
|
||||
],
|
||||
},
|
||||
7 => Op {
|
||||
opcode: OpCode::LessThan,
|
||||
params: vec![
|
||||
OpParam::from(memory[pc + 1], p_type3),
|
||||
OpParam::from(memory[pc + 2], p_type2),
|
||||
OpParam::from(memory[pc + 3], p_type1),
|
||||
OpParam::from(memory.get_default(pc + 1), p_type3),
|
||||
OpParam::from(memory.get_default(pc + 2), p_type2),
|
||||
OpParam::from(memory.get_default(pc + 3), p_type1),
|
||||
],
|
||||
},
|
||||
8 => Op {
|
||||
opcode: OpCode::Equals,
|
||||
params: vec![
|
||||
OpParam::from(memory[pc + 1], p_type3),
|
||||
OpParam::from(memory[pc + 2], p_type2),
|
||||
OpParam::from(memory[pc + 3], p_type1),
|
||||
OpParam::from(memory.get_default(pc + 1), p_type3),
|
||||
OpParam::from(memory.get_default(pc + 2), p_type2),
|
||||
OpParam::from(memory.get_default(pc + 3), p_type1),
|
||||
],
|
||||
},
|
||||
9 => Op {
|
||||
opcode: OpCode::AdjustRelBase,
|
||||
params: vec![OpParam::from(memory.get_default(pc + 1), p_type3)],
|
||||
},
|
||||
99 => Op {
|
||||
opcode: OpCode::Terminate,
|
||||
params: vec![],
|
||||
@@ -140,93 +169,163 @@ impl Op {
|
||||
}
|
||||
|
||||
impl IntCodeComputer {
|
||||
fn new(input: Vec<i32>, memory: Vec<i32>) -> Self {
|
||||
pub fn new(input: Vec<i128>, memory: RAM) -> Self {
|
||||
IntCodeComputer {
|
||||
input_storage: input,
|
||||
output_storage: Vec::new(),
|
||||
pc: 0,
|
||||
ram: memory,
|
||||
relative_base_offset: 0,
|
||||
}
|
||||
}
|
||||
|
||||
fn run_until_end(&mut self) {
|
||||
pub fn run_single(&mut self, input: i128) -> i128 {
|
||||
self.set_input(&[input]);
|
||||
self.clear_output();
|
||||
self.run_until_input_empty();
|
||||
*self.get_output().first().unwrap()
|
||||
}
|
||||
|
||||
pub fn run_until_end(&mut self) {
|
||||
if !self.run_until_input_empty() {
|
||||
panic!("There wasn't enough input given to run until the program halted");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* True means the program terminated, false means it is just waiting for more input
|
||||
*/
|
||||
pub fn run_until_input_empty(&mut self) -> bool {
|
||||
let mut op = Op::from(self.pc, &self.ram);
|
||||
let mut inputs = self.input_storage.iter();
|
||||
while op.opcode != OpCode::Terminate {
|
||||
match op.opcode {
|
||||
OpCode::Add => {
|
||||
let r = op.params[0].retrieve(&self.ram) + op.params[1].retrieve(&self.ram);
|
||||
op.params[2].store(&mut self.ram, r);
|
||||
let r = op.params[0].retrieve(&self.ram, self.relative_base_offset)
|
||||
+ op.params[1].retrieve(&self.ram, self.relative_base_offset);
|
||||
op.params[2].store(&mut self.ram, r, self.relative_base_offset);
|
||||
self.pc += 4;
|
||||
}
|
||||
OpCode::Multiply => {
|
||||
let r = op.params[0].retrieve(&self.ram) * op.params[1].retrieve(&self.ram);
|
||||
op.params[2].store(&mut self.ram, r);
|
||||
let r = op.params[0].retrieve(&self.ram, self.relative_base_offset)
|
||||
* op.params[1].retrieve(&self.ram, self.relative_base_offset);
|
||||
op.params[2].store(&mut self.ram, r, self.relative_base_offset);
|
||||
self.pc += 4;
|
||||
}
|
||||
OpCode::Input => {
|
||||
let v = inputs.next().expect("Not enough inputs given");
|
||||
op.params[0].store(&mut self.ram, *v);
|
||||
self.pc += 2;
|
||||
if let Some(v) = inputs.next() {
|
||||
op.params[0].store(&mut self.ram, *v, self.relative_base_offset);
|
||||
self.pc += 2;
|
||||
} else {
|
||||
self.input_storage.clear();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
OpCode::Output => {
|
||||
self.output_storage.push(op.params[0].retrieve(&self.ram));
|
||||
self.output_storage
|
||||
.push(op.params[0].retrieve(&self.ram, self.relative_base_offset));
|
||||
self.pc += 2;
|
||||
}
|
||||
OpCode::JumpIfTrue => {
|
||||
if op.params[0].retrieve(&self.ram) > 0 {
|
||||
self.pc = op.params[1].retrieve(&self.ram) as usize;
|
||||
if op.params[0].retrieve(&self.ram, self.relative_base_offset) > 0 {
|
||||
self.pc =
|
||||
op.params[1].retrieve(&self.ram, self.relative_base_offset) as usize;
|
||||
} else {
|
||||
self.pc += 3;
|
||||
}
|
||||
}
|
||||
OpCode::JumpIfFalse => {
|
||||
if op.params[0].retrieve(&self.ram) == 0 {
|
||||
self.pc = op.params[1].retrieve(&self.ram) as usize;
|
||||
if op.params[0].retrieve(&self.ram, self.relative_base_offset) == 0 {
|
||||
self.pc =
|
||||
op.params[1].retrieve(&self.ram, self.relative_base_offset) as usize;
|
||||
} else {
|
||||
self.pc += 3;
|
||||
}
|
||||
}
|
||||
OpCode::LessThan => {
|
||||
let r = if op.params[0].retrieve(&self.ram) < op.params[1].retrieve(&self.ram) {
|
||||
1
|
||||
} else {
|
||||
0
|
||||
};
|
||||
op.params[2].store(&mut self.ram, r);
|
||||
self.pc += 4;
|
||||
}
|
||||
OpCode::Equals => {
|
||||
let r = if op.params[0].retrieve(&self.ram) == op.params[1].retrieve(&self.ram)
|
||||
let r = if op.params[0].retrieve(&self.ram, self.relative_base_offset)
|
||||
< op.params[1].retrieve(&self.ram, self.relative_base_offset)
|
||||
{
|
||||
1
|
||||
} else {
|
||||
0
|
||||
};
|
||||
op.params[2].store(&mut self.ram, r);
|
||||
op.params[2].store(&mut self.ram, r, self.relative_base_offset);
|
||||
self.pc += 4;
|
||||
}
|
||||
OpCode::Equals => {
|
||||
let r = if op.params[0].retrieve(&self.ram, self.relative_base_offset)
|
||||
== op.params[1].retrieve(&self.ram, self.relative_base_offset)
|
||||
{
|
||||
1
|
||||
} else {
|
||||
0
|
||||
};
|
||||
op.params[2].store(&mut self.ram, r, self.relative_base_offset);
|
||||
self.pc += 4;
|
||||
}
|
||||
OpCode::AdjustRelBase => {
|
||||
self.relative_base_offset +=
|
||||
op.params[0].retrieve(&self.ram, self.relative_base_offset);
|
||||
self.pc += 2;
|
||||
}
|
||||
OpCode::Terminate => {}
|
||||
}
|
||||
op = Op::from(self.pc, &self.ram);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
fn get_output(&self) -> &[i32] {
|
||||
pub fn set_input(&mut self, input: &[i128]) {
|
||||
self.input_storage.clear();
|
||||
for x in input {
|
||||
self.input_storage.push(*x);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_input(&mut self, input: &[i128]) {
|
||||
for x in input {
|
||||
self.input_storage.push(*x);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_input(&self) -> &[i128] {
|
||||
self.input_storage.as_slice()
|
||||
}
|
||||
|
||||
pub fn clear_output(&mut self) {
|
||||
self.output_storage.clear();
|
||||
}
|
||||
|
||||
pub fn clear_n_output(&mut self, n: usize) {
|
||||
self.output_storage = Vec::from(self.output_storage.split_at(n).1);
|
||||
}
|
||||
|
||||
pub fn get_output(&self) -> &[i128] {
|
||||
self.output_storage.as_slice()
|
||||
}
|
||||
}
|
||||
|
||||
fn task1(ram: Vec<i32>) {
|
||||
fn task1(ram: RAM) {
|
||||
let mut computer = IntCodeComputer::new(vec![1], ram);
|
||||
computer.run_until_end();
|
||||
println!("{:?}", computer.get_output());
|
||||
println!("Task 1: {}", computer.get_output().last().unwrap());
|
||||
}
|
||||
|
||||
fn task2(ram: Vec<i32>) {
|
||||
fn task2(ram: RAM) {
|
||||
let mut computer = IntCodeComputer::new(vec![5], ram);
|
||||
computer.run_until_end();
|
||||
println!("{:?}", computer.get_output());
|
||||
println!("Task 2: {}", computer.get_output().last().unwrap());
|
||||
}
|
||||
|
||||
trait Easy {
|
||||
fn get_default(&self, index: usize) -> i128;
|
||||
}
|
||||
|
||||
impl Easy for RAM {
|
||||
fn get_default(&self, index: usize) -> i128 {
|
||||
**self.get(&index).get_or_insert(&0)
|
||||
}
|
||||
}
|
||||
|
||||
69
src/tasks/day07.rs
Normal file
69
src/tasks/day07.rs
Normal file
@@ -0,0 +1,69 @@
|
||||
use crate::tasks::day05::IntCodeComputer;
|
||||
use itertools::Itertools;
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn run() {
|
||||
let prog_code: Vec<_> = std::fs::read_to_string("input/day07.txt")
|
||||
.unwrap()
|
||||
.split(",")
|
||||
.map(|s| s.parse::<i128>().unwrap())
|
||||
.collect();
|
||||
task1(prog_code.clone());
|
||||
task2(prog_code.clone());
|
||||
}
|
||||
|
||||
fn task1(input: Vec<i128>) {
|
||||
let phases = vec![0, 1, 2, 3, 4];
|
||||
let result = phases
|
||||
.iter()
|
||||
.permutations(phases.len())
|
||||
.map(|perm| {
|
||||
perm.iter().fold(0, |signal, phase| {
|
||||
let mut computer = IntCodeComputer::new(
|
||||
vec![**phase, signal],
|
||||
input.clone().into_iter().enumerate().collect(),
|
||||
);
|
||||
computer.run_until_end();
|
||||
*computer.get_output().last().unwrap()
|
||||
})
|
||||
})
|
||||
.max();
|
||||
println!("Task 1: best signal is {}", result.unwrap());
|
||||
}
|
||||
|
||||
fn task2(input: Vec<i128>) {
|
||||
let phases = vec![5, 6, 7, 8, 9];
|
||||
let result = phases
|
||||
.iter()
|
||||
.permutations(phases.len())
|
||||
.map(|perm| {
|
||||
let mut machines: Vec<IntCodeComputer> = perm
|
||||
.iter()
|
||||
.map(|phase| {
|
||||
let mut comp = IntCodeComputer::new(
|
||||
vec![**phase],
|
||||
input.clone().into_iter().enumerate().collect(),
|
||||
);
|
||||
comp.run_until_input_empty();
|
||||
comp
|
||||
})
|
||||
.collect();
|
||||
let mut m = 0;
|
||||
let mut signal = 0;
|
||||
let mut done = false;
|
||||
while !done {
|
||||
let mach = &mut machines[m];
|
||||
mach.set_input(&vec![signal]);
|
||||
let machine_done = mach.run_until_input_empty();
|
||||
signal = *mach.get_output().last().unwrap();
|
||||
mach.clear_output();
|
||||
if machine_done && m == 4 {
|
||||
done = true;
|
||||
}
|
||||
m = (m + 1) % machines.len();
|
||||
}
|
||||
signal
|
||||
})
|
||||
.max();
|
||||
println!("Task 2: best signal with looping is {}", result.unwrap());
|
||||
}
|
||||
27
src/tasks/day09.rs
Normal file
27
src/tasks/day09.rs
Normal file
@@ -0,0 +1,27 @@
|
||||
use super::day05::{IntCodeComputer, RAM};
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn run() {
|
||||
let input = std::fs::read_to_string("input/day09.txt").unwrap();
|
||||
let ram: RAM = input
|
||||
.split(",")
|
||||
.enumerate()
|
||||
.map(|(i, s)| (i, s.parse::<i128>().unwrap()))
|
||||
.collect();
|
||||
task1(ram.clone());
|
||||
task2(ram.clone());
|
||||
}
|
||||
|
||||
fn task1(ram: RAM) {
|
||||
let mut computer = IntCodeComputer::new(vec![1], ram);
|
||||
computer.run_until_end();
|
||||
println!("{:?}", computer.get_output());
|
||||
println!("Task 1: {}", computer.get_output().last().unwrap());
|
||||
}
|
||||
|
||||
fn task2(ram: RAM) {
|
||||
let mut computer = IntCodeComputer::new(vec![2], ram);
|
||||
computer.run_until_end();
|
||||
println!("{:?}", computer.get_output());
|
||||
println!("Task 2: {}", computer.get_output().last().unwrap());
|
||||
}
|
||||
129
src/tasks/day10.rs
Normal file
129
src/tasks/day10.rs
Normal file
@@ -0,0 +1,129 @@
|
||||
use itertools::Itertools;
|
||||
use std::collections::HashSet;
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn run() {
|
||||
let asteroids: HashSet<(i32, i32)> = std::fs::read_to_string("input/day10.txt")
|
||||
.unwrap()
|
||||
.lines()
|
||||
.enumerate()
|
||||
.map(|(y, line)| {
|
||||
line.chars()
|
||||
.enumerate()
|
||||
.filter(|(_, it)| *it == '#')
|
||||
.map(move |(x, _)| (x as i32, y as i32))
|
||||
})
|
||||
.flatten()
|
||||
.collect();
|
||||
task1(&asteroids);
|
||||
task2(&asteroids);
|
||||
}
|
||||
|
||||
fn task1(asteroids: &HashSet<(i32, i32)>) {
|
||||
let (max, _) = get_best_station(&asteroids);
|
||||
println!(
|
||||
"Task 1: maximum visible asteroids from another asteroid are {}",
|
||||
max
|
||||
);
|
||||
}
|
||||
|
||||
fn task2(asteroids: &HashSet<(i32, i32)>) {
|
||||
let (_, station) = get_best_station(&asteroids);
|
||||
println!("Task 2: The station is at {:?}", station);
|
||||
let mut others = asteroids.clone();
|
||||
others.remove(&station);
|
||||
// map to polar coordinate
|
||||
let mut others: Vec<((i32, i32), (f32, f32))> = others
|
||||
.into_iter()
|
||||
.map(|other| (other, to_polar(station, other)))
|
||||
.collect();
|
||||
use std::cmp::Ordering;
|
||||
others.sort_by(|(_, a), (_, b)| {
|
||||
// sort by angle
|
||||
if a.0 < b.0 {
|
||||
Ordering::Less
|
||||
} else {
|
||||
Ordering::Greater
|
||||
}
|
||||
});
|
||||
let mut v: Vec<(f32, Vec<_>)> = others
|
||||
.iter()
|
||||
.group_by(|(_, (alpha, _))| alpha)
|
||||
.into_iter()
|
||||
.map(|(angle, group)| (*angle, group.collect()))
|
||||
.collect();
|
||||
|
||||
let mut i = 0;
|
||||
let mut shot = Vec::new();
|
||||
while shot.len() < 200 {
|
||||
while v[i].1.is_empty() {
|
||||
i = (i + 1) % v.len();
|
||||
}
|
||||
shot.push(v[i].1.remove(0));
|
||||
i = (i + 1) % v.len();
|
||||
}
|
||||
|
||||
let ((x, y), _) = shot.last().unwrap();
|
||||
println!("Task 2: {}", x * 100 + y);
|
||||
}
|
||||
|
||||
fn d(a: (i32, i32), b: (i32, i32)) -> f32 {
|
||||
((a.0 - b.0) as f32).powi(2) + ((a.1 - b.1) as f32).powi(2).sqrt()
|
||||
}
|
||||
|
||||
/**
|
||||
* generate polar coordinate relative to POV.
|
||||
* rotate angles such that "up" is 0.
|
||||
*/
|
||||
fn to_polar(pov: (i32, i32), other: (i32, i32)) -> (f32, f32) {
|
||||
let mut alpha =
|
||||
((other.1 - pov.1) as f32).atan2((other.0 - pov.0) as f32) + std::f32::consts::FRAC_PI_2;
|
||||
if alpha < 0.0 {
|
||||
alpha += 2.0 * std::f32::consts::PI;
|
||||
}
|
||||
(alpha, d(pov, other))
|
||||
}
|
||||
|
||||
fn blocks_view(pov: (i32, i32), target: (i32, i32), occluder: (i32, i32)) -> bool {
|
||||
if occluder == target {
|
||||
return false;
|
||||
}
|
||||
// using polar coordinates
|
||||
let (ao, d_o) = to_polar(pov, occluder);
|
||||
let (at, d_t) = to_polar(pov, target);
|
||||
(ao - at).abs() <= std::f32::EPSILON && d_t > d_o
|
||||
}
|
||||
|
||||
fn get_best_station(asteroids: &HashSet<(i32, i32)>) -> (usize, (i32, i32)) {
|
||||
asteroids
|
||||
.iter()
|
||||
.map(|asteroid| {
|
||||
// map to number of other asteroids it sees
|
||||
let mut others = asteroids.clone();
|
||||
others.remove(&asteroid);
|
||||
// count those asteroids that are not blocked by another
|
||||
let count = others
|
||||
.iter()
|
||||
.filter(|target| {
|
||||
let blocker = others
|
||||
.iter()
|
||||
.find(|occluder| blocks_view(*asteroid, **target, **occluder));
|
||||
!blocker.is_some()
|
||||
})
|
||||
.count();
|
||||
(count, *asteroid)
|
||||
})
|
||||
.max_by_key(|(count, _)| *count)
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
mod test {
|
||||
#[test]
|
||||
fn block_test() {
|
||||
assert_eq!(true, super::blocks_view((3, 4), (1, 0), (2, 2)));
|
||||
assert_eq!(false, super::blocks_view((3, 4), (2, 2), (1, 0)));
|
||||
assert_eq!(false, super::blocks_view((3, 4), (1, 0), (1, 2)));
|
||||
assert_eq!(true, super::blocks_view((4, 4), (4, 0), (4, 3)));
|
||||
assert_eq!(false, super::blocks_view((3, 2), (1, 0), (4, 3)));
|
||||
}
|
||||
}
|
||||
106
src/tasks/day11.rs
Normal file
106
src/tasks/day11.rs
Normal file
@@ -0,0 +1,106 @@
|
||||
use super::day05::{IntCodeComputer, RAM};
|
||||
use std::collections::{HashMap, HashSet};
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn run() {
|
||||
let input = std::fs::read_to_string("input/day11.txt").unwrap();
|
||||
let ram: RAM = input
|
||||
.split(",")
|
||||
.enumerate()
|
||||
.map(|(i, s)| (i, s.parse::<i128>().unwrap()))
|
||||
.collect();
|
||||
task1(ram.clone());
|
||||
task2(ram.clone());
|
||||
}
|
||||
|
||||
fn task1(ram: RAM) {
|
||||
let directions: HashMap<_, _> =
|
||||
vec![('^', (0, -1)), ('v', (0, 1)), ('<', (-1, 0)), ('>', (1, 0))]
|
||||
.into_iter()
|
||||
.collect();
|
||||
let turns: HashMap<_, _> = vec![
|
||||
(('^', 0), '<'),
|
||||
(('^', 1), '>'),
|
||||
(('v', 0), '>'),
|
||||
(('v', 1), '<'),
|
||||
(('<', 0), 'v'),
|
||||
(('<', 1), '^'),
|
||||
(('>', 0), '^'),
|
||||
(('>', 1), 'v'),
|
||||
]
|
||||
.into_iter()
|
||||
.collect();
|
||||
|
||||
let mut colors: HashMap<(i32, i32), i128> = HashMap::new();
|
||||
let mut painted_positions: HashSet<(i32, i32)> = HashSet::new();
|
||||
let get = |colors: &HashMap<_, _>, (x, y)| **colors.get(&(x, y)).get_or_insert(&0);
|
||||
let turn = |(c, d)| turns.get(&(c, d)).unwrap();
|
||||
let mov = |(x0, y0), (x1, y1)| (x0 + x1, y0 + y1);
|
||||
let mut done = false;
|
||||
let mut computer = IntCodeComputer::new(vec![], ram);
|
||||
let mut pos = (0, 0);
|
||||
let mut dir = '^';
|
||||
while !done {
|
||||
computer.set_input(&[get(&colors, pos)]);
|
||||
computer.clear_output();
|
||||
done = computer.run_until_input_empty();
|
||||
let color = computer.get_output()[0];
|
||||
let turn_indicator = computer.get_output()[1];
|
||||
colors.insert(pos, color);
|
||||
painted_positions.insert(pos);
|
||||
dir = *turn((dir, turn_indicator));
|
||||
pos = mov(pos, *directions.get(&dir).unwrap());
|
||||
}
|
||||
println!("Task 1: {} positions were painted", painted_positions.len());
|
||||
}
|
||||
|
||||
fn task2(ram: RAM) {
|
||||
let directions: HashMap<_, _> =
|
||||
vec![('^', (0, -1)), ('v', (0, 1)), ('<', (-1, 0)), ('>', (1, 0))]
|
||||
.into_iter()
|
||||
.collect();
|
||||
let turns: HashMap<_, _> = vec![
|
||||
(('^', 0), '<'),
|
||||
(('^', 1), '>'),
|
||||
(('v', 0), '>'),
|
||||
(('v', 1), '<'),
|
||||
(('<', 0), 'v'),
|
||||
(('<', 1), '^'),
|
||||
(('>', 0), '^'),
|
||||
(('>', 1), 'v'),
|
||||
]
|
||||
.into_iter()
|
||||
.collect();
|
||||
|
||||
let mut colors: HashMap<(i32, i32), i128> = HashMap::new();
|
||||
colors.insert((0, 0), 1);
|
||||
let mut painted_positions: HashSet<(i32, i32)> = HashSet::new();
|
||||
let get = |colors: &HashMap<_, _>, (x, y)| **colors.get(&(x, y)).get_or_insert(&0);
|
||||
let turn = |(c, d)| turns.get(&(c, d)).unwrap();
|
||||
let mov = |(x0, y0), (x1, y1)| (x0 + x1, y0 + y1);
|
||||
let mut done = false;
|
||||
let mut computer = IntCodeComputer::new(vec![], ram);
|
||||
let mut pos = (0, 0);
|
||||
let mut dir = '^';
|
||||
while !done {
|
||||
computer.set_input(&[get(&colors, pos)]);
|
||||
computer.clear_output();
|
||||
done = computer.run_until_input_empty();
|
||||
let color = computer.get_output()[0];
|
||||
let turn_indicator = computer.get_output()[1];
|
||||
colors.insert(pos, color);
|
||||
painted_positions.insert(pos);
|
||||
dir = *turn((dir, turn_indicator));
|
||||
pos = mov(pos, *directions.get(&dir).unwrap());
|
||||
}
|
||||
let xmin = painted_positions.iter().min_by_key(|it| it.0).unwrap().0;
|
||||
let xmax = painted_positions.iter().max_by_key(|it| it.0).unwrap().0;
|
||||
let ymin = painted_positions.iter().min_by_key(|it| it.1).unwrap().1;
|
||||
let ymax = painted_positions.iter().max_by_key(|it| it.1).unwrap().1;
|
||||
(ymin..=ymax).into_iter().for_each(|y| {
|
||||
(xmin..=xmax).into_iter().for_each(|x| {
|
||||
print!("{}", if get(&colors, (x, y)) == 1 { '#' } else { ' ' });
|
||||
});
|
||||
println!("")
|
||||
})
|
||||
}
|
||||
140
src/tasks/day12.rs
Normal file
140
src/tasks/day12.rs
Normal file
@@ -0,0 +1,140 @@
|
||||
use num_integer::Integer;
|
||||
use regex::Regex;
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn run() {
|
||||
let regex = Regex::new("<x=(-?\\d+),\\sy=(-?\\d+),\\sz=(-?\\d+)").unwrap();
|
||||
let input: Vec<Point> = std::fs::read_to_string("input/day12.txt")
|
||||
.unwrap()
|
||||
.lines()
|
||||
.map(|line| {
|
||||
let m = regex.captures(&line).unwrap();
|
||||
let x: i32 = m[1].parse().unwrap();
|
||||
let y: i32 = m[2].parse().unwrap();
|
||||
let z: i32 = m[3].parse().unwrap();
|
||||
Point { x, y, z }
|
||||
})
|
||||
.collect();
|
||||
let moons: Vec<_> = input
|
||||
.into_iter()
|
||||
.map(|pos| Moon {
|
||||
pos: pos,
|
||||
vel: Point::new(0, 0, 0),
|
||||
})
|
||||
.collect();
|
||||
task1(moons.clone());
|
||||
task2(moons.clone());
|
||||
}
|
||||
|
||||
fn task1(moons: Vec<Moon>) {
|
||||
let finals = (0..1000).fold(moons, |moons, _run| step(moons));
|
||||
let energy: i32 = finals
|
||||
.iter()
|
||||
.map(|moon| moon.pos.energy() * moon.vel.energy())
|
||||
.sum();
|
||||
println!("Task 1: sum of energy is {}", energy);
|
||||
}
|
||||
|
||||
fn task2(moons: Vec<Moon>) {
|
||||
let xstart: Vec<_> = moons.iter().map(|it| [it.pos.x, it.vel.x]).collect();
|
||||
let ystart: Vec<_> = moons.iter().map(|it| [it.pos.y, it.vel.y]).collect();
|
||||
let zstart: Vec<_> = moons.iter().map(|it| [it.pos.z, it.vel.z]).collect();
|
||||
let result = (1 as usize..)
|
||||
.scan((None, None, None, moons), |(dx, dy, dz, moons), run| {
|
||||
let mut new_moons = step(moons.clone());
|
||||
moons.clear();
|
||||
moons.append(&mut new_moons);
|
||||
|
||||
let xv: Vec<_> = moons.iter().map(|it| [it.pos.x, it.vel.x]).collect();
|
||||
let yv: Vec<_> = moons.iter().map(|it| [it.pos.y, it.vel.y]).collect();
|
||||
let zv: Vec<_> = moons.iter().map(|it| [it.pos.z, it.vel.z]).collect();
|
||||
if *dx == None && xv == xstart {
|
||||
*dx = Some(run);
|
||||
}
|
||||
if *dy == None && yv == ystart {
|
||||
*dy = Some(run);
|
||||
}
|
||||
if *dz == None && zv == zstart {
|
||||
*dz = Some(run);
|
||||
}
|
||||
if dx.is_some() && dy.is_some() && dz.is_some() {
|
||||
Some(Some((dx.unwrap(), dy.unwrap(), dz.unwrap())))
|
||||
} else {
|
||||
Some(None)
|
||||
}
|
||||
})
|
||||
.find(|bla| bla.is_some());
|
||||
if let Some(Some((x, y, z))) = result {
|
||||
println!(
|
||||
"Task 2: {:?} until a visited state is reached again",
|
||||
x.lcm(&y.lcm(&z))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn step(moons: Vec<Moon>) -> Vec<Moon> {
|
||||
let gravities: Vec<Point> = moons
|
||||
.iter()
|
||||
.map(|base| {
|
||||
moons.iter().fold(Point::new(0, 0, 0), |grav, other_moon| {
|
||||
grav.add(base.pos.gravity(other_moon.pos))
|
||||
})
|
||||
})
|
||||
.collect();
|
||||
let moons = moons
|
||||
.into_iter()
|
||||
.zip(gravities.into_iter())
|
||||
.map(|(mut moon, grav)| {
|
||||
moon.vel = moon.vel.add(grav);
|
||||
moon.pos = moon.pos.add(moon.vel);
|
||||
moon
|
||||
})
|
||||
.collect();
|
||||
moons
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash, Ord, PartialOrd)]
|
||||
struct Moon {
|
||||
pos: Point,
|
||||
vel: Point,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Ord, PartialOrd)]
|
||||
struct Point {
|
||||
x: i32,
|
||||
y: i32,
|
||||
z: i32,
|
||||
}
|
||||
|
||||
impl Point {
|
||||
fn new(x: i32, y: i32, z: i32) -> Self {
|
||||
Point { x, y, z }
|
||||
}
|
||||
|
||||
fn add(&self, other: Self) -> Self {
|
||||
Point {
|
||||
x: self.x + other.x,
|
||||
y: self.y + other.y,
|
||||
z: self.z + other.z,
|
||||
}
|
||||
}
|
||||
fn gravity(&self, other: Self) -> Self {
|
||||
fn d(a: i32, b: i32) -> i32 {
|
||||
use std::cmp::Ordering;
|
||||
match a.cmp(&b) {
|
||||
Ordering::Less => 1,
|
||||
Ordering::Equal => 0,
|
||||
Ordering::Greater => -1,
|
||||
}
|
||||
}
|
||||
Point {
|
||||
x: d(self.x, other.x),
|
||||
y: d(self.y, other.y),
|
||||
z: d(self.z, other.z),
|
||||
}
|
||||
}
|
||||
|
||||
fn energy(&self) -> i32 {
|
||||
self.x.abs() + self.y.abs() + self.z.abs()
|
||||
}
|
||||
}
|
||||
239
src/tasks/day13.rs
Normal file
239
src/tasks/day13.rs
Normal file
@@ -0,0 +1,239 @@
|
||||
use super::day05::{IntCodeComputer, RAM};
|
||||
use itertools::Itertools;
|
||||
use std::collections::HashMap;
|
||||
use std::fmt;
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn run() {
|
||||
let program: RAM = std::fs::read_to_string("input/day13.txt")
|
||||
.unwrap()
|
||||
.split(",")
|
||||
.map(|it| it.parse::<i128>().unwrap())
|
||||
.enumerate()
|
||||
.collect();
|
||||
task1(program.clone());
|
||||
task2_ai(program.clone());
|
||||
}
|
||||
|
||||
#[derive(PartialEq)]
|
||||
enum FieldType {
|
||||
Empty,
|
||||
Wall,
|
||||
Block,
|
||||
HorizontalPaddle,
|
||||
Ball,
|
||||
}
|
||||
|
||||
impl fmt::Display for FieldType {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"{}",
|
||||
match self {
|
||||
Self::Empty => " ",
|
||||
Self::Wall => "X",
|
||||
Self::Block => "B",
|
||||
Self::HorizontalPaddle => "_",
|
||||
Self::Ball => "O",
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl FieldType {
|
||||
fn from(input: i128) -> Self {
|
||||
match input {
|
||||
0 => Self::Empty,
|
||||
1 => Self::Wall,
|
||||
2 => Self::Block,
|
||||
3 => Self::HorizontalPaddle,
|
||||
4 => Self::Ball,
|
||||
_ => unreachable!("unexpected field type {}", input),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct Game {
|
||||
pc: IntCodeComputer,
|
||||
field: HashMap<(i128, i128), FieldType>,
|
||||
score: i128,
|
||||
show_output: bool,
|
||||
}
|
||||
|
||||
impl Game {
|
||||
fn new(coins: Option<i128>, mut ram: RAM, show_output: bool) -> Self {
|
||||
if let Some(c) = coins {
|
||||
ram.insert(0, c);
|
||||
}
|
||||
let pc = IntCodeComputer::new(vec![], ram);
|
||||
Game {
|
||||
pc,
|
||||
field: HashMap::new(),
|
||||
score: 0,
|
||||
show_output,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* true means the game is over, false means input is awaited
|
||||
*/
|
||||
fn run(&mut self) -> bool {
|
||||
self.pc.clear_output();
|
||||
let done = self.pc.run_until_input_empty();
|
||||
let output = self.pc.get_output().into_iter().map(|it| *it).collect_vec();
|
||||
let mut score = None;
|
||||
output
|
||||
.iter()
|
||||
.tuples()
|
||||
.scan(&mut self.field, |map, (x, y, t)| {
|
||||
if *x == -1 && *y == 0 {
|
||||
score = Some(*t);
|
||||
} else {
|
||||
map.insert((*x, *y), FieldType::from(*t));
|
||||
}
|
||||
Some(())
|
||||
})
|
||||
.any(|_| false);
|
||||
|
||||
// stupid workaround because I cannot access score from within the clojure,
|
||||
// due to then double-borrowing of mutable reference to self
|
||||
if let Some(score) = score {
|
||||
self.score = score;
|
||||
}
|
||||
if self.show_output {
|
||||
self.print();
|
||||
}
|
||||
done
|
||||
}
|
||||
|
||||
fn set_input(&mut self, input: Input) {
|
||||
self.pc.set_input(&[input.int()]);
|
||||
}
|
||||
|
||||
fn print(&self) {
|
||||
let xmin = *self.field.iter().map(|((x, _), _)| x).min().unwrap();
|
||||
let xmax = *self.field.iter().map(|((x, _), _)| x).max().unwrap();
|
||||
let ymin = *self.field.iter().map(|((_, y), _)| y).min().unwrap();
|
||||
let ymax = *self.field.iter().map(|((_, y), _)| y).max().unwrap();
|
||||
for y in ymin..=ymax {
|
||||
for x in xmin..=xmax {
|
||||
if let Some(f) = self.field.get(&(x, y)) {
|
||||
print!("{}", f);
|
||||
} else {
|
||||
panic!("There is an unspecified tile in the field");
|
||||
}
|
||||
}
|
||||
println!();
|
||||
}
|
||||
println!("Score: {}", self.score);
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(PartialEq)]
|
||||
enum Input {
|
||||
Neutral,
|
||||
Left,
|
||||
Right,
|
||||
}
|
||||
|
||||
impl Input {
|
||||
fn int(&self) -> i128 {
|
||||
match self {
|
||||
Self::Neutral => 0,
|
||||
Self::Left => -1,
|
||||
Self::Right => 1,
|
||||
}
|
||||
}
|
||||
|
||||
fn from(input: char) -> Self {
|
||||
match input {
|
||||
's' => Self::Neutral,
|
||||
'a' => Self::Left,
|
||||
'd' => Self::Right,
|
||||
_ => Self::Neutral,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn task1(program: RAM) {
|
||||
let mut game = Game::new(None, program, true);
|
||||
if game.run() {
|
||||
let block_count = game
|
||||
.field
|
||||
.iter()
|
||||
.filter(|(_, ftype)| **ftype == FieldType::Block)
|
||||
.count();
|
||||
println!("Task 1: There are {} blocks in the field", block_count);
|
||||
} else {
|
||||
unreachable!("In this task the game should end without any input.");
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
fn task2(program: RAM) {
|
||||
use std::io::{self, BufRead};
|
||||
let mut game = Game::new(Some(2), program, true);
|
||||
let stdin = io::stdin();
|
||||
let mut input_iter = stdin.lock().lines();
|
||||
while !game.run() {
|
||||
// read input
|
||||
let next = input_iter.next().unwrap().unwrap().chars().next();
|
||||
if let Some(s) = next {
|
||||
game.set_input(Input::from(s));
|
||||
} else {
|
||||
game.set_input(Input::Neutral);
|
||||
}
|
||||
}
|
||||
println!(
|
||||
"You won against the game! Your final score was {}",
|
||||
game.score
|
||||
);
|
||||
}
|
||||
|
||||
fn task2_ai(program: RAM) {
|
||||
let mut game = Game::new(Some(2), program, false);
|
||||
let mut moves = 0;
|
||||
while !game.run() {
|
||||
// always keep the paddle under the ball
|
||||
let x_ball = game
|
||||
.field
|
||||
.iter()
|
||||
.find_map(|((x, _), t)| {
|
||||
if *t == FieldType::Ball {
|
||||
Some(*x)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.unwrap();
|
||||
let x_paddle = game
|
||||
.field
|
||||
.iter()
|
||||
.find_map(|((x, _), t)| {
|
||||
if *t == FieldType::HorizontalPaddle {
|
||||
Some(*x)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.unwrap();
|
||||
let direction = if x_ball < x_paddle {
|
||||
Input::Left
|
||||
} else if x_ball > x_paddle {
|
||||
Input::Right
|
||||
} else {
|
||||
Input::Neutral
|
||||
};
|
||||
game.set_input(direction);
|
||||
moves += 1;
|
||||
}
|
||||
println!("Played for {} moves", moves);
|
||||
println!(
|
||||
"Game is over! There are {} blocks left. Your final score is {}",
|
||||
game.field
|
||||
.iter()
|
||||
.filter(|(_, t)| **t == FieldType::Block)
|
||||
.count(),
|
||||
game.score
|
||||
);
|
||||
}
|
||||
115
src/tasks/day14.rs
Normal file
115
src/tasks/day14.rs
Normal file
@@ -0,0 +1,115 @@
|
||||
use itertools::Itertools;
|
||||
use std::collections::HashMap;
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn run() {
|
||||
fn parser(s: &str) -> Chemical {
|
||||
let (n, t) = s.split(" ").collect_tuple().unwrap();
|
||||
Chemical(n.parse().unwrap(), t)
|
||||
}
|
||||
let text = std::fs::read_to_string("input/day14.txt").unwrap();
|
||||
// maps from a chemical to the chemicals required to create it
|
||||
let rules: HashMap<_, _> = text
|
||||
.lines()
|
||||
.map(|line| {
|
||||
let (left, right) = line
|
||||
.split("=>")
|
||||
.map(|it| it.trim())
|
||||
.collect_tuple()
|
||||
.unwrap();
|
||||
(
|
||||
parser(right).1,
|
||||
(
|
||||
parser(right).0,
|
||||
left.split(",").map(|it| parser(it.trim())).collect_vec(),
|
||||
),
|
||||
)
|
||||
})
|
||||
.collect();
|
||||
task1(&rules);
|
||||
task2(&rules);
|
||||
}
|
||||
|
||||
fn task1(rules: &HashMap<&str, (usize, Vec<Chemical>)>) {
|
||||
println!("Task 1: {} ORE is needed", calc_ore_for_fuel(1, rules));
|
||||
}
|
||||
|
||||
fn task2(rules: &HashMap<&str, (usize, Vec<Chemical>)>) {
|
||||
const ORE_STORAGE: usize = 1_000_000_000_000;
|
||||
// binary search max fuel
|
||||
let (max_fuel, _) = std::iter::successors(Some((1, ORE_STORAGE)), |(min, max)| {
|
||||
if max - min > 1 {
|
||||
let middle = (max + min) / 2;
|
||||
let ore = calc_ore_for_fuel(middle, rules);
|
||||
if ore > ORE_STORAGE {
|
||||
Some((*min, middle))
|
||||
} else {
|
||||
Some((middle, *max))
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.last()
|
||||
.unwrap();
|
||||
println!("Task 2: the maximum amount of fuel is {}", max_fuel);
|
||||
}
|
||||
|
||||
fn calc_ore_for_fuel(fuel: usize, rules: &HashMap<&str, (usize, Vec<Chemical>)>) -> usize {
|
||||
/*
|
||||
The idea is: the rules create a DAG of requirements.
|
||||
We store for every chemical a list of the chemicals that rely on it.
|
||||
We create a mapping from the chemicals to the amount of the chemicals needed
|
||||
by its already processed ancestors in the rule DAG.
|
||||
Then we process all chemicals C, starting with "FUEL", of which all ancestors are already
|
||||
processed. That means, that our mapping of the amounts stores the correct sum of what is
|
||||
needed of the chemical (we round that up, so it matches the amount given on the right
|
||||
hand rule side). We then calculate, using the rules, how much of other chemicals C' we need
|
||||
to produce the desired amount. We add up the amount of the required children C' in
|
||||
`requirements`. We then remove C from the chem_used_by list of C'.
|
||||
Once a chemical has an empty used_by list it is ready for processing.
|
||||
*/
|
||||
|
||||
// maps for every chemical to the ones using it
|
||||
let mut chem_used_by: HashMap<&str, Vec<&str>> =
|
||||
rules
|
||||
.iter()
|
||||
.fold(HashMap::new(), |mut map, (result, (_, ingredients))| {
|
||||
ingredients.iter().for_each(|Chemical(_, ingredient)| {
|
||||
map.entry(&ingredient).or_insert(vec![]).push(result)
|
||||
});
|
||||
map
|
||||
});
|
||||
chem_used_by.insert("FUEL", vec![]);
|
||||
// the amount of a not processed chemical C, which is needed by the chemicals that rely on C
|
||||
let mut requirements = HashMap::<&str, usize>::new();
|
||||
requirements.insert("FUEL", fuel);
|
||||
while let Some((name, amount)) = requirements
|
||||
.iter()
|
||||
.find(|(name, _)| chem_used_by[*name].is_empty() && **name != "ORE")
|
||||
{
|
||||
// needed to remove immutable borrow of `requirements` from above
|
||||
let name = *name;
|
||||
let amount = *amount;
|
||||
let (reaction_size, req_vec) = &rules
|
||||
.get(&name)
|
||||
.expect(&format!("unknown chemical in rules: {}", name));
|
||||
let demand = if amount % reaction_size == 0 {
|
||||
amount / reaction_size
|
||||
} else {
|
||||
amount / reaction_size + 1
|
||||
};
|
||||
for Chemical(req_amount, req_name) in req_vec {
|
||||
chem_used_by
|
||||
.get_mut(req_name)
|
||||
.unwrap()
|
||||
.retain(|x| *x != name);
|
||||
*requirements.entry(req_name).or_insert(0) += demand * req_amount;
|
||||
}
|
||||
requirements.remove(name);
|
||||
}
|
||||
requirements["ORE"]
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Eq, Hash, Copy, Clone, Debug)]
|
||||
struct Chemical<'a>(usize, &'a str);
|
||||
268
src/tasks/day15.rs
Normal file
268
src/tasks/day15.rs
Normal file
@@ -0,0 +1,268 @@
|
||||
use super::day05::*;
|
||||
use std::collections::HashMap;
|
||||
use std::collections::VecDeque;
|
||||
use Direction::*;
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn run() {
|
||||
let ram = load_ram("input/day15.txt");
|
||||
task1(ram.clone());
|
||||
task2(ram.clone());
|
||||
}
|
||||
|
||||
fn task1(ram: RAM) {
|
||||
let (map, goal) = explore_map(ram);
|
||||
let shortest_path = map.get_shortest_path_to(Pos(0, 0), goal);
|
||||
/*
|
||||
map.print(
|
||||
Map::positions_on_path(Pos(0, 0), &shortest_path)
|
||||
.iter()
|
||||
.map(|p| (*p, 'x'))
|
||||
.collect(),
|
||||
);
|
||||
*/
|
||||
|
||||
println!(
|
||||
"Task 1: shortest path to goal ({:?}) has length {}",
|
||||
goal,
|
||||
shortest_path.len()
|
||||
);
|
||||
}
|
||||
|
||||
fn task2(ram: RAM) {
|
||||
let (map, oxygen) = explore_map(ram);
|
||||
let max_distance = map
|
||||
.positions
|
||||
.iter()
|
||||
.filter(|(_, c)| **c == '.')
|
||||
.map(|(pos, _)| map.get_shortest_path_to(oxygen, *pos).len())
|
||||
.max()
|
||||
.unwrap();
|
||||
println!(
|
||||
"Task 2: time needed to reach most distant room is {} minutes",
|
||||
max_distance
|
||||
);
|
||||
}
|
||||
|
||||
fn explore_map(ram: RAM) -> (Map, Pos) {
|
||||
let mut map = Map {
|
||||
positions: HashMap::new(),
|
||||
};
|
||||
let mut current = Pos(0, 0);
|
||||
map.positions.insert(current, '.');
|
||||
let mut target: Option<Pos> = None;
|
||||
let mut pc = IntCodeComputer::new(vec![], ram);
|
||||
while let Some(non_explored_neighbor) = map.get_unexplored() {
|
||||
// move to next field with unexplored neighbors
|
||||
// *find path
|
||||
// *follow directions
|
||||
let round_starts_from = current;
|
||||
let directions = map.get_shortest_path_to(round_starts_from, non_explored_neighbor);
|
||||
for d in directions {
|
||||
let res = pc.run_single(d.to_robot_cmd());
|
||||
if res == 0 {
|
||||
map.print(HashMap::new());
|
||||
panic!("Ran against a wall stepping {:?} from {:?}.", d, current);
|
||||
}
|
||||
current = current.neighbor(d);
|
||||
}
|
||||
|
||||
// explore all 4 neighbor positions
|
||||
// i.e. for every direction move - if result is 0 mark as wall,
|
||||
// if result is 1 or 2 move back and mark as empty. If result is 2 store
|
||||
// target position
|
||||
let ns = vec![N, S, W, E];
|
||||
for d in ns {
|
||||
let r = pc.run_single(d.to_robot_cmd());
|
||||
match r {
|
||||
0 => {
|
||||
map.positions.insert(current.neighbor(d), '#');
|
||||
}
|
||||
1 => {
|
||||
map.positions.insert(current.neighbor(d), '.');
|
||||
pc.run_single(d.opposite().to_robot_cmd());
|
||||
}
|
||||
2 => {
|
||||
map.positions.insert(current.neighbor(d), '.');
|
||||
pc.run_single(d.opposite().to_robot_cmd());
|
||||
target = Some(current.neighbor(d));
|
||||
}
|
||||
_ => panic!("unknown field type {}", r),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
(map, target.unwrap())
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Eq, Hash, Copy, Clone, Debug)]
|
||||
struct Pos(i32, i32);
|
||||
|
||||
impl Pos {
|
||||
fn add(&self, other: Self) -> Self {
|
||||
Pos(self.0 + other.0, self.1 + other.1)
|
||||
}
|
||||
|
||||
fn direction_to(&self, from: Pos) -> Direction {
|
||||
let m: HashMap<Pos, Direction> = vec![
|
||||
(Pos(0, 1), N),
|
||||
(Pos(0, -1), S),
|
||||
(Pos(1, 0), W),
|
||||
(Pos(-1, 0), E),
|
||||
]
|
||||
.into_iter()
|
||||
.collect();
|
||||
m.get(&Pos(self.0 - from.0, self.1 - from.1))
|
||||
.map(|p| *p)
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
fn neighbor(&self, direction: Direction) -> Pos {
|
||||
match direction {
|
||||
N => self.add(Pos(0, -1)),
|
||||
S => self.add(Pos(0, 1)),
|
||||
W => self.add(Pos(-1, 0)),
|
||||
E => self.add(Pos(1, 0)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Map {
|
||||
positions: HashMap<Pos, char>,
|
||||
}
|
||||
|
||||
impl Map {
|
||||
fn get_unexplored(&self) -> Option<Pos> {
|
||||
let neighbors = vec![Pos(-1, 0), Pos(1, 0), Pos(0, -1), Pos(0, 1)];
|
||||
let r = self
|
||||
.positions
|
||||
.iter()
|
||||
.filter(|(_, c)| **c == '.')
|
||||
.map(|(p, _)| p)
|
||||
.find(|pos| {
|
||||
neighbors
|
||||
.iter()
|
||||
.any(|delta| !self.positions.contains_key(&pos.add(*delta)))
|
||||
});
|
||||
r.map(|p| *p)
|
||||
}
|
||||
|
||||
fn get_shortest_path_to(&self, start: Pos, goal: Pos) -> Vec<Direction> {
|
||||
let neighbors = vec![Pos(-1, 0), Pos(1, 0), Pos(0, -1), Pos(0, 1)];
|
||||
let mut open: VecDeque<Pos> = VecDeque::new();
|
||||
open.push_back(start);
|
||||
let mut predecessors: HashMap<Pos, Option<Pos>> = HashMap::new();
|
||||
predecessors.insert(start, None);
|
||||
while let Some(current) = open.pop_front() {
|
||||
let field = self.positions.get(¤t);
|
||||
if let Some(v) = field {
|
||||
if *v != '.' {
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
neighbors.iter().for_each(|d| {
|
||||
let n = current.add(*d);
|
||||
if !predecessors.contains_key(&n) {
|
||||
predecessors.insert(n, Some(current));
|
||||
open.push_back(n);
|
||||
}
|
||||
});
|
||||
if current == goal {
|
||||
break;
|
||||
}
|
||||
}
|
||||
let mut directions = Vec::new();
|
||||
let mut current = goal;
|
||||
while let Some(Some(pred)) = predecessors.get(¤t) {
|
||||
directions.push(current.direction_to(*pred).opposite());
|
||||
current = *pred;
|
||||
}
|
||||
directions.reverse();
|
||||
directions
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
fn positions_on_path(start: Pos, directions: &Vec<Direction>) -> Vec<Pos> {
|
||||
let mut result = vec![start];
|
||||
let mut current = start;
|
||||
for d in directions {
|
||||
current = current.neighbor(*d);
|
||||
result.push(current);
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
fn print(&self, special: HashMap<Pos, char>) {
|
||||
let xmin = (self
|
||||
.positions
|
||||
.iter()
|
||||
.min_by_key(|(Pos(x, _), _)| x)
|
||||
.unwrap()
|
||||
.0)
|
||||
.0;
|
||||
let xmax = (self
|
||||
.positions
|
||||
.iter()
|
||||
.max_by_key(|(Pos(x, _), _)| x)
|
||||
.unwrap()
|
||||
.0)
|
||||
.0;
|
||||
let ymin = (self
|
||||
.positions
|
||||
.iter()
|
||||
.min_by_key(|(Pos(_, y), _)| y)
|
||||
.unwrap()
|
||||
.0)
|
||||
.1;
|
||||
let ymax = (self
|
||||
.positions
|
||||
.iter()
|
||||
.max_by_key(|(Pos(_, y), _)| y)
|
||||
.unwrap()
|
||||
.0)
|
||||
.1;
|
||||
for y in ymin..=ymax {
|
||||
for x in xmin..=xmax {
|
||||
let c = self.positions.get(&Pos(x, y)).unwrap_or(&' ');
|
||||
let c = if let Some(s) = special.get(&Pos(x, y)) {
|
||||
s
|
||||
} else {
|
||||
c
|
||||
};
|
||||
print!("{}", c);
|
||||
}
|
||||
println!("");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Hash, PartialEq, Copy, Clone, Debug)]
|
||||
enum Direction {
|
||||
N,
|
||||
S,
|
||||
W,
|
||||
E,
|
||||
}
|
||||
|
||||
impl Direction {
|
||||
fn opposite(&self) -> Self {
|
||||
match self {
|
||||
N => S,
|
||||
S => N,
|
||||
W => E,
|
||||
E => W,
|
||||
}
|
||||
}
|
||||
|
||||
fn to_robot_cmd(&self) -> i128 {
|
||||
match self {
|
||||
N => 1,
|
||||
S => 2,
|
||||
W => 3,
|
||||
E => 4,
|
||||
}
|
||||
}
|
||||
}
|
||||
175
src/tasks/day16.rs
Normal file
175
src/tasks/day16.rs
Normal file
@@ -0,0 +1,175 @@
|
||||
use std::collections::HashMap;
|
||||
use std::iter;
|
||||
|
||||
use itertools::Itertools;
|
||||
|
||||
const BASE_PATTERN: [i32; 4] = [0, 1, 0, -1];
|
||||
const INPUT: &str = "59750530221324194853012320069589312027523989854830232144164799228029162830477472078089790749906142587998642764059439173975199276254972017316624772614925079238407309384923979338502430726930592959991878698412537971672558832588540600963437409230550897544434635267172603132396722812334366528344715912756154006039512272491073906389218927420387151599044435060075148142946789007756800733869891008058075303490106699737554949348715600795187032293436328810969288892220127730287766004467730818489269295982526297430971411865028098708555709525646237713045259603175397623654950719275982134690893685598734136409536436003548128411943963263336042840301380655801969822";
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn run() {
|
||||
let input = to_digits(INPUT);
|
||||
task1(input.clone());
|
||||
task2(to_digits("02935109699940807407585447034323"));
|
||||
task2(input.clone());
|
||||
}
|
||||
|
||||
fn task1(input: Vec<V>) -> String {
|
||||
let mut s = S { input, cache: HashMap::new() };
|
||||
s.prep();
|
||||
let result = format!("{:.*}", 8, (0..8).map(|position| {
|
||||
let r = s.get(position, 100);
|
||||
r
|
||||
}).join(""));
|
||||
println!("Task 1: {result}");
|
||||
result
|
||||
}
|
||||
|
||||
fn to_digits(input: &str) -> Vec<i32> {
|
||||
input
|
||||
.chars()
|
||||
.map(|it| it.to_digit(10).unwrap() as i32)
|
||||
.collect_vec()
|
||||
}
|
||||
|
||||
fn task2(input: Vec<i32>) -> String {
|
||||
let big_input = iter::repeat(input.clone().into_iter())
|
||||
.take(10_000)
|
||||
.flatten()
|
||||
.collect_vec();
|
||||
|
||||
let mut s = S { input: big_input, cache: HashMap::new() };
|
||||
let result_position = format!("{}", input.split_at(7).0.iter().join("")).parse::<usize>().unwrap();
|
||||
s.prep_after(result_position);
|
||||
let result = format!("{:.*}", 8, (0..8).map(|position| {
|
||||
let r = s.get(position + result_position, 100);
|
||||
r
|
||||
}).join(""));
|
||||
|
||||
println!("Task 2: {result}");
|
||||
result
|
||||
}
|
||||
|
||||
type V = i32;
|
||||
|
||||
struct S {
|
||||
input: Vec<V>,
|
||||
cache: HashMap<(usize, usize), V>,
|
||||
}
|
||||
|
||||
impl S {
|
||||
fn pattern(&self, position: usize, size: usize) -> Vec<i32> {
|
||||
let pattern = BASE_PATTERN.iter().map(|x| iter::repeat(*x).take(position)).flatten();
|
||||
let iter = iter::repeat(pattern).flatten().skip(1).take(size);
|
||||
iter.collect()
|
||||
}
|
||||
|
||||
fn get(&mut self, index: usize, phase: usize) -> V {
|
||||
if phase == 0 {
|
||||
return self.input[index];
|
||||
}
|
||||
|
||||
if self.cache.contains_key(&(phase, index)) {
|
||||
return self.cache[&(phase, index)];
|
||||
}
|
||||
|
||||
if index == self.input.len() - 1 {
|
||||
let v = self.get(index, phase - 1);
|
||||
self.cache.insert((phase, index), v);
|
||||
return v;
|
||||
}
|
||||
|
||||
if index > (self.input.len() / 2 + 1) {
|
||||
let v = self.get(index + 1, phase) + self.get(index, phase - 1);
|
||||
let v = v.abs() % 10;
|
||||
self.cache.insert((phase, index), v);
|
||||
return v;
|
||||
}
|
||||
|
||||
let pattern = self.pattern(index + 1, self.input.len());
|
||||
let val: i32 = pattern
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(i, p)| if *p == 0 { 0 } else { *p * self.get(i, phase - 1) })
|
||||
.sum();
|
||||
let result = val.abs() % 10;
|
||||
self.cache.insert((phase, index), result);
|
||||
result
|
||||
}
|
||||
|
||||
fn prep(&mut self) {
|
||||
for phase in 1..=100 {
|
||||
for i in 1..self.input.len() / 2 {
|
||||
self.get(self.input.len() - i, phase);
|
||||
}
|
||||
}
|
||||
println!("preparation done")
|
||||
}
|
||||
|
||||
fn prep_after(&mut self, start: usize) {
|
||||
for phase in 1..=100 {
|
||||
for i in (start..self.input.len()).rev() {
|
||||
self.get(i, phase);
|
||||
}
|
||||
}
|
||||
println!("preparation done")
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_part_1_examples() {
|
||||
assert_eq!(
|
||||
task1(to_digits("80871224585914546619083218645595")),
|
||||
"24176176"
|
||||
);
|
||||
assert_eq!(
|
||||
task1(to_digits("19617804207202209144916044189917")),
|
||||
"73745418"
|
||||
);
|
||||
assert_eq!(
|
||||
task1(to_digits("69317163492948606335995924319873")),
|
||||
"52432133"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_part_1_solution() {
|
||||
assert_eq!(task1(to_digits(INPUT)), "84487724");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_part_2_solution() {
|
||||
assert_eq!(task2(to_digits(INPUT)), "84692524");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_trivial() {
|
||||
let mut s = S { input: to_digits("12345678"), cache: HashMap::new() };
|
||||
s.prep();
|
||||
let result = format!("{:.*}", 8, (0..8).map(|position| {
|
||||
let r = s.get(position, 1);
|
||||
r
|
||||
}).join(""));
|
||||
assert_eq!(result, "48226158");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_part_2_examples() {
|
||||
assert_eq!(
|
||||
task2(to_digits("02935109699940807407585447034323")),
|
||||
"78725270"
|
||||
);
|
||||
assert_eq!(
|
||||
task2(to_digits("03036732577212944063491565474664")),
|
||||
"84462026"
|
||||
);
|
||||
assert_eq!(
|
||||
task2(to_digits("03081770884921959731165446850517")),
|
||||
"53553731"
|
||||
);
|
||||
}
|
||||
}
|
||||
78
src/tasks/day17.rs
Normal file
78
src/tasks/day17.rs
Normal file
@@ -0,0 +1,78 @@
|
||||
use super::day05::*;
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn run() {
|
||||
let input: RAM = std::fs::read_to_string("input/day17.txt")
|
||||
.unwrap()
|
||||
.split(",")
|
||||
.enumerate()
|
||||
.map(|(i, it)| (i, it.parse::<i128>().unwrap()))
|
||||
.collect();
|
||||
|
||||
task1(input.clone());
|
||||
task2(input.clone());
|
||||
}
|
||||
|
||||
fn task1(ram: RAM) {
|
||||
let mut pc = IntCodeComputer::new(vec![], ram);
|
||||
pc.run_until_end();
|
||||
let map: Vec<Vec<char>> = pc
|
||||
.get_output()
|
||||
.iter()
|
||||
.map(|it| (*it as u8) as char)
|
||||
.collect::<String>()
|
||||
.lines()
|
||||
.map(|line| line.chars().collect())
|
||||
.collect();
|
||||
let height = map.len();
|
||||
let width = map[0].len();
|
||||
let alignment_sum = (1..height - 1).fold(0, |sum, y| {
|
||||
sum + (1..width - 1).fold(0, |sum, x| {
|
||||
let pos = Pos(x, y);
|
||||
if map[y][x] == '#'
|
||||
&& pos
|
||||
.neighbors()
|
||||
.iter()
|
||||
.all(|Pos(xp, yp)| map[*yp][*xp] == '#')
|
||||
{
|
||||
sum + pos.0 * pos.1
|
||||
} else {
|
||||
sum
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
println!("Task 1: sum of alignment parameters is {}", alignment_sum);
|
||||
}
|
||||
|
||||
fn task2(mut ram: RAM) {
|
||||
// R,8,L,10,R,8,R,12,R,8,L,8,12,R,8,L,10,R,8,L,12,L,10,L,8,R,8,L,10,R,8,R,12,R,8,L,8,L,12,L,12,L,10,L,8,L,12,L,10,L,8,R,8,L,10,R,8,R,12,R,8,L,8,L,12
|
||||
/*
|
||||
R,8,L,10,R,8
|
||||
R,12,R,8,L,8,L,12
|
||||
L,12,L,10,L,8
|
||||
*/
|
||||
let main = "A,B,A,C,A,B,C,C,A,B";
|
||||
let a = "R,8,L,10,R,8";
|
||||
let b = "R,12,R,8,L,8,L,12";
|
||||
let c = "L,12,L,10,L,8";
|
||||
let program = format!("{}\n{}\n{}\n{}\nn\n", main, a, b, c);
|
||||
ram.insert(0, 2);
|
||||
let mut pc = IntCodeComputer::new(program.chars().map(|it| (it as u8) as i128).collect(), ram);
|
||||
pc.run_until_end();
|
||||
let out = pc.get_output();
|
||||
println!("{:?}", out.last().unwrap());
|
||||
}
|
||||
|
||||
struct Pos(usize, usize);
|
||||
|
||||
impl Pos {
|
||||
fn neighbors(&self) -> Vec<Pos> {
|
||||
vec![
|
||||
Pos(self.0 - 1, self.1),
|
||||
Pos(self.0 + 1, self.1),
|
||||
Pos(self.0, self.1 - 1),
|
||||
Pos(self.0, self.1 - 1),
|
||||
]
|
||||
}
|
||||
}
|
||||
299
src/tasks/day18.rs
Normal file
299
src/tasks/day18.rs
Normal file
@@ -0,0 +1,299 @@
|
||||
use itertools::Itertools;
|
||||
use std::cmp::{Ord, Ordering, PartialOrd};
|
||||
use std::collections::BinaryHeap;
|
||||
use std::collections::HashSet;
|
||||
use std::collections::VecDeque;
|
||||
use std::rc::Rc;
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn run() {
|
||||
let input: Map = Map(std::fs::read_to_string("input/day18.txt")
|
||||
.unwrap()
|
||||
.lines()
|
||||
.map(|line| line.chars().collect_vec())
|
||||
.collect_vec());
|
||||
|
||||
let t1 = task(input.clone());
|
||||
println!("Task 1: best bound to get all keys is {}", t1);
|
||||
//let t2 = task(input.clone().split_robot());
|
||||
//println!("Task 2: best bound to get all keys is {}", t2);
|
||||
}
|
||||
|
||||
fn task(map: Map) -> usize {
|
||||
let mut all_keys = map
|
||||
.0
|
||||
.iter()
|
||||
.flatten()
|
||||
.filter(|c| c.is_alphabetic() && c.is_lowercase())
|
||||
.collect_vec();
|
||||
all_keys.sort();
|
||||
let all_keys: String = all_keys.into_iter().collect();
|
||||
let map = Rc::from(map);
|
||||
|
||||
let mut visited: HashSet<StateSummary> = HashSet::new();
|
||||
let mut open: BinaryHeap<State> = BinaryHeap::new();
|
||||
|
||||
open.push(State::new(map.clone()));
|
||||
while let Some(state) = open.pop() {
|
||||
let summary = StateSummary::from(&state);
|
||||
if visited.contains(&summary) {
|
||||
// there could come no better solution
|
||||
continue;
|
||||
}
|
||||
|
||||
if summary.1 == all_keys {
|
||||
return state.steps_taken;
|
||||
}
|
||||
|
||||
state
|
||||
.get_available_options()
|
||||
.into_iter()
|
||||
.for_each(|s| open.push(s));
|
||||
|
||||
visited.insert(summary);
|
||||
}
|
||||
|
||||
panic!("if we reach this point no path can be found");
|
||||
}
|
||||
|
||||
#[derive(Eq, PartialEq, Hash, Debug)]
|
||||
struct StateSummary(Vec<Pos>, String);
|
||||
impl StateSummary {
|
||||
fn from(state: &State) -> Self {
|
||||
let mut s = state.opened.iter().collect_vec();
|
||||
s.sort();
|
||||
Self(
|
||||
state.currents.clone(),
|
||||
s.into_iter()
|
||||
.map(|c| {
|
||||
let mut x = *c;
|
||||
x.make_ascii_lowercase();
|
||||
x
|
||||
})
|
||||
.collect(),
|
||||
)
|
||||
}
|
||||
}
|
||||
#[derive(Eq, PartialEq)]
|
||||
struct StateSummaryDist(Pos, HashSet<char>, usize);
|
||||
|
||||
#[derive(PartialEq, Eq, Clone)]
|
||||
struct Map(Vec<Vec<char>>);
|
||||
|
||||
#[allow(dead_code)]
|
||||
impl Map {
|
||||
fn coordinate_of(&self, symbol: char) -> Vec<Pos> {
|
||||
self.0
|
||||
.iter()
|
||||
.enumerate()
|
||||
.fold(Vec::new(), |vec, (y, line)| {
|
||||
line.iter()
|
||||
.enumerate()
|
||||
.filter(|(_x, c)| **c == symbol)
|
||||
.fold(vec, |mut vec, (x, _c)| {
|
||||
vec.push(Pos(x, y));
|
||||
vec
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* return: (char: found key, usize1: index of moved robot,
|
||||
* usize2: distance that robot moved, Pos: new position of robot[index]),
|
||||
* usize3: number of empty points on path to last_door_opened
|
||||
*/
|
||||
fn reachable_keys(
|
||||
&self,
|
||||
start_points: Vec<Pos>,
|
||||
open_doors: &HashSet<char>,
|
||||
last_door_opened: Option<char>,
|
||||
) -> Vec<(char, usize, usize, Pos, usize)> {
|
||||
let all_keys = 'a'..='z';
|
||||
|
||||
let bfs = |start: Pos, open_doors: &HashSet<char>| {
|
||||
// key, distance, new_pos, number of steps of distance until last_open door is met
|
||||
let mut result: Vec<(char, usize, Pos, usize)> = vec![];
|
||||
let mut open: VecDeque<(Pos, usize, usize)> = VecDeque::new(); //position, distance form start, distance until last door opened is met
|
||||
open.push_back((start, 0, 0));
|
||||
let mut visited: HashSet<Pos> = HashSet::new();
|
||||
while let Some((current, walked, ldod)) = open.pop_front() {
|
||||
if visited.contains(¤t) {
|
||||
continue;
|
||||
}
|
||||
let field = self.0[current.1][current.0];
|
||||
let field_is_key = all_keys.contains(&field);
|
||||
// if can move over current type: push neighbors to open
|
||||
if field == '.' || field == '@' || open_doors.contains(&field) || field_is_key {
|
||||
let mut ldod = 0;
|
||||
if let Some(ldo) = last_door_opened {
|
||||
if ldo == field {
|
||||
ldod = walked;
|
||||
}
|
||||
};
|
||||
current
|
||||
.neighbors()
|
||||
.iter()
|
||||
.for_each(|n| open.push_back((*n, walked + 1, ldod)));
|
||||
}
|
||||
|
||||
// if it is a key: push it to result
|
||||
if field_is_key {
|
||||
result.push((field, walked, current, ldod));
|
||||
}
|
||||
|
||||
// anyways: push to visited
|
||||
visited.insert(current);
|
||||
}
|
||||
|
||||
result
|
||||
};
|
||||
|
||||
start_points
|
||||
.iter()
|
||||
.enumerate()
|
||||
.flat_map(|(robot_i, robot_pos)| {
|
||||
bfs(*robot_pos, open_doors)
|
||||
.into_iter()
|
||||
.map(|(key, dist, final_pos, ldod)| (key, robot_i, dist, final_pos, ldod))
|
||||
.collect_vec()
|
||||
})
|
||||
.collect_vec()
|
||||
}
|
||||
|
||||
fn split_robot(mut self) -> Self {
|
||||
let Pos(x, y) = self.coordinate_of('@')[0];
|
||||
self.0[x][y] = '#';
|
||||
self.0[x - 1][y - 1] = '@';
|
||||
self.0[x - 1][y] = '#';
|
||||
self.0[x - 1][y + 1] = '@';
|
||||
self.0[x + 1][y] = '#';
|
||||
self.0[x + 1][y + 1] = '@';
|
||||
self.0[x][y - 1] = '#';
|
||||
self.0[x + 1][y - 1] = '@';
|
||||
self.0[x][y + 1] = '#';
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
|
||||
struct Pos(usize, usize);
|
||||
|
||||
impl Pos {
|
||||
fn neighbors(&self) -> [Pos; 4] {
|
||||
[
|
||||
Pos(self.0 - 1, self.1),
|
||||
Pos(self.0 + 1, self.1),
|
||||
Pos(self.0, self.1 - 1),
|
||||
Pos(self.0, self.1 + 1),
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Eq, PartialEq)]
|
||||
struct State {
|
||||
currents: Vec<Pos>,
|
||||
underrun: Vec<usize>, // the number of steps a robot is behind the leading robots steps
|
||||
opened: HashSet<char>, // capital letter
|
||||
map: Rc<Map>,
|
||||
steps_taken: usize,
|
||||
last_door_opened: Option<char>,
|
||||
}
|
||||
|
||||
impl State {
|
||||
fn new(map: Rc<Map>) -> Self {
|
||||
let currents = map.coordinate_of('@');
|
||||
let no_robots = currents.len();
|
||||
Self {
|
||||
currents: currents,
|
||||
underrun: std::iter::repeat(0).take(no_robots).collect_vec(),
|
||||
opened: HashSet::new(),
|
||||
map: map,
|
||||
steps_taken: 0,
|
||||
last_door_opened: None,
|
||||
}
|
||||
}
|
||||
|
||||
fn get_available_options(&self) -> Vec<State> {
|
||||
// find all keys that are not yet collected + their distance + position
|
||||
let next_keys = self
|
||||
.map
|
||||
.reachable_keys(self.currents.clone(), &self.opened, self.last_door_opened)
|
||||
.into_iter()
|
||||
.filter(|(key, _, _, _, _)| {
|
||||
let mut c = *key;
|
||||
c.make_ascii_uppercase();
|
||||
!self.opened.contains(&c)
|
||||
})
|
||||
.collect_vec();
|
||||
|
||||
// create new state with one open door added + steps increased + current position updated
|
||||
next_keys
|
||||
.into_iter()
|
||||
.map(|(key, robot_i, distance, current, ldod)| {
|
||||
self.advance(key, robot_i, distance, current, ldod)
|
||||
})
|
||||
.collect_vec()
|
||||
}
|
||||
|
||||
fn advance(
|
||||
&self,
|
||||
key_added: char,
|
||||
robot_index: usize,
|
||||
additional_steps: usize,
|
||||
new_pos: Pos,
|
||||
ldod: usize,
|
||||
) -> Self {
|
||||
let mut open_doors = self.opened.clone();
|
||||
let mut door = key_added;
|
||||
door.make_ascii_uppercase();
|
||||
open_doors.insert(door);
|
||||
let mut positions = self.currents.clone();
|
||||
positions[robot_index] = new_pos;
|
||||
let underrun = self
|
||||
.underrun
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(i, u)| {
|
||||
if i != robot_index {
|
||||
*u + additional_steps
|
||||
} else {
|
||||
0
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
|
||||
let usable_underrun = if self.underrun[robot_index] >= ldod {
|
||||
ldod
|
||||
} else {
|
||||
self.underrun[robot_index]
|
||||
};
|
||||
let steps_diff = additional_steps - usable_underrun;
|
||||
Self {
|
||||
currents: positions,
|
||||
underrun: underrun,
|
||||
opened: open_doors,
|
||||
map: self.map.clone(),
|
||||
steps_taken: self.steps_taken + steps_diff as usize,
|
||||
last_door_opened: Some(key_added),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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.steps_taken.cmp(&self.steps_taken)
|
||||
}
|
||||
}
|
||||
|
||||
// `PartialOrd` needs to be implemented as well.
|
||||
impl PartialOrd for State {
|
||||
fn partial_cmp(&self, other: &State) -> Option<Ordering> {
|
||||
Some(self.cmp(other))
|
||||
}
|
||||
}
|
||||
82
src/tasks/day19.rs
Normal file
82
src/tasks/day19.rs
Normal file
@@ -0,0 +1,82 @@
|
||||
use super::day05::{IntCodeComputer, RAM};
|
||||
use itertools::Itertools;
|
||||
use std::collections::HashMap;
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn run() {
|
||||
let program = super::day05::load_ram("input/day19.txt");
|
||||
part1(&program, 50);
|
||||
part2(&program);
|
||||
}
|
||||
|
||||
fn part1(program: &RAM, max_perimeter: i128) {
|
||||
let result = (0..max_perimeter)
|
||||
.flat_map(|x| {
|
||||
(0..max_perimeter)
|
||||
.map(|y| read_coordinate(program, x, y))
|
||||
.collect_vec()
|
||||
})
|
||||
.filter(|v| *v)
|
||||
.count();
|
||||
|
||||
println!("Part 1: {result}");
|
||||
}
|
||||
|
||||
const SHIP_SIZE: i128 = 100;
|
||||
|
||||
fn part2(program: &RAM) {
|
||||
let mut map: HashMap<(i128, i128), bool> = HashMap::new();
|
||||
(0..SHIP_SIZE).for_each(|x| {
|
||||
(0..SHIP_SIZE).for_each(|y| {
|
||||
map.insert((x, y), read_coordinate(program, x, y));
|
||||
})
|
||||
});
|
||||
for perimeter in 0.. {
|
||||
extend_horizon(program, &mut map, perimeter);
|
||||
if let Some((x, y)) = check_all_squares_starting_at(&map, perimeter) {
|
||||
let result = x * 10_000 + y;
|
||||
println!("Part 2: starts at {x},{y} -> {}", result);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn check_all_squares_starting_at(
|
||||
map: &HashMap<(i128, i128), bool>,
|
||||
perimeter: i128,
|
||||
) -> Option<(i128, i128)> {
|
||||
for i in 0..=perimeter {
|
||||
if let Some(point) = check_fits(map, i, perimeter) {
|
||||
return Some(point);
|
||||
}
|
||||
if let Some(point) = check_fits(map, perimeter, i) {
|
||||
return Some(point);
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
fn check_fits(map: &HashMap<(i128, i128), bool>, x: i128, y: i128) -> Option<(i128, i128)> {
|
||||
let ul = map[&(x, y)];
|
||||
let ur = map[&(x + SHIP_SIZE - 1, y)];
|
||||
let ll = map[&(x, y + SHIP_SIZE - 1)];
|
||||
let lr = map[&(x + SHIP_SIZE, y + SHIP_SIZE - 1)];
|
||||
if ul && ur && ll && lr {
|
||||
return Some((x, y));
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
fn extend_horizon(program: &RAM, map: &mut HashMap<(i128, i128), bool>, starts: i128) {
|
||||
(0..=SHIP_SIZE + starts).for_each(|i| {
|
||||
let j = SHIP_SIZE + starts;
|
||||
map.insert((j, i), read_coordinate(program, j, i));
|
||||
map.insert((i, j), read_coordinate(program, i, j));
|
||||
});
|
||||
}
|
||||
|
||||
fn read_coordinate(program: &RAM, x: i128, y: i128) -> bool {
|
||||
let mut computer = IntCodeComputer::new(vec![x, y], program.clone());
|
||||
computer.run_until_end();
|
||||
*computer.get_output().first().unwrap() == 1
|
||||
}
|
||||
364
src/tasks/day20.rs
Normal file
364
src/tasks/day20.rs
Normal file
@@ -0,0 +1,364 @@
|
||||
use std::collections::{HashMap, HashSet, VecDeque};
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn run() {
|
||||
let input = std::fs::read_to_string("input/day20.txt").unwrap();
|
||||
let maze = Maze::from(&input, PortalField::curried_factory);
|
||||
let part1 = maze.shortest_path();
|
||||
println!("Part 1: {}", part1);
|
||||
|
||||
let maze = Maze::from(&input, DimensionField::curried_factory);
|
||||
let part1 = maze.shortest_path();
|
||||
println!("Part 2: {}", part1);
|
||||
}
|
||||
|
||||
type C = i32;
|
||||
type FieldFactory = Box<dyn Fn(&MapPoint) -> Box<dyn Field>>;
|
||||
|
||||
#[derive(Hash, Eq, PartialEq, Copy, Clone, Debug)]
|
||||
struct MapPoint {
|
||||
x: C,
|
||||
y: C,
|
||||
}
|
||||
|
||||
impl MapPoint {
|
||||
fn of(x: C, y: C) -> Self {
|
||||
MapPoint { x, y }
|
||||
}
|
||||
|
||||
fn neighbors(self) -> Vec<MapPoint> {
|
||||
vec![
|
||||
MapPoint::of(self.x + 1, self.y),
|
||||
MapPoint::of(self.x, self.y + 1),
|
||||
MapPoint::of(self.x - 1, self.y),
|
||||
MapPoint::of(self.x, self.y - 1),
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Hash, Eq, PartialEq, Copy, Clone, Debug)]
|
||||
struct RealPoint {
|
||||
x: C,
|
||||
y: C,
|
||||
level: usize,
|
||||
}
|
||||
|
||||
impl RealPoint {
|
||||
fn map_point(&self) -> MapPoint {
|
||||
MapPoint {
|
||||
x: self.x,
|
||||
y: self.y,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl RealPoint {
|
||||
fn from(map_point: MapPoint, level: usize) -> Self {
|
||||
RealPoint {
|
||||
x: map_point.x,
|
||||
y: map_point.y,
|
||||
level,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
trait Field {
|
||||
fn neighbors(&self, at_level: usize) -> Vec<RealPoint>;
|
||||
fn set_label_partner(&mut self, point: MapPoint);
|
||||
fn set_neighbors(&mut self, neighbors: Vec<MapPoint>);
|
||||
fn curried_factory(width: C, height: C) -> FieldFactory
|
||||
where
|
||||
Self: Sized;
|
||||
}
|
||||
|
||||
struct PortalField {
|
||||
neighbors: Vec<MapPoint>,
|
||||
}
|
||||
|
||||
impl PortalField {
|
||||
fn new() -> Self {
|
||||
PortalField { neighbors: vec![] }
|
||||
}
|
||||
}
|
||||
|
||||
impl Field for PortalField {
|
||||
fn neighbors(&self, _: usize) -> Vec<RealPoint> {
|
||||
self.neighbors
|
||||
.iter()
|
||||
.map(|p| RealPoint::from(*p, 0))
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn set_label_partner(&mut self, point: MapPoint) {
|
||||
self.neighbors.push(point);
|
||||
}
|
||||
|
||||
fn set_neighbors(&mut self, neighbors: Vec<MapPoint>) {
|
||||
self.neighbors = neighbors;
|
||||
}
|
||||
|
||||
fn curried_factory(_: C, _: C) -> FieldFactory {
|
||||
Box::new(|_| Box::new(PortalField::new()))
|
||||
}
|
||||
}
|
||||
|
||||
struct DimensionField {
|
||||
point: MapPoint,
|
||||
neighbors: Vec<MapPoint>,
|
||||
jump: Option<MapPoint>,
|
||||
map_width: C,
|
||||
map_height: C,
|
||||
}
|
||||
|
||||
impl DimensionField {
|
||||
fn is_inward(&self) -> bool {
|
||||
let p = self.point;
|
||||
p.x > 2 && p.x < self.map_width - 3 && p.y > 2 && p.y < self.map_height - 3
|
||||
}
|
||||
}
|
||||
|
||||
impl Field for DimensionField {
|
||||
fn neighbors(&self, at_level: usize) -> Vec<RealPoint> {
|
||||
let mut result: Vec<RealPoint> = self
|
||||
.neighbors
|
||||
.iter()
|
||||
.map(|n| RealPoint::from(*n, at_level))
|
||||
.collect();
|
||||
if let Some(destination) = self.jump {
|
||||
if self.is_inward() {
|
||||
result.push(RealPoint::from(destination, at_level + 1));
|
||||
} else if at_level > 0 {
|
||||
result.push(RealPoint::from(destination, at_level - 1));
|
||||
}
|
||||
}
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
fn set_label_partner(&mut self, point: MapPoint) {
|
||||
self.jump = Some(point);
|
||||
}
|
||||
|
||||
fn set_neighbors(&mut self, neighbors: Vec<MapPoint>) {
|
||||
self.neighbors = neighbors;
|
||||
}
|
||||
|
||||
fn curried_factory(width: C, height: C) -> FieldFactory {
|
||||
Box::new(move |point: &MapPoint| {
|
||||
Box::new(Self {
|
||||
point: *point,
|
||||
neighbors: vec![],
|
||||
jump: None,
|
||||
map_width: width,
|
||||
map_height: height,
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
type FieldMap = HashMap<MapPoint, Box<dyn Field>>;
|
||||
|
||||
struct Maze {
|
||||
map: FieldMap,
|
||||
start: RealPoint,
|
||||
finish: RealPoint,
|
||||
}
|
||||
|
||||
impl Maze {
|
||||
fn from(input: &String, factory: fn(C, C) -> FieldFactory) -> Self {
|
||||
let (moc, width, height) = Self::map_of_chars(input);
|
||||
|
||||
let mut map = Self::create_map_of_free_spots(&moc, factory(width, height));
|
||||
Self::add_physical_neighbors(&mut map);
|
||||
let labels = Self::labels(&moc, width, height);
|
||||
Self::process_labels(&mut map, &labels);
|
||||
let start = labels["AA"][0];
|
||||
let finish = labels["ZZ"][0];
|
||||
|
||||
Maze {
|
||||
map,
|
||||
start: RealPoint::from(start, 0),
|
||||
finish: RealPoint::from(finish, 0),
|
||||
}
|
||||
}
|
||||
|
||||
fn shortest_path(&self) -> usize {
|
||||
bfs(&self.map, self.start, self.finish)
|
||||
}
|
||||
|
||||
fn process_labels(map: &mut FieldMap, labels: &HashMap<String, Vec<MapPoint>>) {
|
||||
for (label, points) in labels {
|
||||
if label == "AA" || label == "ZZ" {
|
||||
continue;
|
||||
}
|
||||
|
||||
map.get_mut(&points[0])
|
||||
.unwrap()
|
||||
.set_label_partner(points[1]);
|
||||
map.get_mut(&points[1])
|
||||
.unwrap()
|
||||
.set_label_partner(points[0]);
|
||||
}
|
||||
}
|
||||
|
||||
fn labels(
|
||||
moc: &HashMap<MapPoint, char>,
|
||||
width: C,
|
||||
height: C,
|
||||
) -> HashMap<String, Vec<MapPoint>> {
|
||||
let horizontal: Vec<(String, MapPoint)> = (0..width - 2)
|
||||
.into_iter()
|
||||
.flat_map(|x| {
|
||||
(0..height).into_iter().flat_map(move |y| {
|
||||
let mut triple = [
|
||||
moc[&MapPoint::of(x, y)],
|
||||
moc[&MapPoint::of(x + 1, y)],
|
||||
moc[&MapPoint::of(x + 2, y)],
|
||||
];
|
||||
let left = Self::label(triple).map(|label| (label, MapPoint::of(x, y)));
|
||||
triple.reverse();
|
||||
let right = Self::label(triple).map(|label| (label, MapPoint::of(x + 2, y)));
|
||||
vec![left, right]
|
||||
})
|
||||
})
|
||||
.flatten()
|
||||
.collect();
|
||||
|
||||
let vertical: Vec<(String, MapPoint)> = (0..width)
|
||||
.into_iter()
|
||||
.flat_map(|x| {
|
||||
(0..height - 2).into_iter().flat_map(move |y| {
|
||||
let mut triple = [
|
||||
moc[&MapPoint::of(x, y)],
|
||||
moc[&MapPoint::of(x, y + 1)],
|
||||
moc[&MapPoint::of(x, y + 2)],
|
||||
];
|
||||
let left = Self::label(triple).map(|label| (label, MapPoint::of(x, y)));
|
||||
triple.reverse();
|
||||
let right = Self::label(triple).map(|label| (label, MapPoint::of(x, y + 2)));
|
||||
vec![left, right]
|
||||
})
|
||||
})
|
||||
.flatten()
|
||||
.collect();
|
||||
|
||||
let mut result = HashMap::new();
|
||||
for (s, p) in horizontal.into_iter().chain(vertical.into_iter()) {
|
||||
if !result.contains_key(&s) {
|
||||
result.insert(s.clone(), vec![]);
|
||||
}
|
||||
result.get_mut(&s).unwrap().push(p);
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
fn label(chars: [char; 3]) -> Option<String> {
|
||||
if chars[0] == '.' && chars[1].is_alphabetic() && chars[2].is_alphabetic() {
|
||||
let label = if chars[1] < chars[2] {
|
||||
format!("{}{}", chars[1], chars[2])
|
||||
} else {
|
||||
format!("{}{}", chars[2], chars[1])
|
||||
};
|
||||
Some(label)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn add_physical_neighbors(map: &mut FieldMap) {
|
||||
let points: HashSet<MapPoint> = map.keys().map(|p| *p).collect();
|
||||
map.iter_mut().for_each(|(p, f)| {
|
||||
let neighbors = p
|
||||
.neighbors()
|
||||
.into_iter()
|
||||
.filter(|neighbor| points.contains(neighbor))
|
||||
.collect();
|
||||
f.set_neighbors(neighbors);
|
||||
})
|
||||
}
|
||||
|
||||
fn create_map_of_free_spots(
|
||||
moc: &HashMap<MapPoint, char>,
|
||||
field_factory: FieldFactory,
|
||||
) -> FieldMap {
|
||||
moc.keys()
|
||||
.filter(|p| moc[p] == '.')
|
||||
.map(|p| (*p, field_factory(p)))
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn map_of_chars(input: &String) -> (HashMap<MapPoint, char>, C, C) {
|
||||
let mut map: HashMap<MapPoint, char> = input
|
||||
.lines()
|
||||
.enumerate()
|
||||
.flat_map(|(y, line)| {
|
||||
line.chars()
|
||||
.enumerate()
|
||||
.map(move |(x, c)| (MapPoint::of(x as C, y as C), c))
|
||||
})
|
||||
.collect();
|
||||
|
||||
let width = map.keys().map(|p| p.x).max().unwrap() + 1;
|
||||
let height = map.keys().map(|p| p.y).max().unwrap() + 1;
|
||||
|
||||
for x in 0..width {
|
||||
for y in 0..height {
|
||||
if !map.contains_key(&MapPoint::of(x, y)) {
|
||||
map.insert(MapPoint::of(x, y), ' ');
|
||||
}
|
||||
}
|
||||
}
|
||||
(map, width, height)
|
||||
}
|
||||
}
|
||||
|
||||
fn bfs(map: &FieldMap, start: RealPoint, finish: RealPoint) -> usize {
|
||||
let mut open: VecDeque<(RealPoint, usize)> = VecDeque::new();
|
||||
let mut seen: HashSet<RealPoint> = HashSet::new();
|
||||
|
||||
open.push_back((start, 0));
|
||||
seen.insert(start);
|
||||
|
||||
while let Some((p, d)) = open.pop_front() {
|
||||
if p == finish {
|
||||
return d;
|
||||
}
|
||||
|
||||
for neighbor in map[&p.map_point()].neighbors(p.level) {
|
||||
if !seen.contains(&neighbor) {
|
||||
open.push_back((neighbor, d + 1));
|
||||
seen.insert(neighbor);
|
||||
}
|
||||
}
|
||||
}
|
||||
panic!("no path found")
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use crate::tasks::day20::{DimensionField, Field, Maze, PortalField};
|
||||
|
||||
#[test]
|
||||
fn example_part1() {
|
||||
let input = std::fs::read_to_string("input/day20_example1.txt").unwrap();
|
||||
let maze = Maze::from(&input, PortalField::curried_factory);
|
||||
assert_eq!(maze.shortest_path(), 23);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn example_part2() {
|
||||
let input = std::fs::read_to_string("input/day20_example2.txt").unwrap();
|
||||
let maze = Maze::from(&input, DimensionField::curried_factory);
|
||||
assert_eq!(maze.shortest_path(), 396);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn result() {
|
||||
let input = std::fs::read_to_string("input/day20.txt").unwrap();
|
||||
let maze = Maze::from(&input, PortalField::curried_factory);
|
||||
assert_eq!(maze.shortest_path(), 454);
|
||||
|
||||
let maze = Maze::from(&input, DimensionField::curried_factory);
|
||||
assert_eq!(maze.shortest_path(), 5744);
|
||||
}
|
||||
}
|
||||
66
src/tasks/day21.rs
Normal file
66
src/tasks/day21.rs
Normal file
@@ -0,0 +1,66 @@
|
||||
use super::day05::*;
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn run() {
|
||||
let input = std::fs::read_to_string("input/day21.txt").unwrap();
|
||||
let ram: RAM = input
|
||||
.split(",")
|
||||
.enumerate()
|
||||
.map(|(i, s)| (i, s.parse::<i128>().unwrap()))
|
||||
.collect();
|
||||
task1(ram.clone());
|
||||
task2(ram.clone());
|
||||
}
|
||||
|
||||
fn task1(ram: RAM) {
|
||||
let p = r"NOT A J
|
||||
NOT B T
|
||||
OR T J
|
||||
NOT C T
|
||||
OR T J
|
||||
AND D J
|
||||
WALK
|
||||
"
|
||||
.to_string();
|
||||
play(ram.clone(), p);
|
||||
}
|
||||
|
||||
fn task2(ram: RAM) {
|
||||
// jump if NOT(A and B and C) and D and (H or (E and I) or (E and F))
|
||||
let p = r"OR H J
|
||||
OR E T
|
||||
AND I T
|
||||
OR T J
|
||||
NOT E T
|
||||
NOT T T
|
||||
AND F T
|
||||
OR T J
|
||||
AND D J
|
||||
NOT A T
|
||||
NOT T T
|
||||
AND B T
|
||||
AND C T
|
||||
NOT T T
|
||||
AND T J
|
||||
RUN
|
||||
"
|
||||
.to_string();
|
||||
play(ram.clone(), p);
|
||||
}
|
||||
|
||||
fn play(ram: RAM, program: String) {
|
||||
let mut computer = IntCodeComputer::new(program.chars().map(|c| c as i128).collect(), ram);
|
||||
computer.run_until_end();
|
||||
let output = computer.get_output();
|
||||
let s: String = output
|
||||
.iter()
|
||||
.map(|i| {
|
||||
if *i > 255 {
|
||||
format!("{}", i)
|
||||
} else {
|
||||
format!("{}", (*i as u8) as char)
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
println!("{}", s);
|
||||
}
|
||||
159
src/tasks/day22.rs
Normal file
159
src/tasks/day22.rs
Normal file
@@ -0,0 +1,159 @@
|
||||
use std::collections::VecDeque;
|
||||
|
||||
use mod_exp::mod_exp;
|
||||
use modinverse::modinverse;
|
||||
|
||||
use crate::tasks::day22::Cmd::{Cut, Deal, Stack};
|
||||
|
||||
pub fn run() {
|
||||
let input = std::fs::read_to_string("input/day22.txt").unwrap();
|
||||
println!("Task 1: {}", task1(&input));
|
||||
println!("Task 2: {}", task2(&input));
|
||||
}
|
||||
|
||||
type Deck = VecDeque<u16>;
|
||||
type Size = i128;
|
||||
|
||||
fn task1(input: &str) -> usize {
|
||||
let deck_size = 10_007;
|
||||
let mut deck: Deck = (0..deck_size).collect();
|
||||
for line in input.lines() {
|
||||
if line.starts_with("deal into new stack") {
|
||||
deck = into_new_stack(deck);
|
||||
} else if line.starts_with("cut") {
|
||||
let s = line.split("cut ").collect::<Vec<_>>();
|
||||
let n = s[1].parse::<i32>().unwrap();
|
||||
deck = cut_cards(deck, n);
|
||||
} else if line.starts_with("deal with increment") {
|
||||
let s = line.split("deal with increment ").collect::<Vec<_>>();
|
||||
let n = s[1].parse::<usize>().unwrap();
|
||||
deck = deal_with_increment(deck, n);
|
||||
}
|
||||
}
|
||||
|
||||
let pos_2019 = deck
|
||||
.iter()
|
||||
.enumerate()
|
||||
.find_map(|(i, card)| if *card == 2019 { Some(i) } else { None });
|
||||
|
||||
println!("Result: {:?}", pos_2019);
|
||||
pos_2019.unwrap()
|
||||
}
|
||||
|
||||
fn into_new_stack(deck: Deck) -> Deck {
|
||||
deck.into_iter().rev().collect()
|
||||
}
|
||||
|
||||
fn cut_cards(mut deck: Deck, n: i32) -> Deck {
|
||||
if n > 0 {
|
||||
deck.rotate_left(n as usize);
|
||||
} else {
|
||||
deck.rotate_right(-n as usize);
|
||||
};
|
||||
deck
|
||||
}
|
||||
|
||||
fn deal_with_increment(deck: Deck, n: usize) -> Deck {
|
||||
let mut new = vec![0; deck.len()];
|
||||
let mut index = 0;
|
||||
for card in deck.into_iter() {
|
||||
new[index] = card;
|
||||
index = (index + n) % new.len();
|
||||
}
|
||||
new.into_iter().collect()
|
||||
}
|
||||
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
enum Cmd { Stack, Cut(i128), Deal(i128) }
|
||||
|
||||
// I don't understand this solution but I copied it because I wanted the last star :> (c) AxlLind@github
|
||||
fn task2(input: &String) -> Size {
|
||||
const M: i128 = 119_315_717_514_047;
|
||||
const N: i128 = 101_741_582_076_661;
|
||||
|
||||
let commands: Vec<_> = input.lines().map(|line| {
|
||||
if line.starts_with("deal into new stack") {
|
||||
Stack
|
||||
} else if line.starts_with("cut") {
|
||||
let s = line.split("cut ").collect::<Vec<_>>();
|
||||
let n = s[1].parse::<i128>().unwrap();
|
||||
Cut(n)
|
||||
} else if line.starts_with("deal with increment") {
|
||||
let s = line.split("deal with increment ").collect::<Vec<_>>();
|
||||
let n = s[1].parse::<i128>().unwrap();
|
||||
Deal(n)
|
||||
} else {
|
||||
panic!("'{line}' is illegal")
|
||||
}
|
||||
}).collect();
|
||||
|
||||
// Convert the whole process to a linear equation: ax + b
|
||||
let (a, b) = commands.iter().rev().fold((1, 0), |(a, b), &cmd| {
|
||||
let (a_new, b_new) = match cmd {
|
||||
Stack => (-a, -b - 1),
|
||||
Cut(n) => (a, b + n),
|
||||
Deal(n) => {
|
||||
let n = mod_exp(n, M - 2, M);
|
||||
(a * n, b * n)
|
||||
}
|
||||
};
|
||||
(a_new % M, b_new % M)
|
||||
});
|
||||
|
||||
// Applying the function n times simplifies to:
|
||||
// x * a^n + b * (a^n - 1) / (a-1)
|
||||
let term1 = 2020 * mod_exp(a, N, M) % M;
|
||||
let tmp = (mod_exp(a, N, M) - 1) * mod_exp(a - 1, M - 2, M) % M;
|
||||
let term2 = b * tmp % M;
|
||||
(term1 + term2) % M
|
||||
}
|
||||
|
||||
fn revert_iteration_find_start(shuffles: &Vec<String>, deck_size: Size, field_after: Size) -> Size {
|
||||
let mut current: Size = field_after;
|
||||
for line in shuffles {
|
||||
if line.starts_with("deal into new stack") {
|
||||
current = deck_size - 1 - current;
|
||||
} else if line.starts_with("cut") {
|
||||
let s = line.split("cut ").collect::<Vec<_>>();
|
||||
let n = s[1].parse::<Size>().unwrap();
|
||||
current += n;
|
||||
current += deck_size;
|
||||
current %= deck_size;
|
||||
} else if line.starts_with("deal with increment") {
|
||||
let s = line.split("deal with increment ").collect::<Vec<_>>();
|
||||
let n = s[1].parse::<Size>().unwrap();
|
||||
current = revert_finite_field_multiplikation(deck_size, n, current);
|
||||
}
|
||||
}
|
||||
|
||||
current
|
||||
}
|
||||
|
||||
fn revert_finite_field_multiplikation(
|
||||
field_length: Size,
|
||||
multiplicator: Size,
|
||||
result: Size,
|
||||
) -> Size {
|
||||
let multiplicator_inverse =
|
||||
modinverse(multiplicator, field_length).expect("no modular inverse found");
|
||||
(result * multiplicator_inverse) % field_length
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use crate::tasks::day22::task1;
|
||||
use crate::tasks::day22::task2;
|
||||
|
||||
#[test]
|
||||
fn part1() {
|
||||
let input = std::fs::read_to_string("input/day22.txt").unwrap();
|
||||
assert_eq!(7545, task1(&input));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn part2() {
|
||||
let input = std::fs::read_to_string("input/day22.txt").unwrap();
|
||||
assert_eq!(2019, task2(&input));
|
||||
}
|
||||
}
|
||||
100
src/tasks/day23.rs
Normal file
100
src/tasks/day23.rs
Normal file
@@ -0,0 +1,100 @@
|
||||
use std::collections::VecDeque;
|
||||
|
||||
use crate::tasks::day05::{IntCodeComputer, load_ram, RAM};
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn run() {
|
||||
let ram = load_ram("input/day23.txt");
|
||||
part1(ram.clone());
|
||||
part2(ram.clone());
|
||||
}
|
||||
|
||||
fn part1(ram: RAM) {
|
||||
let mut computers: Vec<IntCodeComputer> = (0..50).map(|address| IntCodeComputer::new(vec![address], ram.clone())).collect();
|
||||
let mut buffer: VecDeque<Packet> = VecDeque::new();
|
||||
loop {
|
||||
for computer in &mut computers {
|
||||
computer.add_input(&[-1]);
|
||||
computer.run_until_input_empty();
|
||||
if computer.get_output().len() >= 3 {
|
||||
buffer.push_back(Packet::from(&computer.get_output()[0..3]));
|
||||
computer.clear_n_output(3);
|
||||
}
|
||||
}
|
||||
|
||||
while let Some(packet) = buffer.pop_front() {
|
||||
if packet.destination == 255 {
|
||||
println!("Part 1: Finished with first y={} to 255", packet.y);
|
||||
return;
|
||||
}
|
||||
|
||||
computers[packet.destination].add_input(packet.to_input().as_slice());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn part2(ram: RAM) {
|
||||
let mut computers: Vec<IntCodeComputer> = (0..50).map(|address| IntCodeComputer::new(vec![address], ram.clone())).collect();
|
||||
let mut buffer: VecDeque<Packet> = VecDeque::new();
|
||||
|
||||
let mut rounds_without_packets = 0;
|
||||
let mut nat_content: Option<Packet> = None;
|
||||
let mut pushed_to_first: Vec<Packet> = Vec::new();
|
||||
loop {
|
||||
for computer in &mut computers {
|
||||
if computer.get_input().is_empty() {
|
||||
computer.add_input(&[-1, -1, -1]);
|
||||
}
|
||||
computer.run_until_input_empty();
|
||||
while computer.get_output().len() >= 3 {
|
||||
buffer.push_back(Packet::from(&computer.get_output()[0..3]));
|
||||
computer.clear_n_output(3);
|
||||
}
|
||||
}
|
||||
|
||||
if buffer.is_empty() {
|
||||
rounds_without_packets += 1;
|
||||
}
|
||||
if let Some(ref energy_packet) = nat_content {
|
||||
if rounds_without_packets > 5 {
|
||||
if let Some(last) = pushed_to_first.last() {
|
||||
if last == energy_packet {
|
||||
println!("Part 2: Got the same packet twice. Y was {}", last.y);
|
||||
return;
|
||||
}
|
||||
}
|
||||
pushed_to_first.push(energy_packet.clone());
|
||||
buffer.push_back(energy_packet.clone());
|
||||
rounds_without_packets = 0;
|
||||
}
|
||||
}
|
||||
while let Some(packet) = buffer.pop_front() {
|
||||
if packet.destination == 255 {
|
||||
nat_content = Some(Packet { destination: 0, x: packet.x, y: packet.y });
|
||||
continue;
|
||||
}
|
||||
|
||||
computers[packet.destination].add_input(packet.to_input().as_slice());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Debug)]
|
||||
struct Packet {
|
||||
destination: usize,
|
||||
x: i128,
|
||||
y: i128,
|
||||
}
|
||||
|
||||
impl Packet {
|
||||
fn from(slice: &[i128]) -> Packet {
|
||||
if slice.len() != 3 {
|
||||
panic!("not enough for a packet")
|
||||
}
|
||||
Packet { destination: slice[0] as usize, x: slice[1], y: slice[2] }
|
||||
}
|
||||
|
||||
fn to_input(&self) -> Vec<i128> {
|
||||
vec![self.x, self.y]
|
||||
}
|
||||
}
|
||||
352
src/tasks/day24.rs
Normal file
352
src/tasks/day24.rs
Normal file
@@ -0,0 +1,352 @@
|
||||
use itertools::Itertools;
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::fmt;
|
||||
use Tile::*;
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn run() {
|
||||
let input = "..#.#
|
||||
#####
|
||||
.#?..
|
||||
...#.
|
||||
##...
|
||||
";
|
||||
let _einput = "....#
|
||||
#..#.
|
||||
#..##
|
||||
..#..
|
||||
#....";
|
||||
task1(Life::from(input));
|
||||
task2(input);
|
||||
}
|
||||
|
||||
fn task1(mut life: Life) {
|
||||
let mut hashes = HashMap::<Life, usize>::new();
|
||||
hashes.insert(life.clone(), 0);
|
||||
for round in 1.. {
|
||||
life.round();
|
||||
if hashes.contains_key(&life) {
|
||||
break;
|
||||
} else {
|
||||
hashes.insert(life.clone(), round);
|
||||
}
|
||||
}
|
||||
println!(
|
||||
"Task 1: bio diversity of first reoccuring state is {}",
|
||||
life.bio_diversity()
|
||||
);
|
||||
}
|
||||
|
||||
fn task2(input: &str) {
|
||||
let mut state: HashMap<Field, Tile> = input
|
||||
.lines()
|
||||
.enumerate()
|
||||
.flat_map(|(y, line)| {
|
||||
line.chars()
|
||||
.enumerate()
|
||||
.filter_map(|(x, c)| {
|
||||
if c == '#' || c == '.' {
|
||||
Some((
|
||||
Field(0, x as i32, y as i32),
|
||||
if c == '#' { Bug } else { Empty },
|
||||
))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.collect_vec()
|
||||
})
|
||||
.collect();
|
||||
for _round in 1..=200 {
|
||||
let new: HashMap<Field, Tile> = state
|
||||
.keys()
|
||||
.map(|field| {
|
||||
let v = field
|
||||
.neighbors()
|
||||
.iter()
|
||||
.chain(std::iter::once(field))
|
||||
.map(|f| *f)
|
||||
.collect_vec();
|
||||
v
|
||||
})
|
||||
.flatten()
|
||||
.map(|f| (f, new_state_of(f, &state)))
|
||||
.collect();
|
||||
state = new;
|
||||
}
|
||||
let bug_count = state.iter().filter(|(_k, tile)| **tile == Bug).count();
|
||||
println!("Task 2: we have {} bugs overall", bug_count);
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
fn print_levels(state: &HashMap<Field, Tile>, mark_neighbors: Field) {
|
||||
let mut levels = state
|
||||
.iter()
|
||||
.map(|(Field(level, _, _), _)| *level)
|
||||
.collect::<HashSet<i32>>()
|
||||
.into_iter()
|
||||
.collect_vec();
|
||||
levels.sort();
|
||||
|
||||
let neighbors = mark_neighbors.neighbors();
|
||||
|
||||
for level in levels {
|
||||
println!("Depth {}:", level);
|
||||
for y in 0..5 {
|
||||
for x in 0..5 {
|
||||
let c = if x == 2 && y == 2 {
|
||||
'?'
|
||||
} else if Field(level, x, y) == mark_neighbors {
|
||||
'O'
|
||||
} else if neighbors.contains(&Field(level, x, y)) {
|
||||
'x'
|
||||
} else if let Some(tile) = state.get(&Field(level, x, y)) {
|
||||
match tile {
|
||||
Bug => '#',
|
||||
Empty => '.',
|
||||
}
|
||||
} else {
|
||||
'*'
|
||||
};
|
||||
print!("{}", c);
|
||||
}
|
||||
println!("");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn new_state_of(field: Field, state: &HashMap<Field, Tile>) -> Tile {
|
||||
let at = |f| *state.get(&f).unwrap_or(&Empty);
|
||||
let old = at(field);
|
||||
if at(field) == Bug {
|
||||
if field
|
||||
.neighbors()
|
||||
.into_iter()
|
||||
.filter(|p| at(*p) == Bug)
|
||||
.count()
|
||||
!= 1
|
||||
{
|
||||
Empty
|
||||
} else {
|
||||
old
|
||||
}
|
||||
} else {
|
||||
let count = field
|
||||
.neighbors()
|
||||
.into_iter()
|
||||
.filter(|p| at(*p) == Bug)
|
||||
.count();
|
||||
if count == 1 || count == 2 {
|
||||
Bug
|
||||
} else {
|
||||
old
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Eq, PartialEq, Hash, Clone, Copy, Debug)]
|
||||
struct Field(i32, i32, i32);
|
||||
impl Field {
|
||||
fn neighbors(&self) -> Vec<Self> {
|
||||
let mut res = vec![
|
||||
Self(self.0, self.1 - 1, self.2),
|
||||
Self(self.0, self.1 + 1, self.2),
|
||||
Self(self.0, self.1, self.2 - 1),
|
||||
Self(self.0, self.1, self.2 + 1),
|
||||
];
|
||||
res.retain(|p| !(p.1 == 2 && p.2 == 2) && ((0..5).contains(&p.1) && (0..5).contains(&p.2)));
|
||||
|
||||
// link to higher level
|
||||
if self.1 == 0 {
|
||||
res.push(Self(self.0 - 1, 1, 2));
|
||||
}
|
||||
if self.1 == 4 {
|
||||
res.push(Self(self.0 - 1, 3, 2));
|
||||
}
|
||||
if self.2 == 0 {
|
||||
res.push(Self(self.0 - 1, 2, 1));
|
||||
}
|
||||
if self.2 == 4 {
|
||||
res.push(Self(self.0 - 1, 2, 3));
|
||||
}
|
||||
|
||||
// link to lower level
|
||||
match self {
|
||||
Field(lvl, 2, 1) => (0..5).for_each(|x| res.push(Self(lvl + 1, x, 0))),
|
||||
Field(lvl, 2, 3) => (0..5).for_each(|x| res.push(Self(lvl + 1, x, 4))),
|
||||
Field(lvl, 1, 2) => (0..5).for_each(|y| res.push(Self(lvl + 1, 0, y))),
|
||||
Field(lvl, 3, 2) => (0..5).for_each(|y| res.push(Self(lvl + 1, 4, y))),
|
||||
_ => (),
|
||||
}
|
||||
|
||||
res
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Eq, Hash, Clone)]
|
||||
struct Life {
|
||||
area: [[Tile; 5]; 5],
|
||||
}
|
||||
|
||||
impl Life {
|
||||
fn from(string: &str) -> Self {
|
||||
let vecs = string
|
||||
.lines()
|
||||
.map(|line| {
|
||||
line.chars()
|
||||
.map(|c| if c == '#' { Bug } else { Empty })
|
||||
.collect_vec()
|
||||
})
|
||||
.collect_vec();
|
||||
assert_eq!(5, vecs.len());
|
||||
assert_eq!(5, vecs[0].len());
|
||||
|
||||
let mut life = Life {
|
||||
area: [[Empty; 5]; 5],
|
||||
};
|
||||
|
||||
for x in 0..5 {
|
||||
for y in 0..5 {
|
||||
life.area[x][y] = vecs[y][x];
|
||||
}
|
||||
}
|
||||
life
|
||||
}
|
||||
|
||||
fn at(&self, pos: Pos) -> Tile {
|
||||
if (0..5).contains(&pos.0) && (0..5).contains(&pos.1) {
|
||||
self.area[pos.0 as usize][pos.1 as usize]
|
||||
} else {
|
||||
Empty
|
||||
}
|
||||
}
|
||||
|
||||
fn round(&mut self) {
|
||||
let mut new = self.area.clone();
|
||||
for y in 0..5 {
|
||||
for x in 0..5 {
|
||||
if self.at(Pos(x, y)) == Bug {
|
||||
if Pos(x, y)
|
||||
.neighbors()
|
||||
.iter()
|
||||
.filter(|p| self.at(**p) == Bug)
|
||||
.count()
|
||||
!= 1
|
||||
{
|
||||
new[x as usize][y as usize] = Empty;
|
||||
}
|
||||
} else {
|
||||
let count = Pos(x, y)
|
||||
.neighbors()
|
||||
.iter()
|
||||
.filter(|p| self.at(**p) == Bug)
|
||||
.count();
|
||||
if count == 1 || count == 2 {
|
||||
new[x as usize][y as usize] = Bug;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
self.area = new;
|
||||
}
|
||||
|
||||
fn bio_diversity(&self) -> usize {
|
||||
(0..5)
|
||||
.map(|x| {
|
||||
(0..5)
|
||||
.map(|y| {
|
||||
if self.at(Pos(x, y)).is_bug() {
|
||||
let v = 1usize.wrapping_shl((5 * y + x) as u32);
|
||||
v
|
||||
} else {
|
||||
0 as usize
|
||||
}
|
||||
})
|
||||
.sum::<usize>()
|
||||
})
|
||||
.sum()
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Life {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
for y in 0..5 {
|
||||
for x in 0..5 {
|
||||
let r = write!(f, "{}", self.area[x][y]);
|
||||
if let fmt::Result::Err(_) = r {
|
||||
return r;
|
||||
}
|
||||
}
|
||||
let r = writeln!(f, "");
|
||||
if let fmt::Result::Err(_) = r {
|
||||
return r;
|
||||
}
|
||||
}
|
||||
fmt::Result::Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
|
||||
enum Tile {
|
||||
Bug,
|
||||
Empty,
|
||||
}
|
||||
|
||||
impl Tile {
|
||||
fn is_bug(&self) -> bool {
|
||||
*self == Bug
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Tile {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"{}",
|
||||
match self {
|
||||
Bug => '#',
|
||||
Empty => '.',
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
|
||||
struct Pos(i32, i32);
|
||||
|
||||
impl Pos {
|
||||
fn neighbors(&self) -> [Pos; 4] {
|
||||
[
|
||||
Pos(self.0 - 1, self.1),
|
||||
Pos(self.0 + 1, self.1),
|
||||
Pos(self.0, self.1 - 1),
|
||||
Pos(self.0, self.1 + 1),
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
mod test {
|
||||
use super::Field;
|
||||
#[test]
|
||||
fn neighborhood_bijective() {
|
||||
for x in 0..5 {
|
||||
for y in 0..5 {
|
||||
if x == 2 && y == 2 {
|
||||
continue;
|
||||
}
|
||||
let field = Field(0, x, y);
|
||||
let neighbors = field.neighbors();
|
||||
neighbors.into_iter().for_each(|n| {
|
||||
assert_eq!(
|
||||
n.neighbors().contains(&field),
|
||||
true,
|
||||
"{:?} is not a neighbor of its neighbor {:?}",
|
||||
field,
|
||||
n
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
44
src/tasks/day25.rs
Normal file
44
src/tasks/day25.rs
Normal file
@@ -0,0 +1,44 @@
|
||||
use std::io;
|
||||
|
||||
use crate::tasks::day05::{IntCodeComputer, load_ram};
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn run() {
|
||||
let ram = load_ram("input/day25.txt");
|
||||
let mut computer = IntCodeComputer::new(vec![], ram);
|
||||
|
||||
loop {
|
||||
let done = computer.run_until_input_empty();
|
||||
println!("{}", to_ascii(computer.get_output()));
|
||||
computer.clear_output();
|
||||
|
||||
if done {
|
||||
println!("Game Over");
|
||||
return;
|
||||
}
|
||||
|
||||
let input = read_line();
|
||||
computer.set_input(&input);
|
||||
}
|
||||
|
||||
// needed items:
|
||||
// fixed point
|
||||
// polygon
|
||||
// candy cane
|
||||
// shell
|
||||
|
||||
// result: 136839232
|
||||
}
|
||||
|
||||
fn to_ascii(output: &[i128]) -> String {
|
||||
output.iter().map(|i| (*i as u8) as char).collect()
|
||||
}
|
||||
|
||||
fn read_line() -> Vec<i128> {
|
||||
let mut buffer = String::new();
|
||||
io::stdin().read_line(&mut buffer).unwrap();
|
||||
if !buffer.is_ascii() {
|
||||
panic!("'{}' is not ascii input", buffer);
|
||||
}
|
||||
buffer.chars().map(|c| c as i128).collect()
|
||||
}
|
||||
@@ -3,4 +3,23 @@ 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;
|
||||
#[allow(dead_code)]
|
||||
pub mod day22;
|
||||
pub mod day23;
|
||||
pub mod day24;
|
||||
pub mod day25;
|
||||
|
||||
Reference in New Issue
Block a user