Compare commits
29 Commits
a5019f1afb
...
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 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,3 +1,4 @@
|
||||
/target
|
||||
**/*.rs.bk
|
||||
.vscode
|
||||
.idea
|
||||
137
Cargo.lock
generated
137
Cargo.lock
generated
@@ -1,100 +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.6"
|
||||
version = "0.7.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f"
|
||||
dependencies = [
|
||||
"memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "aoc_2019"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"itertools 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"regex 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"itertools",
|
||||
"mod_exp",
|
||||
"modinverse",
|
||||
"num-integer",
|
||||
"regex",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "0.1.7"
|
||||
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",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "1.4.0"
|
||||
name = "memchr"
|
||||
version = "2.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a"
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.2.1"
|
||||
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.41"
|
||||
version = "0.1.44"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db"
|
||||
dependencies = [
|
||||
"autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-traits 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"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.10"
|
||||
version = "0.2.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290"
|
||||
dependencies = [
|
||||
"autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.3.1"
|
||||
version = "1.5.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1a11647b6b25ff05a515cb92c365cec08801e83423a235b51e231e1808747286"
|
||||
dependencies = [
|
||||
"aho-corasick 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"regex-syntax 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
"regex-syntax",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-syntax"
|
||||
version = "0.6.12"
|
||||
version = "0.6.25"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "thread_local"
|
||||
version = "0.3.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[metadata]
|
||||
"checksum aho-corasick 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)" = "58fb5e95d83b38284460a5fda7d6470aa0b8844d283a0b614b8535e880800d2d"
|
||||
"checksum autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "1d49d90015b3c36167a20fe2810c5cd875ad504b39cff3d4eae7977e6b7c1cb2"
|
||||
"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"
|
||||
"checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||
"checksum memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "88579771288728879b57485cc7d6b07d648c9f0141eb955f8ab7f9d45394468e"
|
||||
"checksum num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)" = "b85e541ef8255f6cf42bbfe4ef361305c6c135d10919ecc26126c4e5ae94bc09"
|
||||
"checksum num-traits 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "d4c81ffc11c212fa327657cb19dd85eb7419e163b5b076bede2bdb5c974c07e4"
|
||||
"checksum regex 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dc220bd33bdce8f093101afe22a037b8eb0e5af33592e6a9caafff0d4cb81cbd"
|
||||
"checksum regex-syntax 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)" = "11a7e20d1cce64ef2fed88b66d347f88bd9babb82845b2b858f3edbf59a4f716"
|
||||
"checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b"
|
||||
checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b"
|
||||
|
||||
10
Cargo.toml
10
Cargo.toml
@@ -2,11 +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"
|
||||
regex = "1.3.1"
|
||||
num-integer = "0.1"
|
||||
itertools = "0.10.3"
|
||||
regex = "1.5.5"
|
||||
num-integer = "0.1.44"
|
||||
modinverse = "0.1.1"
|
||||
mod_exp = "1.0.1"
|
||||
|
||||
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
|
||||
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,5 +1,7 @@
|
||||
extern crate core;
|
||||
|
||||
mod tasks;
|
||||
|
||||
fn main() {
|
||||
tasks::day17::run();
|
||||
tasks::day22::run();
|
||||
}
|
||||
|
||||
@@ -217,6 +217,7 @@ impl IntCodeComputer {
|
||||
op.params[0].store(&mut self.ram, *v, self.relative_base_offset);
|
||||
self.pc += 2;
|
||||
} else {
|
||||
self.input_storage.clear();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -282,10 +283,24 @@ impl IntCodeComputer {
|
||||
}
|
||||
}
|
||||
|
||||
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()
|
||||
}
|
||||
|
||||
@@ -1,77 +1,175 @@
|
||||
use itertools::Itertools;
|
||||
use num_integer::Integer;
|
||||
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 = "03036732577212944063491565474664" //"59750530221324194853012320069589312027523989854830232144164799228029162830477472078089790749906142587998642764059439173975199276254972017316624772614925079238407309384923979338502430726930592959991878698412537971672558832588540600963437409230550897544434635267172603132396722812334366528344715912756154006039512272491073906389218927420387151599044435060075148142946789007756800733869891008058075303490106699737554949348715600795187032293436328810969288892220127730287766004467730818489269295982526297430971411865028098708555709525646237713045259603175397623654950719275982134690893685598734136409536436003548128411943963263336042840301380655801969822"
|
||||
.chars()
|
||||
.map(|it| it.to_digit(10).unwrap() as i32)
|
||||
.collect_vec();
|
||||
let input = to_digits(INPUT);
|
||||
task1(input.clone());
|
||||
task2(to_digits("02935109699940807407585447034323"));
|
||||
task2(input.clone());
|
||||
}
|
||||
|
||||
fn task1(input: Vec<i32>) {
|
||||
let p = [0, 1, 0, -1];
|
||||
let result = (0..100).fold(input, |old, _| {
|
||||
(1..=old.len())
|
||||
.map(|position| {
|
||||
let pattern = p
|
||||
.iter()
|
||||
.map(|x| std::iter::repeat(*x).take(position))
|
||||
.flatten();
|
||||
let val: i32 = old
|
||||
.iter()
|
||||
.zip(std::iter::repeat(pattern).flatten().skip(1))
|
||||
.map(|(value, multiplier)| value * multiplier)
|
||||
.sum();
|
||||
val.abs() % 10
|
||||
})
|
||||
.collect_vec()
|
||||
});
|
||||
println!("Task 1: {:.*}", 8, result.iter().join(""));
|
||||
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 task2(input: Vec<i32>) {
|
||||
let l = input.len() * 10_000;
|
||||
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()
|
||||
.take(l)
|
||||
.collect_vec();
|
||||
let p = [0, 1, 0, -1];
|
||||
let result = (0..100).fold(big_input, |old, _| {
|
||||
(1..=old.len())
|
||||
.map(|position| {
|
||||
let pattern = p.iter().map(|x| iter::repeat(*x).take(position)).flatten();
|
||||
let iter = iter::repeat(pattern).flatten().skip(1);
|
||||
let repeats_after = (4 * position).lcm(&input.len());
|
||||
if repeats_after > l {
|
||||
l
|
||||
} else {
|
||||
repeats_after
|
||||
};
|
||||
let part: i32 = iter::repeat(input.iter())
|
||||
.flatten()
|
||||
.zip(iter.clone())
|
||||
.take(repeats_after)
|
||||
.map(|(value, multiplier)| value * multiplier)
|
||||
.sum();
|
||||
let part_fits = l / repeats_after;
|
||||
let most_parts = part * part_fits as i32;
|
||||
|
||||
let number_rest = l / repeats_after;
|
||||
let part_rest: i32 = iter
|
||||
.zip(iter::repeat(input.iter()).flatten())
|
||||
.take(number_rest)
|
||||
.map(|(value, multiplier)| value * multiplier)
|
||||
.sum();
|
||||
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(""));
|
||||
|
||||
(part_rest + most_parts) % 10
|
||||
})
|
||||
.collect_vec()
|
||||
});
|
||||
let offset = input[0..7].iter().join("").parse::<usize>().unwrap();
|
||||
let message = result[offset..offset + 8].iter().join("");
|
||||
println!("Task 2: {}", message);
|
||||
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"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
use super::day05::*;
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn run() {
|
||||
let input: RAM = std::fs::read_to_string("input/day17.txt")
|
||||
.unwrap()
|
||||
|
||||
@@ -15,8 +15,8 @@ pub fn run() {
|
||||
|
||||
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);
|
||||
//let t2 = task(input.clone().split_robot());
|
||||
//println!("Task 2: best bound to get all keys is {}", t2);
|
||||
}
|
||||
|
||||
fn task(map: Map) -> usize {
|
||||
@@ -32,20 +32,17 @@ fn task(map: Map) -> usize {
|
||||
|
||||
let mut visited: HashSet<StateSummary> = HashSet::new();
|
||||
let mut open: BinaryHeap<State> = BinaryHeap::new();
|
||||
let mut best_found_for_all = std::usize::MAX;
|
||||
|
||||
open.push(State::new(map.clone()));
|
||||
while let Some(state) = open.pop() {
|
||||
let summary = StateSummary::from(&state);
|
||||
if visited.contains(&summary) || best_found_for_all <= state.steps_taken {
|
||||
if visited.contains(&summary) {
|
||||
// there could come no better solution
|
||||
continue;
|
||||
}
|
||||
|
||||
if summary.1 == all_keys {
|
||||
if state.steps_taken < best_found_for_all {
|
||||
best_found_for_all = state.steps_taken;
|
||||
}
|
||||
return state.steps_taken;
|
||||
}
|
||||
|
||||
state
|
||||
@@ -56,7 +53,7 @@ fn task(map: Map) -> usize {
|
||||
visited.insert(summary);
|
||||
}
|
||||
|
||||
best_found_for_all
|
||||
panic!("if we reach this point no path can be found");
|
||||
}
|
||||
|
||||
#[derive(Eq, PartialEq, Hash, Debug)]
|
||||
@@ -83,6 +80,7 @@ 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
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
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()
|
||||
}
|
||||
@@ -15,4 +15,11 @@ 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