summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJustin Wernick <justin@worthe-it.co.za>2022-04-19 20:32:43 +0200
committerJustin Wernick <justin@worthe-it.co.za>2022-04-19 20:32:43 +0200
commit2410e500560a1989399c8ad0c23fe7aa9827576d (patch)
tree5e3a18944de222f4d0565fb208d4d89f9eebdf2b
parentcb3d2db9b82f131ebb36a9b3bea6830bf1a80c0f (diff)
parent9892e3ebde304726903a1e5c358d05c2e343ea5e (diff)
Merge branch '2019-main'
-rw-r--r--.gitignore3
-rw-r--r--2019/Cargo.lock580
-rw-r--r--2019/Cargo.toml19
-rw-r--r--2019/inputs/day_1.txt100
-rw-r--r--2019/inputs/day_10.txt24
-rw-r--r--2019/inputs/day_11.txt1
-rw-r--r--2019/inputs/day_12.txt4
-rw-r--r--2019/inputs/day_13.txt1
-rw-r--r--2019/inputs/day_14.txt59
-rw-r--r--2019/inputs/day_15.txt1
-rw-r--r--2019/inputs/day_16.txt1
-rw-r--r--2019/inputs/day_17.txt1
-rw-r--r--2019/inputs/day_18.txt81
-rw-r--r--2019/inputs/day_18_2.txt81
-rw-r--r--2019/inputs/day_19.txt1
-rw-r--r--2019/inputs/day_2.txt1
-rw-r--r--2019/inputs/day_20.txt113
-rw-r--r--2019/inputs/day_21.txt1
-rw-r--r--2019/inputs/day_22.txt100
-rw-r--r--2019/inputs/day_23.txt1
-rw-r--r--2019/inputs/day_24.txt5
-rw-r--r--2019/inputs/day_25.txt1
-rw-r--r--2019/inputs/day_3.txt2
-rw-r--r--2019/inputs/day_4.txt2
-rw-r--r--2019/inputs/day_5.txt1
-rw-r--r--2019/inputs/day_6.txt2306
-rw-r--r--2019/inputs/day_7.txt1
-rw-r--r--2019/inputs/day_8.txt1
-rw-r--r--2019/inputs/day_9.txt1
-rw-r--r--2019/readme.org26
-rw-r--r--2019/src/bin/day_1.rs93
-rw-r--r--2019/src/bin/day_10.rs158
-rw-r--r--2019/src/bin/day_11.rs205
-rw-r--r--2019/src/bin/day_12.rs205
-rw-r--r--2019/src/bin/day_13.rs149
-rw-r--r--2019/src/bin/day_14.rs221
-rw-r--r--2019/src/bin/day_15.rs183
-rw-r--r--2019/src/bin/day_16.rs112
-rw-r--r--2019/src/bin/day_17.rs78
-rw-r--r--2019/src/bin/day_18.rs365
-rw-r--r--2019/src/bin/day_19.rs102
-rw-r--r--2019/src/bin/day_2.rs96
-rw-r--r--2019/src/bin/day_20.rs310
-rw-r--r--2019/src/bin/day_21.rs109
-rw-r--r--2019/src/bin/day_22.rs325
-rw-r--r--2019/src/bin/day_23.rs211
-rw-r--r--2019/src/bin/day_24.rs239
-rw-r--r--2019/src/bin/day_25.dot43
-rw-r--r--2019/src/bin/day_25.rs110
-rw-r--r--2019/src/bin/day_3.rs333
-rw-r--r--2019/src/bin/day_4.rs55
-rw-r--r--2019/src/bin/day_5.rs45
-rw-r--r--2019/src/bin/day_6.rs251
-rw-r--r--2019/src/bin/day_7.rs175
-rw-r--r--2019/src/bin/day_8.rs135
-rw-r--r--2019/src/bin/day_9.rs1
-rw-r--r--2019/src/lib.rs438
-rw-r--r--2019/src/main.rs12
58 files changed, 8276 insertions, 2 deletions
diff --git a/.gitignore b/.gitignore
index 6aa1064..53eaa21 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,2 @@
-/target/
+/target
**/*.rs.bk
-Cargo.lock
diff --git a/2019/Cargo.lock b/2019/Cargo.lock
new file mode 100644
index 0000000..52c69da
--- /dev/null
+++ b/2019/Cargo.lock
@@ -0,0 +1,580 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+[[package]]
+name = "ansi_term"
+version = "0.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "aoc2019"
+version = "0.1.0"
+dependencies = [
+ "archery 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cached 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "derivative 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "derive_more 0.99.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "im 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "num 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rayon 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rpds 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "structopt 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "archery"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "static_assertions 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "atty"
+version = "0.2.13"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "autocfg"
+version = "0.1.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "bitflags"
+version = "1.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "bitmaps"
+version = "2.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "typenum 1.11.2 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "cached"
+version = "0.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "once_cell 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "cfg-if"
+version = "0.1.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "clap"
+version = "2.33.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)",
+ "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "unicode-width 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "crossbeam-deque"
+version = "0.7.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "crossbeam-epoch 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "crossbeam-utils 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "crossbeam-epoch"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
+ "crossbeam-utils 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "memoffset 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "crossbeam-queue"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "crossbeam-utils 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "crossbeam-utils"
+version = "0.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
+ "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "derivative"
+version = "1.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
+ "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)",
+ "syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "derive_more"
+version = "0.99.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "syn 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "either"
+version = "1.5.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "heck"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "unicode-segmentation 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "hermit-abi"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "im"
+version = "14.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "bitmaps 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rand_xoshiro 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "sized-chunks 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "typenum 1.11.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "version_check 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "lazy_static"
+version = "1.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "libc"
+version = "0.2.66"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "memoffset"
+version = "0.5.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "num"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "num-bigint 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "num-complex 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)",
+ "num-iter 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)",
+ "num-rational 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "num-traits 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "num-bigint"
+version = "0.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
+ "num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)",
+ "num-traits 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "num-complex"
+version = "0.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+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)",
+]
+
+[[package]]
+name = "num-integer"
+version = "0.1.41"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+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)",
+]
+
+[[package]]
+name = "num-iter"
+version = "0.1.39"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
+ "num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)",
+ "num-traits 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "num-rational"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
+ "num-bigint 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)",
+ "num-traits 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "num-traits"
+version = "0.2.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "num_cpus"
+version = "1.11.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "hermit-abi 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "once_cell"
+version = "1.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "proc-macro-error"
+version = "0.2.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "syn 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "proc-macro2"
+version = "0.4.30"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "proc-macro2"
+version = "1.0.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "quote"
+version = "0.6.13"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "quote"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "rand_core"
+version = "0.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "rand_xoshiro"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "rayon"
+version = "1.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "crossbeam-deque 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rayon-core 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "rayon-core"
+version = "1.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "crossbeam-deque 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "crossbeam-queue 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "crossbeam-utils 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "num_cpus 1.11.1 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "rpds"
+version = "0.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "archery 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "rustc_version"
+version = "0.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "scopeguard"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "semver"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "semver-parser"
+version = "0.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "sized-chunks"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "bitmaps 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "typenum 1.11.2 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "static_assertions"
+version = "0.3.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "strsim"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "structopt"
+version = "0.3.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "structopt-derive 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "structopt-derive"
+version = "0.3.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "proc-macro-error 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "syn 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "syn"
+version = "0.15.44"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
+ "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)",
+ "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "syn"
+version = "1.0.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "textwrap"
+version = "0.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "unicode-width 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "typenum"
+version = "1.11.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "unicode-segmentation"
+version = "1.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "unicode-width"
+version = "0.1.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "unicode-xid"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "unicode-xid"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "vec_map"
+version = "0.8.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "version_check"
+version = "0.9.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "winapi"
+version = "0.3.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "winapi-i686-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "winapi-x86_64-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[metadata]
+"checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
+"checksum archery 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d308d8fa3f687f7a7588fccc4812ed6914be09518232f00454693a7417273ad2"
+"checksum atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)" = "1803c647a3ec87095e7ae7acfca019e98de5ec9a7d01343f611cf3152ed71a90"
+"checksum autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "1d49d90015b3c36167a20fe2810c5cd875ad504b39cff3d4eae7977e6b7c1cb2"
+"checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
+"checksum bitmaps 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "81e039a80914325b37fde728ef7693c212f0ac913d5599607d7b95a9484aae0b"
+"checksum cached 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b052fd10f32987c3bd028d91ef86190b36fba5c8fccb5515d42083f061e6104"
+"checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
+"checksum clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5067f5bb2d80ef5d68b4c87db81601f0b75bca627bc2ef76b141d7b846a3c6d9"
+"checksum crossbeam-deque 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c3aa945d63861bfe624b55d153a39684da1e8c0bc8fba932f7ee3a3c16cea3ca"
+"checksum crossbeam-epoch 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5064ebdbf05ce3cb95e45c8b086f72263f4166b29b97f6baff7ef7fe047b55ac"
+"checksum crossbeam-queue 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "dfd6515864a82d2f877b42813d4553292c6659498c9a2aa31bab5a15243c2700"
+"checksum crossbeam-utils 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ce446db02cdc3165b94ae73111e570793400d0794e46125cc4056c81cbb039f4"
+"checksum derivative 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "942ca430eef7a3806595a6737bc388bf51adb888d3fc0dd1b50f1c170167ee3a"
+"checksum derive_more 0.99.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2159be042979966de68315bce7034bb000c775f22e3e834e1c52ff78f041cae8"
+"checksum either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "bb1f6b1ce1c140482ea30ddd3335fc0024ac7ee112895426e0a629a6c20adfe3"
+"checksum heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205"
+"checksum hermit-abi 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "f629dc602392d3ec14bfc8a09b5e644d7ffd725102b48b81e59f90f2633621d7"
+"checksum im 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a1f9b6540e530defef7f2df4ed330d45b739b10450548c74a9913f63ea1acc6b"
+"checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
+"checksum libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)" = "d515b1f41455adea1313a4a2ac8a8a477634fbae63cc6100e3aebb207ce61558"
+"checksum memoffset 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "75189eb85871ea5c2e2c15abbdd541185f63b408415e5051f5cac122d8c774b9"
+"checksum num 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cf4825417e1e1406b3782a8ce92f4d53f26ec055e3622e1881ca8e9f5f9e08db"
+"checksum num-bigint 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "f9c3f34cdd24f334cb265d9bf8bfa8a241920d026916785747a92f0e55541a1a"
+"checksum num-complex 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "fcb0cf31fb3ff77e6d2a6ebd6800df7fdcd106f2ad89113c9130bcd07f93dffc"
+"checksum num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)" = "b85e541ef8255f6cf42bbfe4ef361305c6c135d10919ecc26126c4e5ae94bc09"
+"checksum num-iter 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)" = "76bd5272412d173d6bf9afdf98db8612bbabc9a7a830b7bfc9c188911716132e"
+"checksum num-rational 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f2885278d5fe2adc2f75ced642d52d879bffaceb5a2e0b1d4309ffdfb239b454"
+"checksum num-traits 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "d4c81ffc11c212fa327657cb19dd85eb7419e163b5b076bede2bdb5c974c07e4"
+"checksum num_cpus 1.11.1 (registry+https://github.com/rust-lang/crates.io-index)" = "76dac5ed2a876980778b8b85f75a71b6cbf0db0b1232ee12f826bccb00d09d72"
+"checksum once_cell 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "891f486f630e5c5a4916c7e16c4b24a53e78c860b646e9f8e005e4f16847bfed"
+"checksum proc-macro-error 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "aeccfe4d5d8ea175d5f0e4a2ad0637e0f4121d63bd99d356fb1f39ab2e7c6097"
+"checksum proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759"
+"checksum proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "9c9e470a8dc4aeae2dee2f335e8f533e2d4b347e1434e5671afc49b054592f27"
+"checksum quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)" = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1"
+"checksum quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe"
+"checksum rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19"
+"checksum rand_xoshiro 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a9fcdd2e881d02f1d9390ae47ad8e5696a9e4be7b547a1da2afbc61973217004"
+"checksum rayon 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "db6ce3297f9c85e16621bb8cca38a06779ffc31bb8184e1be4bed2be4678a098"
+"checksum rayon-core 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "08a89b46efaf957e52b18062fb2f4660f8b8a4dde1807ca002690868ef2c85a9"
+"checksum rpds 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1196a0a2f52d343bd32179834273eaac7d8739f7e3f8b700227d2fa06b9a423b"
+"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
+"checksum scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b42e15e59b18a828bbf5c58ea01debb36b9b096346de35d941dcb89009f24a0d"
+"checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
+"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
+"checksum sized-chunks 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "62db64dd92b3b54314b1e216c274634ca2b3fe8da8b3873be670cb1ac4dad30f"
+"checksum static_assertions 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "7f3eb36b47e512f8f1c9e3d10c2c1965bc992bd9cdb024fa581e2194501c83d3"
+"checksum strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
+"checksum structopt 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "30b3a3e93f5ad553c38b3301c8a0a0cec829a36783f6a0c467fc4bf553a5f5bf"
+"checksum structopt-derive 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "ea692d40005b3ceba90a9fe7a78fa8d4b82b0ce627eebbffc329aab850f3410e"
+"checksum syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)" = "9ca4b3b69a77cbe1ffc9e198781b7acb0c7365a883670e8f1c1bc66fba79a5c5"
+"checksum syn 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)" = "dff0acdb207ae2fe6d5976617f887eb1e35a2ba52c13c7234c790960cdad9238"
+"checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
+"checksum typenum 1.11.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6d2783fe2d6b8c1101136184eb41be8b1ad379e4657050b8aaff0c79ee7575f9"
+"checksum unicode-segmentation 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e83e153d1053cbb5a118eeff7fd5be06ed99153f00dbcd8ae310c5fb2b22edc0"
+"checksum unicode-width 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7007dbd421b92cc6e28410fe7362e2e0a2503394908f417b68ec8d1c364c4e20"
+"checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc"
+"checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c"
+"checksum vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a"
+"checksum version_check 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "078775d0255232fb988e6fccf26ddc9d1ac274299aaedcedce21c6f72cc533ce"
+"checksum winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6"
+"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
+"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
diff --git a/2019/Cargo.toml b/2019/Cargo.toml
new file mode 100644
index 0000000..c5937b0
--- /dev/null
+++ b/2019/Cargo.toml
@@ -0,0 +1,19 @@
+[package]
+name = "aoc2019"
+version = "0.1.0"
+authors = ["Justin Wernick <justin@worthe-it.co.za>"]
+edition = "2018"
+
+[dependencies]
+structopt = "0.3.5"
+derive_more = "0.99.2"
+derivative = "1.0.3"
+im = "14.0.0"
+rpds = "0.7.0"
+archery = "0.3.0"
+num = "0.2"
+rayon = "1.3.0"
+cached = "0.11.0"
+
+[profile.release]
+debug = true
diff --git a/2019/inputs/day_1.txt b/2019/inputs/day_1.txt
new file mode 100644
index 0000000..5c720ed
--- /dev/null
+++ b/2019/inputs/day_1.txt
@@ -0,0 +1,100 @@
+66690
+86239
+75191
+140364
+95979
+106923
+95229
+123571
+84764
+89444
+98107
+89062
+109369
+146067
+124760
+76900
+139198
+111441
+74046
+84920
+54397
+143807
+121654
+93863
+73909
+104121
+58485
+119084
+126227
+142078
+79820
+132617
+108430
+98032
+107434
+127307
+105619
+57741
+53468
+63301
+137970
+136780
+80897
+133205
+79159
+89124
+94477
+56714
+143704
+122097
+117335
+108246
+75507
+101459
+101162
+146197
+121884
+66217
+57074
+142903
+140951
+64883
+124556
+67382
+142407
+121778
+57933
+94599
+87426
+143758
+64043
+65678
+90137
+61090
+77315
+102383
+146607
+139290
+85394
+149787
+125611
+106405
+91561
+135739
+54845
+68782
+111175
+61011
+125658
+70751
+85607
+75458
+75419
+124311
+66022
+122784
+129018
+54901
+73788
+108240
diff --git a/2019/inputs/day_10.txt b/2019/inputs/day_10.txt
new file mode 100644
index 0000000..51520ab
--- /dev/null
+++ b/2019/inputs/day_10.txt
@@ -0,0 +1,24 @@
+.###.#...#.#.##.#.####..
+.#....#####...#.######..
+#.#.###.###.#.....#.####
+##.###..##..####.#.####.
+###########.#######.##.#
+##########.#########.##.
+.#.##.########.##...###.
+###.#.##.#####.#.###.###
+##.#####.##..###.#.##.#.
+.#.#.#####.####.#..#####
+.###.#####.#..#..##.#.##
+########.##.#...########
+.####..##..#.###.###.#.#
+....######.##.#.######.#
+###.####.######.#....###
+############.#.#.##.####
+##...##..####.####.#..##
+.###.#########.###..#.##
+#.##.#.#...##...#####..#
+##.#..###############.##
+##.###.#####.##.######..
+##.#####.#.#.##..#######
+...#######.######...####
+#....#.#.#.####.#.#.#.##
diff --git a/2019/inputs/day_11.txt b/2019/inputs/day_11.txt
new file mode 100644
index 0000000..d6581e1
--- /dev/null
+++ b/2019/inputs/day_11.txt
@@ -0,0 +1 @@
+3,8,1005,8,320,1106,0,11,0,0,0,104,1,104,0,3,8,1002,8,-1,10,101,1,10,10,4,10,1008,8,1,10,4,10,102,1,8,29,2,1005,1,10,1006,0,11,3,8,1002,8,-1,10,101,1,10,10,4,10,108,0,8,10,4,10,102,1,8,57,1,8,15,10,1006,0,79,1,6,3,10,3,8,102,-1,8,10,101,1,10,10,4,10,108,0,8,10,4,10,101,0,8,90,2,103,18,10,1006,0,3,2,105,14,10,3,8,102,-1,8,10,1001,10,1,10,4,10,108,0,8,10,4,10,101,0,8,123,2,9,2,10,3,8,102,-1,8,10,1001,10,1,10,4,10,1008,8,1,10,4,10,1001,8,0,150,1,2,2,10,2,1009,6,10,1,1006,12,10,1006,0,81,3,8,102,-1,8,10,1001,10,1,10,4,10,1008,8,1,10,4,10,102,1,8,187,3,8,102,-1,8,10,1001,10,1,10,4,10,1008,8,0,10,4,10,101,0,8,209,3,8,1002,8,-1,10,1001,10,1,10,4,10,1008,8,1,10,4,10,101,0,8,231,1,1008,11,10,1,1001,4,10,2,1104,18,10,3,8,102,-1,8,10,1001,10,1,10,4,10,108,1,8,10,4,10,1001,8,0,264,1,8,14,10,1006,0,36,3,8,1002,8,-1,10,1001,10,1,10,4,10,108,0,8,10,4,10,101,0,8,293,1006,0,80,1006,0,68,101,1,9,9,1007,9,960,10,1005,10,15,99,109,642,104,0,104,1,21102,1,846914232732,1,21102,1,337,0,1105,1,441,21102,1,387512115980,1,21101,348,0,0,1106,0,441,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,21102,209533824219,1,1,21102,1,395,0,1106,0,441,21101,0,21477985303,1,21102,406,1,0,1106,0,441,3,10,104,0,104,0,3,10,104,0,104,0,21101,868494234468,0,1,21101,429,0,0,1106,0,441,21102,838429471080,1,1,21102,1,440,0,1106,0,441,99,109,2,21201,-1,0,1,21101,0,40,2,21102,472,1,3,21101,0,462,0,1106,0,505,109,-2,2106,0,0,0,1,0,0,1,109,2,3,10,204,-1,1001,467,468,483,4,0,1001,467,1,467,108,4,467,10,1006,10,499,1102,1,0,467,109,-2,2106,0,0,0,109,4,2101,0,-1,504,1207,-3,0,10,1006,10,522,21101,0,0,-3,21202,-3,1,1,22101,0,-2,2,21102,1,1,3,21102,541,1,0,1106,0,546,109,-4,2105,1,0,109,5,1207,-3,1,10,1006,10,569,2207,-4,-2,10,1006,10,569,22102,1,-4,-4,1105,1,637,22102,1,-4,1,21201,-3,-1,2,21202,-2,2,3,21102,588,1,0,1105,1,546,22101,0,1,-4,21102,1,1,-1,2207,-4,-2,10,1006,10,607,21101,0,0,-1,22202,-2,-1,-2,2107,0,-3,10,1006,10,629,21201,-1,0,1,21102,629,1,0,105,1,504,21202,-2,-1,-2,22201,-4,-2,-4,109,-5,2105,1,0
diff --git a/2019/inputs/day_12.txt b/2019/inputs/day_12.txt
new file mode 100644
index 0000000..7e72a58
--- /dev/null
+++ b/2019/inputs/day_12.txt
@@ -0,0 +1,4 @@
+<x=14, y=2, z=8>
+<x=7, y=4, z=10>
+<x=1, y=17, z=16>
+<x=-4, y=-1, z=1>
diff --git a/2019/inputs/day_13.txt b/2019/inputs/day_13.txt
new file mode 100644
index 0000000..c600ec1
--- /dev/null
+++ b/2019/inputs/day_13.txt
@@ -0,0 +1 @@
+1,380,379,385,1008,2689,888873,381,1005,381,12,99,109,2690,1102,0,1,383,1101,0,0,382,21001,382,0,1,20102,1,383,2,21101,0,37,0,1105,1,578,4,382,4,383,204,1,1001,382,1,382,1007,382,41,381,1005,381,22,1001,383,1,383,1007,383,25,381,1005,381,18,1006,385,69,99,104,-1,104,0,4,386,3,384,1007,384,0,381,1005,381,94,107,0,384,381,1005,381,108,1105,1,161,107,1,392,381,1006,381,161,1101,-1,0,384,1106,0,119,1007,392,39,381,1006,381,161,1102,1,1,384,20101,0,392,1,21101,23,0,2,21102,0,1,3,21102,138,1,0,1105,1,549,1,392,384,392,21001,392,0,1,21101,23,0,2,21101,3,0,3,21102,1,161,0,1105,1,549,1101,0,0,384,20001,388,390,1,20101,0,389,2,21101,0,180,0,1106,0,578,1206,1,213,1208,1,2,381,1006,381,205,20001,388,390,1,20101,0,389,2,21101,205,0,0,1105,1,393,1002,390,-1,390,1102,1,1,384,21001,388,0,1,20001,389,391,2,21101,228,0,0,1105,1,578,1206,1,261,1208,1,2,381,1006,381,253,20101,0,388,1,20001,389,391,2,21101,253,0,0,1106,0,393,1002,391,-1,391,1101,0,1,384,1005,384,161,20001,388,390,1,20001,389,391,2,21101,279,0,0,1106,0,578,1206,1,316,1208,1,2,381,1006,381,304,20001,388,390,1,20001,389,391,2,21101,0,304,0,1106,0,393,1002,390,-1,390,1002,391,-1,391,1101,0,1,384,1005,384,161,20102,1,388,1,20101,0,389,2,21101,0,0,3,21101,0,338,0,1106,0,549,1,388,390,388,1,389,391,389,21001,388,0,1,21002,389,1,2,21102,4,1,3,21101,0,365,0,1105,1,549,1007,389,24,381,1005,381,75,104,-1,104,0,104,0,99,0,1,0,0,0,0,0,0,230,18,20,1,1,20,109,3,21201,-2,0,1,22101,0,-1,2,21101,0,0,3,21102,1,414,0,1106,0,549,22102,1,-2,1,22102,1,-1,2,21101,0,429,0,1105,1,601,2102,1,1,435,1,386,0,386,104,-1,104,0,4,386,1001,387,-1,387,1005,387,451,99,109,-3,2106,0,0,109,8,22202,-7,-6,-3,22201,-3,-5,-3,21202,-4,64,-2,2207,-3,-2,381,1005,381,492,21202,-2,-1,-1,22201,-3,-1,-3,2207,-3,-2,381,1006,381,481,21202,-4,8,-2,2207,-3,-2,381,1005,381,518,21202,-2,-1,-1,22201,-3,-1,-3,2207,-3,-2,381,1006,381,507,2207,-3,-4,381,1005,381,540,21202,-4,-1,-1,22201,-3,-1,-3,2207,-3,-4,381,1006,381,529,22102,1,-3,-7,109,-8,2106,0,0,109,4,1202,-2,41,566,201,-3,566,566,101,639,566,566,2101,0,-1,0,204,-3,204,-2,204,-1,109,-4,2105,1,0,109,3,1202,-1,41,594,201,-2,594,594,101,639,594,594,20102,1,0,-2,109,-3,2106,0,0,109,3,22102,25,-2,1,22201,1,-1,1,21101,0,521,2,21102,1,1011,3,21102,1,1025,4,21102,630,1,0,1106,0,456,21201,1,1664,-2,109,-3,2105,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,2,2,0,2,0,2,0,2,0,0,2,2,0,2,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,2,0,0,2,0,1,1,0,0,0,0,2,0,0,2,0,2,2,2,2,0,2,0,0,0,2,2,0,0,2,2,2,2,0,0,0,0,0,2,0,0,0,0,2,2,0,1,1,0,0,0,0,0,2,0,0,0,2,0,0,0,0,0,0,2,2,0,2,0,0,0,0,2,0,0,0,0,2,0,0,0,0,2,2,2,0,0,1,1,0,0,2,2,2,0,0,0,2,0,0,0,0,0,2,2,0,0,2,0,2,0,0,0,2,2,0,0,0,2,0,0,0,2,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,2,0,0,0,2,0,0,0,0,2,0,0,2,0,0,0,0,2,0,0,2,0,2,0,2,0,2,0,0,1,1,0,0,0,0,0,2,2,0,0,2,2,0,0,0,0,2,0,0,2,2,0,0,0,2,2,0,0,2,0,0,0,2,2,2,2,2,0,2,0,1,1,0,0,0,0,2,0,2,0,0,2,0,0,0,0,0,0,2,0,0,2,0,2,2,2,0,2,2,2,0,0,0,0,0,2,0,0,2,0,0,1,1,0,2,0,0,2,0,0,0,0,2,0,0,0,0,2,2,0,2,0,0,0,0,2,0,0,0,0,0,2,0,2,0,0,2,0,0,2,0,0,1,1,0,2,2,2,0,0,0,0,2,2,2,2,2,2,0,0,0,0,0,0,0,2,0,0,2,0,2,0,2,2,0,2,2,0,2,0,2,0,0,1,1,0,0,2,0,0,2,0,2,0,0,2,0,0,2,0,0,0,2,0,0,0,0,2,0,0,2,0,0,2,2,0,2,0,0,0,0,2,2,0,1,1,0,0,2,2,0,0,2,2,0,2,2,0,0,0,0,0,2,0,0,0,0,2,2,2,0,0,2,0,2,0,2,2,0,0,2,0,2,0,0,1,1,0,0,2,2,2,0,0,2,2,0,2,2,2,0,0,0,2,2,2,0,2,0,0,0,0,0,2,0,0,2,0,2,0,0,0,0,0,0,0,1,1,0,2,0,0,0,2,2,0,2,0,0,2,0,2,2,2,0,0,2,2,0,2,0,0,0,0,0,0,2,2,0,2,2,0,2,0,0,2,0,1,1,0,0,2,0,0,2,2,0,0,0,0,0,2,2,0,2,2,2,0,2,0,2,2,2,0,0,2,0,2,2,2,0,0,0,0,0,0,2,0,1,1,0,2,0,2,0,2,2,2,2,0,0,0,2,0,0,0,2,2,0,0,0,0,2,0,2,2,0,0,0,0,2,0,2,0,0,2,0,0,0,1,1,0,0,0,0,2,0,0,2,0,0,2,2,0,2,0,0,0,2,0,0,0,0,0,0,2,0,0,2,0,0,0,0,0,0,0,0,0,2,0,1,1,0,2,0,0,0,2,0,0,0,2,2,0,2,0,0,2,0,0,2,2,0,2,0,0,2,0,0,0,0,0,0,0,0,2,0,0,2,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,34,58,37,19,14,62,51,10,28,52,86,20,39,30,61,36,77,73,19,11,17,74,7,54,40,59,20,92,18,13,85,72,83,58,18,68,10,22,94,22,25,40,67,96,55,96,42,16,80,80,96,35,19,79,81,63,91,5,72,68,80,93,79,36,91,47,71,82,45,29,51,36,10,62,57,29,17,16,4,88,75,81,70,77,32,2,38,37,35,86,41,35,61,71,72,22,14,33,12,10,10,56,30,3,90,71,24,62,69,31,47,2,18,77,43,20,64,85,50,43,43,73,16,23,98,4,23,53,82,15,88,1,39,78,43,57,65,8,45,79,17,44,32,76,31,3,25,71,45,16,42,61,89,21,93,4,98,66,68,5,13,19,48,65,29,5,24,59,29,49,57,39,21,96,10,8,25,82,17,42,46,49,83,4,81,32,14,7,76,62,31,74,55,19,39,63,89,41,38,28,34,34,88,7,77,43,87,10,47,85,39,31,88,69,40,72,51,49,64,46,64,14,66,95,95,58,38,88,82,35,6,58,3,21,33,58,9,95,43,52,13,22,22,10,11,47,35,33,31,58,93,83,13,14,55,71,88,42,73,83,91,84,62,78,80,15,26,50,8,15,6,91,89,3,12,53,47,47,82,67,12,77,6,63,88,94,53,19,97,36,34,59,91,27,37,45,44,31,8,58,16,7,74,76,83,17,28,42,85,19,1,61,73,84,37,15,43,52,80,48,51,98,70,77,28,55,78,85,64,32,22,82,69,7,82,55,78,24,5,89,55,4,34,28,71,76,81,90,96,2,2,77,41,32,24,60,10,11,26,64,66,19,11,77,11,82,81,1,52,2,79,43,47,87,63,73,3,81,69,66,53,4,83,88,13,5,62,94,55,58,4,93,96,58,40,69,64,56,80,71,85,44,45,24,80,59,53,15,85,92,89,95,69,77,53,27,72,3,54,49,9,35,10,85,43,86,9,42,69,29,64,96,17,72,47,24,2,13,40,45,62,19,41,85,28,68,73,20,52,56,19,57,1,36,64,18,26,41,94,81,45,35,29,32,28,87,86,53,71,54,67,68,47,53,17,40,61,58,74,2,51,43,23,62,54,13,80,67,88,94,1,62,85,7,12,87,51,4,69,25,57,6,79,94,15,75,93,46,19,28,84,72,84,59,60,59,59,14,11,30,57,53,75,83,72,61,65,50,26,49,23,40,82,11,67,8,55,13,22,41,32,33,89,37,69,11,24,24,8,21,89,11,46,89,88,59,3,7,43,85,74,92,72,60,85,82,33,82,71,14,21,41,4,78,88,4,22,81,30,92,17,9,62,69,84,47,6,86,49,94,11,96,21,1,5,1,45,19,60,59,17,85,67,42,21,11,79,39,27,72,54,19,69,50,52,78,78,6,16,96,86,37,58,79,9,45,10,73,29,53,75,63,50,66,6,69,8,74,68,88,9,88,87,50,34,45,12,43,43,58,14,29,32,77,77,97,45,29,41,94,21,91,52,22,74,44,48,11,20,68,9,51,7,85,93,74,59,16,34,60,12,3,18,17,4,71,44,49,79,68,54,96,74,21,74,60,59,16,77,65,97,84,54,52,37,95,9,3,41,9,72,82,82,95,31,71,56,50,59,93,57,79,16,9,74,72,47,1,9,5,55,63,64,80,40,93,54,11,57,26,76,19,85,41,80,90,92,27,61,24,83,93,96,95,28,68,80,11,60,65,36,2,46,75,59,52,11,36,74,62,52,6,23,85,93,61,36,26,70,2,13,97,52,92,96,87,63,63,31,2,50,25,34,79,46,4,48,51,74,96,74,7,43,82,84,50,59,53,13,51,8,81,36,93,10,31,10,50,76,69,33,3,71,1,1,65,68,57,69,15,64,81,59,38,38,89,79,80,52,44,59,26,96,21,38,38,79,2,96,2,92,73,49,14,71,74,66,94,98,63,28,59,26,30,67,1,61,84,92,47,24,27,41,57,95,89,6,96,48,43,7,82,42,5,27,15,32,89,53,3,35,63,84,97,92,77,50,38,73,10,50,89,95,96,77,61,51,90,22,75,41,77,1,14,72,68,91,10,80,28,25,10,86,54,10,87,55,40,79,16,35,8,82,51,70,84,12,72,74,4,88,71,69,83,9,55,10,57,9,3,40,74,72,61,75,64,54,32,61,26,53,48,45,22,6,83,21,21,9,4,7,65,98,78,17,54,35,95,79,36,53,59,84,53,14,20,94,12,31,54,86,39,95,82,38,8,22,58,50,27,32,53,79,49,71,76,18,64,75,64,88,58,88,27,62,31,54,11,59,11,3,42,66,85,41,888873
diff --git a/2019/inputs/day_14.txt b/2019/inputs/day_14.txt
new file mode 100644
index 0000000..dac9757
--- /dev/null
+++ b/2019/inputs/day_14.txt
@@ -0,0 +1,59 @@
+2 RWPCH => 9 PVTL
+1 FHFH => 4 BLPJK
+146 ORE => 5 VJNBT
+8 KDFNZ, 1 ZJGH, 1 GSCG => 5 LKPQG
+11 NWDZ, 2 WBQR, 1 VRQR => 2 BMJR
+3 GSCG => 4 KQDVM
+5 QVNKN, 6 RPWKC => 3 BCNV
+10 QMBM, 4 RBXB, 2 VRQR => 1 JHXBM
+15 RPWKC => 6 MGCQ
+1 QWKRZ => 4 FHFH
+10 RWPCH => 6 MZKG
+11 JFKGV, 5 QVNKN, 1 CTVK => 4 VQDT
+1 SXKT => 5 RPWKC
+1 VQDT, 25 ZVMCB => 2 RBXB
+6 LGLNV, 4 XSNKB => 3 WBQR
+199 ORE => 2 SXKT
+1 XSNKB, 6 CWBNX, 1 HPKB, 5 PVTL, 1 JNKH, 9 SXKT, 3 KQDVM => 3 ZKTX
+7 FDSX => 6 WJDF
+7 JLRM => 4 CWBNX
+167 ORE => 5 PQZXH
+13 JHXBM, 2 NWDZ, 4 RFLX, 12 VRQR, 10 FJRFG, 14 PVTL, 2 JLRM => 6 DGFG
+12 HPKB, 3 WHVXC => 9 ZJGH
+1 JLRM, 2 ZJGH, 2 QVNKN => 9 FJRFG
+129 ORE => 7 KZFPJ
+2 QMBM => 1 RWPCH
+7 VJMWM => 4 JHDW
+7 PQZXH, 7 SXKT => 9 BJVQM
+1 VJMWM, 4 JHDW, 1 MQXF => 7 FDSX
+1 RPWKC => 7 WHVXC
+1 ZJGH => 1 ZVMCB
+1 RWPCH => 3 MPKR
+187 ORE => 8 VJMWM
+15 CTVK => 5 GSCG
+2 XSNKB, 15 ZVMCB, 3 KDFNZ => 2 RFLX
+18 QVNKN => 8 XLFZJ
+4 CWBNX => 8 ZSCX
+2 ZJGH, 1 JLRM, 1 MGCQ => 9 NPRST
+13 BJVQM, 2 BCNV => 2 QWKRZ
+2 QWKRZ, 2 BLPJK, 5 XSNKB => 2 VRQR
+13 HPKB, 3 VQDT => 9 JLRM
+2 SXKT, 1 VJNBT, 5 VLWQB => 6 CTVK
+2 MPKR, 2 LMNCH, 24 VRQR => 8 DZFNW
+2 VQDT => 1 KDFNZ
+1 CTVK, 6 FDSX => 6 QVNKN
+3 CTVK, 1 QVNKN => 4 HPKB
+3 NPRST, 1 KGSDJ, 1 CTVK => 2 QMBM
+4 KZFPJ, 1 PQZXH => 5 VLWQB
+2 VQDT => 7 KGSDJ
+3 MPKR => 2 JNKH
+1 KQDVM => 5 XQBS
+3 ZKGMX, 1 XQBS, 11 MZKG, 11 NPRST, 1 DZFNW, 5 VQDT, 2 FHFH => 6 JQNF
+2 FJRFG, 17 BMJR, 3 BJVQM, 55 JQNF, 8 DGFG, 13 ZJGH, 29 ZKTX => 1 FUEL
+27 KZFPJ, 5 VJNBT => 5 MQXF
+11 FDSX, 1 WHVXC, 1 WJDF => 4 ZKGMX
+1 ZVMCB => 4 NWDZ
+1 XLFZJ => 6 LGLNV
+13 ZSCX, 4 XLFZJ => 8 LMNCH
+1 RPWKC, 1 FDSX, 2 BJVQM => 8 JFKGV
+1 WJDF, 1 LKPQG => 4 XSNKB
diff --git a/2019/inputs/day_15.txt b/2019/inputs/day_15.txt
new file mode 100644
index 0000000..ca5836c
--- /dev/null
+++ b/2019/inputs/day_15.txt
@@ -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,1002,1034,1,1039,102,1,1036,1041,1001,1035,-1,1040,1008,1038,0,1043,102,-1,1043,1032,1,1037,1032,1042,1106,0,124,1002,1034,1,1039,1001,1036,0,1041,1001,1035,1,1040,1008,1038,0,1043,1,1037,1038,1042,1105,1,124,1001,1034,-1,1039,1008,1036,0,1041,1001,1035,0,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,1,1032,1006,1032,165,1008,1040,9,1032,1006,1032,165,1102,1,2,1044,1105,1,224,2,1041,1043,1032,1006,1032,179,1102,1,1,1044,1106,0,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,35,1044,1106,0,224,1101,0,0,1044,1105,1,224,1006,1044,247,102,1,1039,1034,1002,1040,1,1035,1002,1041,1,1036,102,1,1043,1038,101,0,1042,1037,4,1044,1105,1,0,1,5,41,19,22,1,39,81,29,20,15,82,33,18,45,30,32,55,28,26,70,13,56,32,28,18,3,59,90,11,95,15,85,8,61,25,59,24,34,1,85,5,25,54,57,18,20,54,80,91,28,65,36,12,44,36,13,92,24,56,13,39,69,29,79,10,41,27,23,25,72,20,3,61,15,51,11,12,12,48,10,45,13,29,49,90,30,17,9,41,21,18,7,30,48,17,83,71,4,10,31,10,96,81,77,9,50,39,21,36,33,72,12,3,23,79,18,4,75,17,58,64,8,7,97,60,72,72,1,94,55,42,2,94,2,21,88,19,82,57,96,19,25,27,41,62,15,40,23,61,86,27,73,61,13,46,52,81,12,34,23,73,23,59,1,30,47,9,99,10,37,17,28,98,5,92,73,8,63,4,86,76,79,7,30,68,28,91,12,12,98,74,4,22,44,10,23,45,37,16,90,76,23,74,75,12,21,38,14,15,76,28,49,71,7,6,6,71,53,33,12,87,15,92,66,21,38,13,53,92,34,49,25,6,67,21,27,89,24,61,25,30,41,30,99,28,19,41,90,51,74,14,33,54,48,10,14,42,2,67,76,10,21,2,67,43,27,69,11,16,78,7,36,9,24,48,63,81,53,29,94,34,25,99,66,47,17,97,33,52,11,62,22,52,30,23,89,95,15,13,50,48,26,10,6,69,78,13,6,94,1,28,67,10,70,16,50,19,24,15,79,50,27,3,19,62,4,31,83,20,17,83,67,5,80,26,36,62,87,3,10,80,22,65,60,10,78,4,20,60,30,11,7,83,10,13,72,81,37,22,14,55,63,51,27,32,77,52,20,50,16,48,2,55,10,53,26,84,6,87,43,37,26,3,85,62,25,78,50,16,10,37,22,54,5,80,24,7,32,49,18,27,12,41,70,82,20,34,91,15,98,77,22,6,79,3,8,54,17,32,4,44,2,97,14,15,65,30,97,14,79,75,11,77,5,61,37,20,91,20,45,74,19,40,2,41,89,12,34,44,18,62,57,17,68,22,96,7,59,63,2,60,70,2,26,75,26,3,53,19,80,16,97,7,34,58,52,66,24,75,25,30,75,42,13,12,89,13,3,84,92,1,75,30,54,43,2,56,15,1,15,84,99,6,98,42,17,29,1,18,26,70,71,29,91,23,21,87,66,18,38,32,18,81,65,2,58,99,12,4,84,24,32,88,30,67,49,29,59,64,18,70,10,24,56,5,27,97,50,4,28,85,65,16,67,83,15,16,61,18,86,8,36,25,36,29,97,45,19,81,41,29,45,30,69,26,57,93,27,72,34,30,99,61,2,48,16,12,76,98,28,14,32,32,90,48,10,30,57,23,39,2,8,39,33,13,88,34,31,74,15,60,8,47,60,31,5,79,1,98,86,33,3,99,33,62,11,96,25,22,38,98,84,3,56,70,49,3,8,56,87,4,29,59,65,26,34,77,7,14,78,26,25,70,49,3,31,45,92,24,95,17,4,9,4,96,64,92,27,67,4,99,6,44,7,16,86,2,75,1,6,68,81,4,1,44,49,7,92,8,40,36,25,81,13,56,99,10,2,30,72,6,43,30,12,43,93,19,20,23,95,10,19,66,63,28,96,40,50,8,15,56,38,13,93,42,71,12,18,87,8,4,21,85,9,2,66,77,10,80,26,61,9,43,20,88,10,39,67,55,31,49,17,58,26,80,20,84,54,49,5,73,11,52,15,63,7,62,24,57,92,61,25,87,56,37,31,38,14,99,0,0,21,21,1,10,1,0,0,0,0,0,0
diff --git a/2019/inputs/day_16.txt b/2019/inputs/day_16.txt
new file mode 100644
index 0000000..357965c
--- /dev/null
+++ b/2019/inputs/day_16.txt
@@ -0,0 +1 @@
+59723517898690342336085619027921111260000667417052529433894092649779685557557996383085708903241535436786723718804155370155263736632861535632645335233170435646844328735934063129720822438983948765830873108060969395372667944081201020154126736565212455403582565814037568332106043336657972906297306993727714730061029321153984390658949013821918352341503629705587666779681013358053312990709423156110291835794179056432958537796855287734217125615700199928915524410743382078079059706420865085147514027374485354815106354367548002650415494525590292210440827027951624280115914909910917047084328588833201558964370296841789611989343040407348115608623432403085634084
diff --git a/2019/inputs/day_17.txt b/2019/inputs/day_17.txt
new file mode 100644
index 0000000..49131d4
--- /dev/null
+++ b/2019/inputs/day_17.txt
@@ -0,0 +1 @@
+1,330,331,332,109,3974,1102,1182,1,15,1101,1475,0,24,1001,0,0,570,1006,570,36,101,0,571,0,1001,570,-1,570,1001,24,1,24,1106,0,18,1008,571,0,571,1001,15,1,15,1008,15,1475,570,1006,570,14,21102,1,58,0,1105,1,786,1006,332,62,99,21101,333,0,1,21102,73,1,0,1105,1,579,1102,0,1,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,1002,574,1,0,3,574,101,1,573,573,1008,574,10,570,1005,570,189,1008,574,44,570,1006,570,158,1105,1,81,21102,340,1,1,1105,1,177,21101,0,477,1,1106,0,177,21102,1,514,1,21101,0,176,0,1106,0,579,99,21102,184,1,0,1105,1,579,4,574,104,10,99,1007,573,22,570,1006,570,165,1002,572,1,1182,21101,0,375,1,21101,0,211,0,1105,1,579,21101,1182,11,1,21102,1,222,0,1106,0,979,21102,1,388,1,21102,1,233,0,1106,0,579,21101,1182,22,1,21101,0,244,0,1105,1,979,21101,0,401,1,21102,1,255,0,1106,0,579,21101,1182,33,1,21102,1,266,0,1106,0,979,21102,414,1,1,21102,277,1,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,1182,1,1,21102,1,313,0,1106,0,622,1005,575,327,1101,1,0,575,21101,327,0,0,1105,1,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,50,26,0,109,4,1201,-3,0,587,20102,1,0,-1,22101,1,-3,-3,21102,0,1,-2,2208,-2,-1,570,1005,570,617,2201,-3,-2,609,4,0,21201,-2,1,-2,1106,0,597,109,-4,2106,0,0,109,5,2101,0,-4,630,20101,0,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,21102,702,1,0,1106,0,786,21201,-1,-1,-1,1106,0,676,1001,578,1,578,1008,578,4,570,1006,570,724,1001,578,-4,578,21102,731,1,0,1105,1,786,1106,0,774,1001,578,-1,578,1008,578,-1,570,1006,570,749,1001,578,4,578,21101,756,0,0,1105,1,786,1106,0,774,21202,-1,-11,1,22101,1182,1,1,21102,774,1,0,1105,1,622,21201,-3,1,-3,1106,0,640,109,-5,2105,1,0,109,7,1005,575,802,20102,1,576,-6,20101,0,577,-5,1105,1,814,21101,0,0,-1,21101,0,0,-5,21101,0,0,-6,20208,-6,576,-2,208,-5,577,570,22002,570,-2,-2,21202,-5,51,-3,22201,-6,-3,-3,22101,1475,-3,-3,2102,1,-3,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,21102,1,35,-4,1106,0,924,1202,-3,1,878,1008,0,1,570,1006,570,916,1001,374,1,374,1201,-3,0,895,1101,0,2,0,2101,0,-3,902,1001,438,0,438,2202,-6,-5,570,1,570,374,570,1,570,438,438,1001,578,558,921,21002,0,1,-4,1006,575,959,204,-4,22101,1,-6,-6,1208,-6,51,570,1006,570,814,104,10,22101,1,-5,-5,1208,-5,49,570,1006,570,810,104,10,1206,-1,974,99,1206,-1,974,1102,1,1,575,21101,973,0,0,1105,1,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,1105,1,1041,21102,1,-4,-2,1106,0,1041,21101,0,-5,-2,21201,-4,1,-4,21207,-4,11,-1,1206,-1,1138,2201,-5,-4,1059,2102,1,-2,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,2102,1,-2,0,1106,0,1060,21208,-2,10,-1,1205,-1,1162,21208,-2,44,-1,1206,-1,1131,1106,0,989,21101,0,439,1,1105,1,1150,21101,477,0,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,2101,0,-5,1176,2102,1,-4,0,109,-6,2106,0,0,32,5,46,1,3,1,46,1,3,1,46,1,3,1,46,1,3,1,46,1,3,1,40,11,40,1,5,1,44,1,5,1,44,1,5,1,44,1,5,1,44,1,5,1,40,11,40,1,3,1,46,1,3,1,46,1,3,1,46,1,3,9,38,1,11,1,26,1,11,1,11,1,26,1,11,1,11,1,26,1,11,5,7,1,26,1,15,1,7,1,26,1,15,1,7,1,26,1,15,1,7,1,26,1,11,7,5,1,26,1,11,1,3,1,1,1,5,1,26,1,9,13,1,1,3,13,10,1,9,1,1,1,3,1,1,1,3,1,1,1,3,1,22,5,5,1,1,13,3,1,26,1,5,1,5,1,1,1,3,1,5,1,26,1,5,1,5,7,5,1,26,1,5,1,7,1,9,1,26,1,5,1,7,1,9,1,26,1,5,1,7,1,9,1,26,1,5,1,7,11,26,1,5,1,34,11,5,1,34,1,15,1,34,1,5,9,1,9,26,1,5,1,7,1,9,1,26,1,5,1,7,1,9,1,26,1,5,1,7,1,9,1,22,11,7,1,9,1,22,1,3,1,13,1,9,1,22,1,3,1,13,1,9,1,22,1,3,1,13,1,9,1,22,1,3,1,13,1,9,1,22,1,3,1,13,1,9,1,22,5,13,11,22
diff --git a/2019/inputs/day_18.txt b/2019/inputs/day_18.txt
new file mode 100644
index 0000000..3cb4307
--- /dev/null
+++ b/2019/inputs/day_18.txt
@@ -0,0 +1,81 @@
+#################################################################################
+#.............#.....#.................#.#.....#...#.......#...................#a#
+#.#####.#######.#.###.#########.#####.#.#.###Y###.#.#####.#.#####.###########.#.#
+#.#...#.#.....#.#..c#.........#...#.#...#...#.#...#.#.#...#.#.#...#...#...#.....#
+#.#.###.#.###.#.###.#.###########.#.###.#.#.#.#.#.#.#.#.#.#.#.#.###.#.#.#.#######
+#.#...#...#.#...#.#...#...........#.#...#.#.#...#.#.#.#.#.#.#.#...#.#.#.#.#.....#
+#.#.#.#####.#####.#####.###.#######.#.###.#.#######.#.#.###.#.###.#.#.#.#.#.###.#
+#.#.#.............#.#...#.#.#..e..#.....#.#...........#...#.#...#...#...#.....#.#
+#.#########.#####.#.#.###.#.#.###.#####.#.###############.#T#.#.###############.#
+#...#..k....#.....#.#.Z.#...#...#.....#.#.........#.#.....#.#.#.....#.L.....#...#
+###.#.#.#######.###.###.#######.#####.#.#########.#.#.###.#.#.###.#.###.###.#.###
+#...#.#.#.....#.#...#...#.....#.....#.#.#...#...#.#.#.#...#.#.#...#...#.#...#...#
+#.###.#.#.###.#.#.###.###.###.#####.#.#.#.#.#.#.#.#.#.###.#.###.#####.#.#.#####.#
+#.#...#.#.#...#.#...#.....#.#.....#.#.#.#.#...#...#.#...#.#.#...#.#...#.#.#.....#
+#.###.#.#.#.###.###.#######.#.#####.#.#.#.#########.###.###.#.###.#.###.#.#.###.#
+#...#.#.#.#...#...#.........#.#.....#.#.#.............#.......#...#.#...#.#...#.#
+###.#.###.###.###.###.#.#####.#.#####.###############.#########.#.#.###.#.###.#.#
+#.....#...#...#.J...#.#.#.....#.....#...#...........#.#...#...#.#.......#...#.#.#
+#######.###.#######.#.###.#####.#######.#########.#.#.###.#.#.#########.#####.#.#
+#.......#.#...#...#...#...#...#.#.......#.....O.#.#.#.#...#.#.......#...#.....#s#
+#.#######.###.#.#.#####.###.#.#.#.#######.#####.#.#.#.#.###.#####.#.#.###.#####.#
+#...#...#...#...#...#.#.#...#...#.......#.....#.#.#.#.#...#.#...#.#.#...#...#...#
+###.#.#.#.#########.#.#.#.#######.#####.#.#####.#.###.###.#.###.###.#.#####.#.###
+#.#...#.#.........#...#...#....d#.....#.#.#.....#.#...#...#.#.#...#.#.#.....#.#.#
+#.#####.#######.#######.###.###.#####.#.#.#.#####.#.###.#.#.#.###.#.#.#.#####.#.#
+#...#.#.......#.......#...#.#...#.....#.#.#.....#.......#.#.....#.#.#.#.#.......#
+#.#.#.#######.#.#.#####.###.#.#####.###.#.#####.#############.###.#.#.#.#######.#
+#.#...#.....#.#.#...#...#...#.....#...#.#.#...#.#...........#.#...#.#.#.#...#.#.#
+#.###.###.#.#.#.###.#.###.#######.#####.#.###.#.#.#########.#.#.###.#.#.#.#.#.#.#
+#...#.....#.#.#...#...#...#.......#.....#...#.#.#.....#...#...#...#.#.#...#.#...#
+#.#.#######.#.###.#####.###.#######.#######.#.#.#####.###.#######.#.#####.#.#.###
+#.#.#.....#.#.#.#.#.#...#.#.#...#...#...#...#.#.....#...#.....#...#.....#.#.#w#.#
+#.#.#.###.#.#.#.#.#.#.###.#.#.#.###.#.#.#.###.#.###.###.#.###.#.###.###.###.#.#.#
+#.#.#.#.#.#.#.#.#.#.#.#m..#...#...#...#.#.#...#...#...#.#...#.#.#.....#.#...#.#.#
+###.#.#.#.###W#.#.#.#.#.#########.#####.#.#.#.###.#####.###.#.#.#######.#.###.#.#
+#...#...#.#...#.....#.#.......#...#...#.#.#.#.#.#.....#.....#.#.........#.#.#...#
+#.###.###.#.###.#####.#.###.###.###.#.#.#.#.#.#.#####.#######.###########.#.###.#
+#.#...#...#.#...#.S...#...#.....#...#.#.#...#.....#.#.........#...#...#...#.....#
+#.#.###.###.#####.#######.#######.###.#.#########.#.###########.#.#.#.#.###.#####
+#.....#...........#.......F.......#..................f..........#...#...#.......#
+#######################################.@.#######################################
+#.....#.#...........#.....#.........................#...#.....#.M.......#.....#.#
+###P#.#.#.#######.###.###.#.#######.###.#.#########.#.#.#.###.###.#####.###.#.#.#
+#...#...#...#.#...#.....#.#.#.......#...#...#.........#...#.......#...#.....#.#.#
+#.#.#######.#.#.###.#####.#.#.#######.#####.###############.#########.#######.#.#
+#.#.#.....#.#.#.#...#...#.#.#.#.........#...#.......#...#.....#.....#.#.......#.#
+#.###.###.#.#.#.#.###.#.#.#.#.###########.###.#####.#.#.#######.###.#.#.#######.#
+#...#.#.#.#...#.#.#...#...#.#...........#...#...#.#...#.......#.#.#.#.#.........#
+#.#.#.#.#.#.###.#.#.#####.#######.#####.###.###.#.###########.#.#.#.#.#.#######.#
+#.#.#...#...#...#.#r#.....#.....#.....#.#...#.#.#.......#...#.....#.#...#.....#.#
+#.#.###.#####.###.#.#######.###.#####.#.#.#.#.#.###.#####.#.#######.#.###.###.#.#
+#.#...#.#...#...#.#.........#...#...#.#.#.#...#...#.#.....#.#......p#...#.#.#.#.#
+###.#.#.#.#.###.#.###########.###.#.#.#.#.###.###.#.#.#####.#.###.#######.#.#.###
+#...#.#.#.#...#.......#.....#.#...#...#.#...#.#...#.....#...#.#...#.K...#.#.#...#
+#.#####.#.###.#######.#.###Q#.#.#######.###.#.#.#####.###.###.#.###.###.#.#.###.#
+#.....#...#...#.#...#.#.#.#...#...#.....#...#.#.....#.#...#...#.#...#.#..j#.#...#
+#.###.#####.###.#.#.###.#.#########.###.#.#########.###.#.#.###.#.###.#####.#.###
+#...#.#.....#...#.#.B...#...#...#...#...#.#.......#.....#.#...#.#...........#.R.#
+#.###.#.#######.#.#######.#.#.#.#.###.###.#.#.###.#######.###.###.#############.#
+#.#...#.......#.#n....#...#.#.#...#...#.#...#...#.....#...#.#.....#..u..#.....#.#
+###.#.#######.#.#####.#.###.#.#####.###.#.#####.###.###.###.###.###.###.#.###.#.#
+#...#.#...#...#.....#.#.#...#...#.#...#.#...#...#...#...#...#.#.#...#...#.#...#.#
+#.#####.#.#.###.#.#####.#.###.#.#.###.#.#####.#######.#####.#.###.###.###.###.#.#
+#...#...#.#.#...#.......#.#...#.#...#...#.....#.......#.....#.U...#.#...#...#...#
+#.#.#.###.#.#.#########.#.#####.###.###.#.#.###.#######.###########.###X#.#.###.#
+#.#..l#...#.#...#.......#.....#...#...#.#.#o#...#.#.....#...#......x....#.#.#...#
+#.#####C###.#.###.###########.###.#.###.#.###.###.#.###.#.#.#I#############.#.###
+#.....#...#.#.#...#...#.....#.#...#.#...#.#...#.....#...#.#...#v......G.#...#..q#
+###.#####.#.###.###.#.#.###.#.#.###.#.###.#.###.#####.#.#.#####.#######.#.#####.#
+#.#y#...#.#...#.#...#.#...#.#...#...#...#.#.#...#.....#.#..i..#...#.....#...#...#
+#.#.#.#.#.###.#.#.###.#.#.#.#####.#.###.#.#.###.#.###########H#.#.#.#####.#.#.###
+#...#.#.#...#.#.....#.#.#.#.#...#.#.....#.#...#.#...........#.#.#.#g..#...#.#...#
+#.###.#.###A#.#######.#.#.#.#.###.#######.###.#.#########.#.#.#.#.###.#####.###.#
+#.#...#.....#.........#.#.#.#.#...#.....#...#.#.......#...#.#.#.#.#.#.#...#...#.#
+###.#####################.#.#.#.#####.###.#.#.#########.###.#.###.#.#.#.#.###.#.#
+#...#.......#.............#..t#.#...#...#.#.#.#.......#.#...#...#.#.#.N.#.....#.#
+#.###.#####.#.#########.#######.#.#D#.#.#.#.#.#.#####.#.#.#####.#.#.###########.#
+#.#...#...#..z#.#.......#.....#...#.#.#.#.#.#...#...#...#.#.#..h#.#.....#......b#
+#.#.###.#.#####.#.#######.###.#####.###.#.#.#####.#.#####.#.#.###.#.###.#.#######
+#.......#.......#...........#...........#.#.....E.#.........#...V.#...#.........#
+#################################################################################
diff --git a/2019/inputs/day_18_2.txt b/2019/inputs/day_18_2.txt
new file mode 100644
index 0000000..8fda759
--- /dev/null
+++ b/2019/inputs/day_18_2.txt
@@ -0,0 +1,81 @@
+#################################################################################
+#.............#.....#.................#.#.....#...#.......#...................#a#
+#.#####.#######.#.###.#########.#####.#.#.###Y###.#.#####.#.#####.###########.#.#
+#.#...#.#.....#.#..c#.........#...#.#...#...#.#...#.#.#...#.#.#...#...#...#.....#
+#.#.###.#.###.#.###.#.###########.#.###.#.#.#.#.#.#.#.#.#.#.#.#.###.#.#.#.#######
+#.#...#...#.#...#.#...#...........#.#...#.#.#...#.#.#.#.#.#.#.#...#.#.#.#.#.....#
+#.#.#.#####.#####.#####.###.#######.#.###.#.#######.#.#.###.#.###.#.#.#.#.#.###.#
+#.#.#.............#.#...#.#.#..e..#.....#.#...........#...#.#...#...#...#.....#.#
+#.#########.#####.#.#.###.#.#.###.#####.#.###############.#T#.#.###############.#
+#...#..k....#.....#.#.Z.#...#...#.....#.#.........#.#.....#.#.#.....#.L.....#...#
+###.#.#.#######.###.###.#######.#####.#.#########.#.#.###.#.#.###.#.###.###.#.###
+#...#.#.#.....#.#...#...#.....#.....#.#.#...#...#.#.#.#...#.#.#...#...#.#...#...#
+#.###.#.#.###.#.#.###.###.###.#####.#.#.#.#.#.#.#.#.#.###.#.###.#####.#.#.#####.#
+#.#...#.#.#...#.#...#.....#.#.....#.#.#.#.#...#...#.#...#.#.#...#.#...#.#.#.....#
+#.###.#.#.#.###.###.#######.#.#####.#.#.#.#########.###.###.#.###.#.###.#.#.###.#
+#...#.#.#.#...#...#.........#.#.....#.#.#.............#.......#...#.#...#.#...#.#
+###.#.###.###.###.###.#.#####.#.#####.###############.#########.#.#.###.#.###.#.#
+#.....#...#...#.J...#.#.#.....#.....#...#...........#.#...#...#.#.......#...#.#.#
+#######.###.#######.#.###.#####.#######.#########.#.#.###.#.#.#########.#####.#.#
+#.......#.#...#...#...#...#...#.#.......#.....O.#.#.#.#...#.#.......#...#.....#s#
+#.#######.###.#.#.#####.###.#.#.#.#######.#####.#.#.#.#.###.#####.#.#.###.#####.#
+#...#...#...#...#...#.#.#...#...#.......#.....#.#.#.#.#...#.#...#.#.#...#...#...#
+###.#.#.#.#########.#.#.#.#######.#####.#.#####.#.###.###.#.###.###.#.#####.#.###
+#.#...#.#.........#...#...#....d#.....#.#.#.....#.#...#...#.#.#...#.#.#.....#.#.#
+#.#####.#######.#######.###.###.#####.#.#.#.#####.#.###.#.#.#.###.#.#.#.#####.#.#
+#...#.#.......#.......#...#.#...#.....#.#.#.....#.......#.#.....#.#.#.#.#.......#
+#.#.#.#######.#.#.#####.###.#.#####.###.#.#####.#############.###.#.#.#.#######.#
+#.#...#.....#.#.#...#...#...#.....#...#.#.#...#.#...........#.#...#.#.#.#...#.#.#
+#.###.###.#.#.#.###.#.###.#######.#####.#.###.#.#.#########.#.#.###.#.#.#.#.#.#.#
+#...#.....#.#.#...#...#...#.......#.....#...#.#.#.....#...#...#...#.#.#...#.#...#
+#.#.#######.#.###.#####.###.#######.#######.#.#.#####.###.#######.#.#####.#.#.###
+#.#.#.....#.#.#.#.#.#...#.#.#...#...#...#...#.#.....#...#.....#...#.....#.#.#w#.#
+#.#.#.###.#.#.#.#.#.#.###.#.#.#.###.#.#.#.###.#.###.###.#.###.#.###.###.###.#.#.#
+#.#.#.#.#.#.#.#.#.#.#.#m..#...#...#...#.#.#...#...#...#.#...#.#.#.....#.#...#.#.#
+###.#.#.#.###W#.#.#.#.#.#########.#####.#.#.#.###.#####.###.#.#.#######.#.###.#.#
+#...#...#.#...#.....#.#.......#...#...#.#.#.#.#.#.....#.....#.#.........#.#.#...#
+#.###.###.#.###.#####.#.###.###.###.#.#.#.#.#.#.#####.#######.###########.#.###.#
+#.#...#...#.#...#.S...#...#.....#...#.#.#...#.....#.#.........#...#...#...#.....#
+#.#.###.###.#####.#######.#######.###.#.#########.#.###########.#.#.#.#.###.#####
+#.....#...........#.......F.......#....@#@...........f..........#...#...#.......#
+#################################################################################
+#.....#.#...........#.....#............@#@..........#...#.....#.M.......#.....#.#
+###P#.#.#.#######.###.###.#.#######.###.#.#########.#.#.#.###.###.#####.###.#.#.#
+#...#...#...#.#...#.....#.#.#.......#...#...#.........#...#.......#...#.....#.#.#
+#.#.#######.#.#.###.#####.#.#.#######.#####.###############.#########.#######.#.#
+#.#.#.....#.#.#.#...#...#.#.#.#.........#...#.......#...#.....#.....#.#.......#.#
+#.###.###.#.#.#.#.###.#.#.#.#.###########.###.#####.#.#.#######.###.#.#.#######.#
+#...#.#.#.#...#.#.#...#...#.#...........#...#...#.#...#.......#.#.#.#.#.........#
+#.#.#.#.#.#.###.#.#.#####.#######.#####.###.###.#.###########.#.#.#.#.#.#######.#
+#.#.#...#...#...#.#r#.....#.....#.....#.#...#.#.#.......#...#.....#.#...#.....#.#
+#.#.###.#####.###.#.#######.###.#####.#.#.#.#.#.###.#####.#.#######.#.###.###.#.#
+#.#...#.#...#...#.#.........#...#...#.#.#.#...#...#.#.....#.#......p#...#.#.#.#.#
+###.#.#.#.#.###.#.###########.###.#.#.#.#.###.###.#.#.#####.#.###.#######.#.#.###
+#...#.#.#.#...#.......#.....#.#...#...#.#...#.#...#.....#...#.#...#.K...#.#.#...#
+#.#####.#.###.#######.#.###Q#.#.#######.###.#.#.#####.###.###.#.###.###.#.#.###.#
+#.....#...#...#.#...#.#.#.#...#...#.....#...#.#.....#.#...#...#.#...#.#..j#.#...#
+#.###.#####.###.#.#.###.#.#########.###.#.#########.###.#.#.###.#.###.#####.#.###
+#...#.#.....#...#.#.B...#...#...#...#...#.#.......#.....#.#...#.#...........#.R.#
+#.###.#.#######.#.#######.#.#.#.#.###.###.#.#.###.#######.###.###.#############.#
+#.#...#.......#.#n....#...#.#.#...#...#.#...#...#.....#...#.#.....#..u..#.....#.#
+###.#.#######.#.#####.#.###.#.#####.###.#.#####.###.###.###.###.###.###.#.###.#.#
+#...#.#...#...#.....#.#.#...#...#.#...#.#...#...#...#...#...#.#.#...#...#.#...#.#
+#.#####.#.#.###.#.#####.#.###.#.#.###.#.#####.#######.#####.#.###.###.###.###.#.#
+#...#...#.#.#...#.......#.#...#.#...#...#.....#.......#.....#.U...#.#...#...#...#
+#.#.#.###.#.#.#########.#.#####.###.###.#.#.###.#######.###########.###X#.#.###.#
+#.#..l#...#.#...#.......#.....#...#...#.#.#o#...#.#.....#...#......x....#.#.#...#
+#.#####C###.#.###.###########.###.#.###.#.###.###.#.###.#.#.#I#############.#.###
+#.....#...#.#.#...#...#.....#.#...#.#...#.#...#.....#...#.#...#v......G.#...#..q#
+###.#####.#.###.###.#.#.###.#.#.###.#.###.#.###.#####.#.#.#####.#######.#.#####.#
+#.#y#...#.#...#.#...#.#...#.#...#...#...#.#.#...#.....#.#..i..#...#.....#...#...#
+#.#.#.#.#.###.#.#.###.#.#.#.#####.#.###.#.#.###.#.###########H#.#.#.#####.#.#.###
+#...#.#.#...#.#.....#.#.#.#.#...#.#.....#.#...#.#...........#.#.#.#g..#...#.#...#
+#.###.#.###A#.#######.#.#.#.#.###.#######.###.#.#########.#.#.#.#.###.#####.###.#
+#.#...#.....#.........#.#.#.#.#...#.....#...#.#.......#...#.#.#.#.#.#.#...#...#.#
+###.#####################.#.#.#.#####.###.#.#.#########.###.#.###.#.#.#.#.###.#.#
+#...#.......#.............#..t#.#...#...#.#.#.#.......#.#...#...#.#.#.N.#.....#.#
+#.###.#####.#.#########.#######.#.#D#.#.#.#.#.#.#####.#.#.#####.#.#.###########.#
+#.#...#...#..z#.#.......#.....#...#.#.#.#.#.#...#...#...#.#.#..h#.#.....#......b#
+#.#.###.#.#####.#.#######.###.#####.###.#.#.#####.#.#####.#.#.###.#.###.#.#######
+#.......#.......#...........#...........#.#.....E.#.........#...V.#...#.........#
+#################################################################################
diff --git a/2019/inputs/day_19.txt b/2019/inputs/day_19.txt
new file mode 100644
index 0000000..e85881e
--- /dev/null
+++ b/2019/inputs/day_19.txt
@@ -0,0 +1 @@
+109,424,203,1,21102,11,1,0,1106,0,282,21101,0,18,0,1106,0,259,1201,1,0,221,203,1,21102,1,31,0,1106,0,282,21101,0,38,0,1106,0,259,20102,1,23,2,21202,1,1,3,21101,1,0,1,21101,0,57,0,1105,1,303,2101,0,1,222,20101,0,221,3,21001,221,0,2,21102,1,259,1,21101,0,80,0,1105,1,225,21101,185,0,2,21102,91,1,0,1106,0,303,1202,1,1,223,21001,222,0,4,21102,259,1,3,21101,225,0,2,21102,1,225,1,21101,0,118,0,1106,0,225,20102,1,222,3,21102,1,131,2,21101,133,0,0,1106,0,303,21202,1,-1,1,22001,223,1,1,21101,148,0,0,1105,1,259,2101,0,1,223,21002,221,1,4,21002,222,1,3,21101,0,16,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,21101,0,195,0,106,0,109,20207,1,223,2,20101,0,23,1,21102,1,-1,3,21101,0,214,0,1105,1,303,22101,1,1,1,204,1,99,0,0,0,0,109,5,1201,-4,0,249,22101,0,-3,1,22101,0,-2,2,21201,-1,0,3,21101,0,250,0,1106,0,225,21201,1,0,-4,109,-5,2106,0,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,22102,1,-2,-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,21201,-2,0,3,21101,343,0,0,1106,0,303,1105,1,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,22101,0,-4,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,21201,1,0,-4,109,-5,2106,0,0
diff --git a/2019/inputs/day_2.txt b/2019/inputs/day_2.txt
new file mode 100644
index 0000000..dd34cff
--- /dev/null
+++ b/2019/inputs/day_2.txt
@@ -0,0 +1 @@
+1,0,0,3,1,1,2,3,1,3,4,3,1,5,0,3,2,9,1,19,1,19,5,23,1,23,6,27,2,9,27,31,1,5,31,35,1,35,10,39,1,39,10,43,2,43,9,47,1,6,47,51,2,51,6,55,1,5,55,59,2,59,10,63,1,9,63,67,1,9,67,71,2,71,6,75,1,5,75,79,1,5,79,83,1,9,83,87,2,87,10,91,2,10,91,95,1,95,9,99,2,99,9,103,2,10,103,107,2,9,107,111,1,111,5,115,1,115,2,119,1,119,6,0,99,2,0,14,0
diff --git a/2019/inputs/day_20.txt b/2019/inputs/day_20.txt
new file mode 100644
index 0000000..09d6330
--- /dev/null
+++ b/2019/inputs/day_20.txt
@@ -0,0 +1,113 @@
+ K Z V U I F
+ Q T Y Y E E
+ ###################################.#####.###.###########.#####.#.#####################################
+ #.......#.#.............#.........#.#.......#.#.#.........#.....#...#...#...........#...#.....#.#.....#
+ ###.#####.###.###.###.###########.#.###.#####.#.###.#.#.#.###.###.###.#####.#######.###.#####.#.###.###
+ #.#...#.#.#.#.#.#.#.#.....#...........#.....#.#...#.#.#.#...#.#.#.#.....#.#.#...#.#.#...#.#.#.....#...#
+ #.#.###.#.#.###.###.#.#########.###.#######.#.#.#.#######.#.#.#.#.#.###.#.#.#.###.#####.#.#.#.#####.###
+ #.....#...#...............#.#.#.#.#.#.....#.#.#.#...#.....#.#.#.#.#...#.....#.#.#.........#...#.#...#.#
+ #.#######.###########.###.#.#.###.#.###.#.#.#.#.###.###.###.#.#.#.#.###.#.###.#.#.#.#######.###.###.#.#
+ #...#.......#...#.#...#...#...#.#.#.#...#...#.....#.#.#.#...#...#...#...#.........#.#.#.#...#.......#.#
+ #.#######.#.###.#.#######.###.#.#.#.#.#.###.###.#####.#####.###.#.#####.#####.#.#.###.#.###.#.#######.#
+ #.#.#...#.#...#.......#.......#.#...#.#...#.#.#...#.#.......#...#.#.........#.#.#...............#.....#
+ #.#.#.#######.#####.#####.###.#.###.#.#####.#.#.###.#####.###.#####.###.###########.###############.###
+ #.#...#...#.......#...#...#.#.......#.....#.#.....#.#.......#.#...#.#.#.#.......#.......#...#...#.#...#
+ #.###.###.#####.#.###.#####.#####.#.###.#######.#.#.#######.#.#.#####.#.#.###########.#####.###.#.#.###
+ #.#.#.#...#...#.#.#...#.#.#.#.#.#.#.#...#.......#.#.#.#.....#.....#...............#...#.#...#.........#
+ #.#.#.#.#####.#.#####.#.#.#.#.#.###.#.#####.###.###.#.#####.#.#######.#.#######.#######.#.#.###.#####.#
+ #.......#.#.#...#.#...............#.#...#.#.#.......#...#...#.......#.#.#.#.#...#.#.....#.#.#...#.#...#
+ #.#######.#.###.#.#.###.#.#.#.###.#.###.#.###.#.###.#.###.#.#.#.#######.#.#.#####.#.#######.#.###.###.#
+ #.#.#.#.#.#.......#.#.#.#.#.#.#.#.#.#...#...#.#.#.#.#.....#.#.#.#.#.#...#.......#.#.#.#...#.#.#...#.#.#
+ #.#.#.#.#.#####.#####.#.#####.#.#.#.#.###.#.#.###.#####.#####.#.#.#.#.#####.#.###.#.#.#.###.#.###.#.###
+ #.#.#.#.#.#.....#.#.....#.......#.#.#.#...#.#...#...#.......#.#.#.#.........#.#...#.......#.#.#.#.#.#.#
+ #.#.#.#.#.#.###.#.#.#####.###.#.#.#.#.#.###.#.###.#.###.#######.#.#.###.###.#####.#.#.#.###.#.#.#.#.#.#
+ #.......#.#.#.#.#.#.#...#.#.#.#.#...#...#...#...#.#.#.....#.#...#...#...#.......#...#.#...#.#.#.#...#.#
+ #####.###.#.#.###.#####.###.###.###.#####.#####.#.#.#.#####.#.#.#####.#######.#####.#######.#.#.#.###.#
+ #.#...#.........#...#.#.......#...#...#.....#...#.#.#.....#...#.#...........#.#.#.#...#.#.........#...#
+ #.###.#.#.#######.#.#.#.#########.#########.#.###.#.#.#.###.#.#########.###.###.#.#.###.###.#######.###
+ #.#.....#...#...#.#...#.....#.......#.......#.....#.#.#...#.#.....#.....#.....#...#.#...#.........#...#
+ #.###.#.#.#####.###.###.#######.#####.#############.#.#########.###.###########.###.#.#.#.###.#.###.#.#
+ #...#.#.#.#.#...#.#.#.....# U N Q W Z N #.......#.#...#...#...#.#.#
+ ###.###.###.###.#.#.###.### Y D P L W J #####.#########.#######.###
+ #.#.#.#.#...#...#.#...#.#.# #.....#...#...........#.#.#
+ #.#.#.#.###.###.#.#.###.#.# ###.#.###.###.###.#####.#.#
+ #...................#.#...# #.#.#.........#...#........CB
+ #.###.#######.#.###.#.#.#.# #.#.#.###.#####.###.#.#.#.#
+ #.#.........#.#...#.....#.# #...#.#.....#...#...#.#.#..AA
+ #######.#######.###.#####.# #.#######.#.###.#.#.###.###
+ #.....#.......#...#...#...# QJ..#.#...#.#.#.#...#...#.#.#
+ ###.#.#.###.###########.### ###.#.#######.###########.#
+YG....#.....#.#.......#......TY #.........#...........#...#
+ #.#.#.###########.#.#.##### #.#####.###.#########.#.#.#
+ #.#.#.#...#...#...#.#.#...# CB..#.#.......#.#.#.#.....#..DN
+ #######.#####.#.#.#####.### ###.#########.#.#.#########
+ #.....#...#...#.#.#...#.#.# #...#.........#...#.......#
+ #.###.#.#.#.#.#.#.#.#.#.#.# ###.###.#####.#.#.#.#####.#
+SP..#.....#...#...#...#......YG #.......#...#...#.#.#.....#
+ ########################### #.#.###.###.#.###.#.#.#####
+NJ....#.................#.#.# KQ..#.#.......#.#...#.#.....#
+ #.#.#.#####.#.#.#####.#.#.# ###.###.###.###.#.#.###.#.#
+ #.#.#.....#.#.#.#.....#...# #.#...#.#.#.#.#.#.....#.#..IT
+ ###.#####.###.#####.#####.# #.#.#####.###.#############
+ #.#.....#...#.....#........WE IE..#.#.#.#...............#.#
+ #.#.#.#.#.#########.#.###.# #.#.#.#.#.###.###.###.###.#
+ #...#.#...#.#.#.#...#.#...# #.#.#...#.#.#...#.#...#.#.#
+ #.#######.#.#.#.#####.##### #.#####.#.#.#.#.#####.#.#.#
+ #.#.....#.#.........#.#...# #...........#.#.#.#...#....QJ
+ #######.###.#.#.###.#####.# #######.#.#######.#.#.###.#
+ #.#.....#...#.#.#.........# #.....#.#.#...#.#...#.....#
+ #.###.#.#.#######.#.#####.# ###.#########.#.###########
+YV..#...#.#...#.#.#.#.#.....# #.......#.........#.#.....#
+ #.#.###.#.#.#.#.#.###.#.### #.#####.###.#####.#.#.#.#.#
+ #.....#...#.#...#.#.#.#....QX #.#...#.........#.#...#.#..QP
+ ###.###.#######.###.###.#.# #.###.#.###.#####.#.#####.#
+ #.#.#.....#.....#.....#.#.# #.#.#.#.#...#.....#...#...#
+ #.#####.#######.###.#.##### #.#.#.#####.#.###.###.#.#.#
+ #.#...#.#.....#.#.#.#...#..DM FE..#.#...#.#.#.#.......#.#.#
+ #.#.#####.#.###.#.#.###.#.# #.#.#.#.#.###############.#
+ #.#.......#...#.#.....#...# #.#...#.#.#.....#.......#.#
+ #.#.#.#.#.###.#.#####.###.# #######.#.#.#######.#.#####
+QX....#.#.#.#.............#.# #.......#.#.......#.#.....#
+ #####.#.#.#.#.#.########### ###.###.#.#.#.###.#.#####.#
+ #.#.#.#.#.#.#.#.#.........# GX..#.#.......#.#.#.......#..DM
+ #.#.###############.###.#.# #.#.#####.#.###.###.###.#.#
+ #.#.#.........#...#...#.#..CS #.....#.#.#.#.#...#.#.#.#.#
+ #.#.#######.#####.###.#.### #######.#.###.#.#####.#####
+WE........#.#.#.#.#.#...#...# MX........#.#.........#......CS
+ #####.###.#.#.#.#.#.#.##### #####.###.###.#####.###.###
+ #...#...............#.#.#.# #.#.....#.#.......#...#...#
+ ###.###################.#.# #.#.###########.#.###.#.#.#
+ #...............#.#........ME #.#.#.#...#...#.#.#...#.#.#
+ #.#.#####.#####.#.#.###.#.# #.#.#####.#######.#.#####.#
+GX..#...#.#.#...........#.#.# #.................#.......#
+ #.#.###.#######.###.#####.# J D Z V S I Y #.###.###.#.###.###.#.#.#.#
+ #.#.......#.......#.....#.# I N T Y P T V #...#...#.#.#.#.#.#.#.#.#.#
+ #.#.#.#########.#.#.#############.#########.###.#.#.#############.###.###########.###.#.#.#.#.#.#####.#
+ #.#.#.....#.....#.#...#.......#.....#.......#.....#.#.#.#.#...#...#.........#.....#...#.#.....#...#...#
+ #.#############.###.#######.#.#####.#.###.###.#####.#.#.#.###.#.#####.#.#.#####.#.#.#.#.#####.###.#####
+ #...........#.....#.....#...#.......#...#.#.#.....#.#.....#.#.......#.#.#...#...#.#.#.#.#.....#.#.....#
+ ###.#######.#######.#####.###.#######.#.###.###.#.#.#.###.#.#.#######.#############.#.#######.#.#.###.#
+ #.#.....#.#.#.#.......#.#.#.#...#...#.#...#...#.#.#.....#...#.......#.....#.#...#...#...#.......#.#...#
+ #.#.#.###.#.#.#.#.###.#.###.###.#.#.###.#.###.#.#########.#####.#.###.#.###.#.#########.#####.#####.#.#
+ #...#...#.....#.#.#...#...#.#...#.#...#.#.#.....#.#.#.....#...#.#.#...#.............#.....#.....#...#.#
+ #####.###########.#####.###.#.###.#.###.#####.#.#.#.###.#.#.#.###.#.#######.###.#########.#.#.#########
+ #.........#.....#.#...........#...#.#...#.#...#.#...#...#.#.#.....#.......#...#.#.....#.#.#.#.....#.#.#
+ ###.###.#.###.#####.#.#.#.#.#.#.###.###.#.###.#####.#.#####.#.###.###.#####.#####.#####.#####.#####.#.#
+ #...#.#.#.#.........#.#.#.#.#...#...#.....#.....#.......#...#.#.#.#.......#.#.#...#.....#.#.#.........#
+ #.#.#.#.###.###.###########.###.#.###.#.#####.#.#.#.#.#.#.#.###.###.#.###.###.###.#.#.#.#.#.#.###.#.#.#
+ #.#.#...#...#.....#.........#.#.#...#.#.#.#...#.#.#.#.#.#.#.......#.#...#.#.....#...#.#.#.......#.#.#.#
+ #.#.###.#.#.#.#.#.#####.#####.#.###.#.###.###.#####.#######.###.###.#########.###.#######.#.#.#####.#.#
+ #.#.#...#.#.#.#.#.#.#.#.#.......#...#...#...#...#.....#.#.....#.#.#.......#...#.....#.#.#.#.#.#.#...#.#
+ #.#####.#.#####.###.#.#######.#.#.#.###.###.#.#.###.###.###.#####.#.#.#####.#####.#.#.#.###.#.#.#####.#
+ #...#...#.#.....#.#.....#.#...#.#.#.#...#.#...#.#.......#.#.#.#.#...#...........#.#.#...#.#.#.....#.#.#
+ ###.###.#########.#####.#.###.#####.#.###.###.#####.#####.#.#.#.#.#######.#######.###.###.#####.#.#.###
+ #.....#.#.....................#...#.#.......#.#.....#.....#.....#.#...........#.....#.#.#.#.#...#.#...#
+ #.###.#####.#.#.#.###.#.#.#.###.###.###.#.###.#####.###.#.#.#########.###########.###.#.#.#.###.###.###
+ #...#...#...#.#.#.#...#.#.#.#.......#.#.#...#.....#.#...#.#.......#.#.........#.............#.........#
+ ###.#.#####.#############.#####.#.###.#.###.#####.#.#.###.###.#.#.#.#####.#.###.###.###.###.#.#####.###
+ #...#.#.#.#...#.#...#.......#...#.....#.#...#.....#...#.#.#.#.#.#...#.....#.....#.....#...#.#...#.....#
+ #.###.#.#.###.#.###.###.#####.#####.#####.###.#########.#.#.#####.#######.#####.###.#####.#.#.###.###.#
+ #.#.........#.#.........#.....#.....#.....#.........#.....#.......#...........#...#...#...#.#...#.#...#
+ ###################################.###.#######.#.###.###.###.#######.#################################
+ N J W Z Z M M T
+ D I L W Z X E Y
diff --git a/2019/inputs/day_21.txt b/2019/inputs/day_21.txt
new file mode 100644
index 0000000..cafb613
--- /dev/null
+++ b/2019/inputs/day_21.txt
@@ -0,0 +1 @@
+109,2050,21102,1,966,1,21101,0,13,0,1106,0,1378,21101,20,0,0,1105,1,1337,21101,27,0,0,1105,1,1279,1208,1,65,748,1005,748,73,1208,1,79,748,1005,748,110,1208,1,78,748,1005,748,132,1208,1,87,748,1005,748,169,1208,1,82,748,1005,748,239,21101,0,1041,1,21102,73,1,0,1106,0,1421,21101,0,78,1,21101,0,1041,2,21101,88,0,0,1106,0,1301,21101,68,0,1,21102,1041,1,2,21102,103,1,0,1106,0,1301,1101,0,1,750,1105,1,298,21101,0,82,1,21101,0,1041,2,21102,1,125,0,1105,1,1301,1102,1,2,750,1105,1,298,21102,79,1,1,21102,1,1041,2,21101,147,0,0,1106,0,1301,21102,1,84,1,21102,1,1041,2,21101,0,162,0,1106,0,1301,1101,0,3,750,1106,0,298,21101,0,65,1,21101,1041,0,2,21101,0,184,0,1106,0,1301,21101,76,0,1,21102,1,1041,2,21101,199,0,0,1106,0,1301,21102,75,1,1,21102,1,1041,2,21101,214,0,0,1105,1,1301,21101,221,0,0,1106,0,1337,21101,10,0,1,21102,1041,1,2,21102,236,1,0,1105,1,1301,1106,0,553,21102,1,85,1,21102,1,1041,2,21101,254,0,0,1105,1,1301,21101,78,0,1,21101,0,1041,2,21102,1,269,0,1106,0,1301,21102,276,1,0,1105,1,1337,21101,10,0,1,21102,1,1041,2,21101,0,291,0,1105,1,1301,1101,1,0,755,1105,1,553,21101,32,0,1,21102,1,1041,2,21102,313,1,0,1106,0,1301,21102,1,320,0,1106,0,1337,21102,327,1,0,1105,1,1279,1202,1,1,749,21102,65,1,2,21101,0,73,3,21102,1,346,0,1106,0,1889,1206,1,367,1007,749,69,748,1005,748,360,1101,0,1,756,1001,749,-64,751,1106,0,406,1008,749,74,748,1006,748,381,1102,1,-1,751,1105,1,406,1008,749,84,748,1006,748,395,1102,1,-2,751,1105,1,406,21102,1100,1,1,21101,0,406,0,1105,1,1421,21101,32,0,1,21102,1,1100,2,21101,421,0,0,1105,1,1301,21102,1,428,0,1106,0,1337,21102,435,1,0,1105,1,1279,2102,1,1,749,1008,749,74,748,1006,748,453,1102,1,-1,752,1106,0,478,1008,749,84,748,1006,748,467,1101,0,-2,752,1105,1,478,21101,1168,0,1,21101,0,478,0,1106,0,1421,21102,485,1,0,1105,1,1337,21102,1,10,1,21101,1168,0,2,21101,0,500,0,1105,1,1301,1007,920,15,748,1005,748,518,21101,0,1209,1,21102,1,518,0,1106,0,1421,1002,920,3,529,1001,529,921,529,101,0,750,0,1001,529,1,537,101,0,751,0,1001,537,1,545,1001,752,0,0,1001,920,1,920,1105,1,13,1005,755,577,1006,756,570,21102,1100,1,1,21101,570,0,0,1105,1,1421,21102,1,987,1,1105,1,581,21101,1001,0,1,21102,1,588,0,1106,0,1378,1101,0,758,593,1001,0,0,753,1006,753,654,21001,753,0,1,21101,610,0,0,1106,0,667,21101,0,0,1,21101,621,0,0,1106,0,1463,1205,1,647,21101,1015,0,1,21101,635,0,0,1106,0,1378,21101,1,0,1,21101,646,0,0,1105,1,1463,99,1001,593,1,593,1106,0,592,1006,755,664,1101,0,0,755,1105,1,647,4,754,99,109,2,1102,1,726,757,21202,-1,1,1,21101,9,0,2,21102,1,697,3,21102,692,1,0,1105,1,1913,109,-2,2105,1,0,109,2,101,0,757,706,1201,-1,0,0,1001,757,1,757,109,-2,2106,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,255,63,95,191,159,223,127,0,155,123,163,249,179,110,200,117,68,60,61,190,197,250,196,186,111,187,99,158,244,217,222,246,94,205,35,54,115,239,218,243,62,241,229,168,79,199,215,178,182,118,43,228,125,203,214,113,231,120,77,153,141,157,253,143,87,102,86,207,213,177,57,181,156,85,78,204,247,174,109,172,248,92,98,53,93,232,69,242,212,237,152,70,216,183,47,49,124,121,116,122,230,114,100,103,201,51,55,84,171,234,254,238,233,76,185,34,50,175,219,140,42,189,136,38,226,169,39,184,198,166,137,220,251,245,202,142,56,139,167,206,126,252,106,107,71,162,235,236,101,108,119,58,173,170,46,221,227,59,154,188,138,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,73,110,112,117,116,32,105,110,115,116,114,117,99,116,105,111,110,115,58,10,13,10,87,97,108,107,105,110,103,46,46,46,10,10,13,10,82,117,110,110,105,110,103,46,46,46,10,10,25,10,68,105,100,110,39,116,32,109,97,107,101,32,105,116,32,97,99,114,111,115,115,58,10,10,58,73,110,118,97,108,105,100,32,111,112,101,114,97,116,105,111,110,59,32,101,120,112,101,99,116,101,100,32,115,111,109,101,116,104,105,110,103,32,108,105,107,101,32,65,78,68,44,32,79,82,44,32,111,114,32,78,79,84,67,73,110,118,97,108,105,100,32,102,105,114,115,116,32,97,114,103,117,109,101,110,116,59,32,101,120,112,101,99,116,101,100,32,115,111,109,101,116,104,105,110,103,32,108,105,107,101,32,65,44,32,66,44,32,67,44,32,68,44,32,74,44,32,111,114,32,84,40,73,110,118,97,108,105,100,32,115,101,99,111,110,100,32,97,114,103,117,109,101,110,116,59,32,101,120,112,101,99,116,101,100,32,74,32,111,114,32,84,52,79,117,116,32,111,102,32,109,101,109,111,114,121,59,32,97,116,32,109,111,115,116,32,49,53,32,105,110,115,116,114,117,99,116,105,111,110,115,32,99,97,110,32,98,101,32,115,116,111,114,101,100,0,109,1,1005,1262,1270,3,1262,20101,0,1262,0,109,-1,2106,0,0,109,1,21102,1,1288,0,1106,0,1263,21001,1262,0,0,1102,0,1,1262,109,-1,2106,0,0,109,5,21102,1310,1,0,1105,1,1279,22102,1,1,-2,22208,-2,-4,-1,1205,-1,1332,22101,0,-3,1,21101,1332,0,0,1106,0,1421,109,-5,2106,0,0,109,2,21101,1346,0,0,1105,1,1263,21208,1,32,-1,1205,-1,1363,21208,1,9,-1,1205,-1,1363,1105,1,1373,21102,1,1370,0,1106,0,1279,1106,0,1339,109,-2,2105,1,0,109,5,1202,-4,1,1386,20101,0,0,-2,22101,1,-4,-4,21102,0,1,-3,22208,-3,-2,-1,1205,-1,1416,2201,-4,-3,1408,4,0,21201,-3,1,-3,1106,0,1396,109,-5,2106,0,0,109,2,104,10,22102,1,-1,1,21101,0,1436,0,1106,0,1378,104,10,99,109,-2,2105,1,0,109,3,20002,593,753,-1,22202,-1,-2,-1,201,-1,754,754,109,-3,2105,1,0,109,10,21102,5,1,-5,21102,1,1,-4,21102,1,0,-3,1206,-9,1555,21101,3,0,-6,21101,5,0,-7,22208,-7,-5,-8,1206,-8,1507,22208,-6,-4,-8,1206,-8,1507,104,64,1105,1,1529,1205,-6,1527,1201,-7,716,1515,21002,0,-11,-8,21201,-8,46,-8,204,-8,1105,1,1529,104,46,21201,-7,1,-7,21207,-7,22,-8,1205,-8,1488,104,10,21201,-6,-1,-6,21207,-6,0,-8,1206,-8,1484,104,10,21207,-4,1,-8,1206,-8,1569,21102,1,0,-9,1105,1,1689,21208,-5,21,-8,1206,-8,1583,21102,1,1,-9,1106,0,1689,1201,-5,716,1588,21002,0,1,-2,21208,-4,1,-1,22202,-2,-1,-1,1205,-2,1613,21201,-5,0,1,21102,1613,1,0,1105,1,1444,1206,-1,1634,22101,0,-5,1,21101,0,1627,0,1106,0,1694,1206,1,1634,21101,2,0,-3,22107,1,-4,-8,22201,-1,-8,-8,1206,-8,1649,21201,-5,1,-5,1206,-3,1663,21201,-3,-1,-3,21201,-4,1,-4,1106,0,1667,21201,-4,-1,-4,21208,-4,0,-1,1201,-5,716,1676,22002,0,-1,-1,1206,-1,1686,21101,1,0,-4,1105,1,1477,109,-10,2106,0,0,109,11,21102,0,1,-6,21101,0,0,-8,21101,0,0,-7,20208,-6,920,-9,1205,-9,1880,21202,-6,3,-9,1201,-9,921,1724,21002,0,1,-5,1001,1724,1,1733,20101,0,0,-4,21202,-4,1,1,21101,1,0,2,21101,9,0,3,21101,1754,0,0,1105,1,1889,1206,1,1772,2201,-10,-4,1767,1001,1767,716,1767,20102,1,0,-3,1105,1,1790,21208,-4,-1,-9,1206,-9,1786,22101,0,-8,-3,1105,1,1790,22101,0,-7,-3,1001,1733,1,1795,21001,0,0,-2,21208,-2,-1,-9,1206,-9,1812,21201,-8,0,-1,1105,1,1816,22101,0,-7,-1,21208,-5,1,-9,1205,-9,1837,21208,-5,2,-9,1205,-9,1844,21208,-3,0,-1,1106,0,1855,22202,-3,-1,-1,1106,0,1855,22201,-3,-1,-1,22107,0,-1,-1,1106,0,1855,21208,-2,-1,-9,1206,-9,1869,21201,-1,0,-8,1105,1,1873,22101,0,-1,-7,21201,-6,1,-6,1105,1,1708,22102,1,-8,-10,109,-11,2106,0,0,109,7,22207,-6,-5,-3,22207,-4,-6,-2,22201,-3,-2,-1,21208,-1,0,-6,109,-7,2105,1,0,0,109,5,2102,1,-2,1912,21207,-4,0,-1,1206,-1,1930,21102,1,0,-4,22101,0,-4,1,21202,-3,1,2,21102,1,1,3,21102,1949,1,0,1105,1,1954,109,-5,2105,1,0,109,6,21207,-4,1,-1,1206,-1,1977,22207,-5,-3,-1,1206,-1,1977,21202,-5,1,-5,1105,1,2045,22102,1,-5,1,21201,-4,-1,2,21202,-3,2,3,21102,1,1996,0,1105,1,1954,22102,1,1,-5,21102,1,1,-2,22207,-5,-3,-1,1206,-1,2015,21101,0,0,-2,22202,-3,-2,-3,22107,0,-4,-1,1206,-1,2037,21202,-2,1,1,21101,2037,0,0,106,0,1912,21202,-3,-1,-3,22201,-5,-3,-5,109,-6,2106,0,0
diff --git a/2019/inputs/day_22.txt b/2019/inputs/day_22.txt
new file mode 100644
index 0000000..b61e760
--- /dev/null
+++ b/2019/inputs/day_22.txt
@@ -0,0 +1,100 @@
+deal with increment 34
+deal into new stack
+cut 1712
+deal into new stack
+cut 1984
+deal with increment 62
+deal into new stack
+deal with increment 13
+deal into new stack
+deal with increment 67
+cut -5590
+deal with increment 63
+cut -1086
+deal with increment 52
+cut 7894
+deal with increment 71
+cut -864
+deal into new stack
+cut 239
+deal with increment 17
+cut -7187
+deal with increment 62
+deal into new stack
+cut -7380
+deal with increment 14
+cut 3842
+deal into new stack
+cut -5258
+deal with increment 40
+deal into new stack
+deal with increment 45
+cut -6026
+deal with increment 21
+cut 3600
+deal with increment 56
+cut 2329
+deal into new stack
+deal with increment 13
+cut -2409
+deal with increment 49
+cut 294
+deal into new stack
+cut 4776
+deal with increment 17
+cut 5801
+deal with increment 43
+cut 8999
+deal with increment 46
+cut -8527
+deal with increment 4
+deal into new stack
+cut -6767
+deal into new stack
+deal with increment 33
+cut -532
+deal with increment 29
+deal into new stack
+deal with increment 56
+cut 6867
+deal with increment 70
+cut 4276
+deal into new stack
+cut -5621
+deal with increment 56
+cut -2966
+deal with increment 70
+deal into new stack
+deal with increment 51
+cut -4097
+deal with increment 42
+deal into new stack
+cut -5180
+deal with increment 61
+deal into new stack
+cut 5367
+deal with increment 50
+cut 3191
+deal with increment 75
+cut 915
+deal with increment 72
+cut -3893
+deal with increment 22
+cut -3405
+deal with increment 30
+cut -6509
+deal with increment 31
+cut -7220
+deal with increment 45
+cut 6489
+deal with increment 70
+cut -4047
+deal into new stack
+deal with increment 75
+cut 3980
+deal with increment 10
+cut 9677
+deal into new stack
+deal with increment 45
+cut -6969
+deal into new stack
diff --git a/2019/inputs/day_23.txt b/2019/inputs/day_23.txt
new file mode 100644
index 0000000..e4f8887
--- /dev/null
+++ b/2019/inputs/day_23.txt
@@ -0,0 +1 @@
+3,62,1001,62,11,10,109,2215,105,1,0,1846,1780,1120,1959,571,2182,1083,631,1485,1306,1157,2153,1654,1592,1454,664,1815,951,2124,794,695,2023,1378,1248,1518,984,1887,2058,823,1019,891,1277,1685,2089,1341,1922,1186,765,1751,1413,602,922,858,1623,1217,1559,1050,1990,734,1720,0,0,0,0,0,0,0,0,0,0,0,0,3,64,1008,64,-1,62,1006,62,88,1006,61,170,1106,0,73,3,65,20101,0,64,1,21001,66,0,2,21101,105,0,0,1105,1,436,1201,1,-1,64,1007,64,0,62,1005,62,73,7,64,67,62,1006,62,73,1002,64,2,133,1,133,68,133,101,0,0,62,1001,133,1,140,8,0,65,63,2,63,62,62,1005,62,73,1002,64,2,161,1,161,68,161,1101,1,0,0,1001,161,1,169,101,0,65,0,1101,0,1,61,1101,0,0,63,7,63,67,62,1006,62,203,1002,63,2,194,1,68,194,194,1006,0,73,1001,63,1,63,1105,1,178,21102,1,210,0,105,1,69,2101,0,1,70,1102,0,1,63,7,63,71,62,1006,62,250,1002,63,2,234,1,72,234,234,4,0,101,1,234,240,4,0,4,70,1001,63,1,63,1105,1,218,1105,1,73,109,4,21101,0,0,-3,21102,0,1,-2,20207,-2,67,-1,1206,-1,293,1202,-2,2,283,101,1,283,283,1,68,283,283,22001,0,-3,-3,21201,-2,1,-2,1106,0,263,22102,1,-3,-3,109,-4,2106,0,0,109,4,21101,0,1,-3,21101,0,0,-2,20207,-2,67,-1,1206,-1,342,1202,-2,2,332,101,1,332,332,1,68,332,332,22002,0,-3,-3,21201,-2,1,-2,1106,0,312,21202,-3,1,-3,109,-4,2106,0,0,109,1,101,1,68,358,21001,0,0,1,101,3,68,366,21001,0,0,2,21102,1,376,0,1106,0,436,22101,0,1,0,109,-1,2106,0,0,1,2,4,8,16,32,64,128,256,512,1024,2048,4096,8192,16384,32768,65536,131072,262144,524288,1048576,2097152,4194304,8388608,16777216,33554432,67108864,134217728,268435456,536870912,1073741824,2147483648,4294967296,8589934592,17179869184,34359738368,68719476736,137438953472,274877906944,549755813888,1099511627776,2199023255552,4398046511104,8796093022208,17592186044416,35184372088832,70368744177664,140737488355328,281474976710656,562949953421312,1125899906842624,109,8,21202,-6,10,-5,22207,-7,-5,-5,1205,-5,521,21102,1,0,-4,21102,1,0,-3,21101,0,51,-2,21201,-2,-1,-2,1201,-2,385,471,20102,1,0,-1,21202,-3,2,-3,22207,-7,-1,-5,1205,-5,496,21201,-3,1,-3,22102,-1,-1,-5,22201,-7,-5,-7,22207,-3,-6,-5,1205,-5,515,22102,-1,-6,-5,22201,-3,-5,-3,22201,-1,-4,-4,1205,-2,461,1106,0,547,21102,-1,1,-4,21202,-6,-1,-6,21207,-7,0,-5,1205,-5,547,22201,-7,-6,-7,21201,-4,1,-4,1106,0,529,21201,-4,0,-7,109,-8,2106,0,0,109,1,101,1,68,564,20102,1,0,0,109,-1,2106,0,0,1102,97571,1,66,1101,1,0,67,1101,598,0,68,1101,556,0,69,1101,0,1,71,1101,0,600,72,1105,1,73,1,-1605712,28,112719,1102,1,48679,66,1102,1,1,67,1102,1,629,68,1102,556,1,69,1101,0,0,71,1102,631,1,72,1106,0,73,1,1782,1102,1,7877,66,1102,1,2,67,1101,658,0,68,1101,302,0,69,1102,1,1,71,1102,1,662,72,1105,1,73,0,0,0,0,26,81559,1101,0,22453,66,1101,1,0,67,1102,1,691,68,1101,0,556,69,1102,1,1,71,1102,1,693,72,1105,1,73,1,125,35,19959,1101,0,21493,66,1101,0,5,67,1102,1,722,68,1101,0,302,69,1102,1,1,71,1101,0,732,72,1106,0,73,0,0,0,0,0,0,0,0,0,0,2,56893,1102,77191,1,66,1101,1,0,67,1102,1,761,68,1101,556,0,69,1101,1,0,71,1101,763,0,72,1105,1,73,1,1037327,8,179734,1101,57977,0,66,1101,0,1,67,1101,792,0,68,1102,556,1,69,1101,0,0,71,1101,0,794,72,1105,1,73,1,1430,1102,57173,1,66,1101,0,1,67,1101,0,821,68,1102,1,556,69,1101,0,0,71,1101,0,823,72,1106,0,73,1,1128,1101,0,37573,66,1102,1,3,67,1102,1,850,68,1102,253,1,69,1102,1,1,71,1101,856,0,72,1105,1,73,0,0,0,0,0,0,17,209158,1101,0,17569,66,1102,1,1,67,1101,0,885,68,1102,556,1,69,1101,2,0,71,1101,887,0,72,1106,0,73,1,8329,20,85972,34,54146,1101,84653,0,66,1101,1,0,67,1101,0,918,68,1102,1,556,69,1102,1,1,71,1101,0,920,72,1105,1,73,1,3167,20,64479,1101,0,88657,66,1102,1,1,67,1101,0,949,68,1101,556,0,69,1102,0,1,71,1102,1,951,72,1105,1,73,1,1419,1101,0,104579,66,1101,2,0,67,1101,0,978,68,1101,0,302,69,1101,0,1,71,1102,982,1,72,1105,1,73,0,0,0,0,6,76316,1102,33797,1,66,1101,0,1,67,1102,1011,1,68,1101,556,0,69,1102,1,3,71,1101,0,1013,72,1105,1,73,1,5,35,13306,35,26612,39,113194,1102,75781,1,66,1101,0,1,67,1102,1,1046,68,1102,1,556,69,1101,0,1,71,1101,1048,0,72,1106,0,73,1,1777,20,42986,1101,32183,0,66,1102,1,1,67,1102,1,1077,68,1102,556,1,69,1102,1,2,71,1102,1,1079,72,1105,1,73,1,10,35,6653,39,169791,1101,19079,0,66,1101,0,4,67,1102,1,1110,68,1102,253,1,69,1101,0,1,71,1102,1118,1,72,1105,1,73,0,0,0,0,0,0,0,0,7,7877,1102,1,56893,66,1101,0,4,67,1102,1147,1,68,1101,253,0,69,1102,1,1,71,1101,0,1155,72,1105,1,73,0,0,0,0,0,0,0,0,45,73189,1102,104651,1,66,1101,1,0,67,1102,1,1184,68,1101,556,0,69,1101,0,0,71,1101,0,1186,72,1105,1,73,1,1351,1101,0,43661,66,1101,1,0,67,1102,1213,1,68,1101,0,556,69,1102,1,1,71,1101,1215,0,72,1105,1,73,1,763676,28,75146,1101,16963,0,66,1102,1,1,67,1102,1,1244,68,1102,1,556,69,1102,1,1,71,1102,1246,1,72,1106,0,73,1,11,26,163118,1101,461,0,66,1101,1,0,67,1102,1275,1,68,1101,556,0,69,1101,0,0,71,1102,1,1277,72,1106,0,73,1,1263,1102,101483,1,66,1101,1,0,67,1102,1304,1,68,1102,556,1,69,1102,0,1,71,1102,1306,1,72,1106,0,73,1,1607,1101,0,14251,66,1101,0,3,67,1102,1333,1,68,1101,302,0,69,1102,1,1,71,1102,1,1339,72,1105,1,73,0,0,0,0,0,0,2,170679,1101,0,27073,66,1101,0,4,67,1102,1,1368,68,1102,1,302,69,1101,1,0,71,1101,0,1376,72,1106,0,73,0,0,0,0,0,0,0,0,1,154743,1101,0,15583,66,1101,0,1,67,1102,1,1405,68,1102,556,1,69,1101,0,3,71,1101,0,1407,72,1106,0,73,1,1,33,14998,21,302361,34,81219,1101,0,56597,66,1101,0,6,67,1102,1440,1,68,1102,1,302,69,1102,1,1,71,1101,1452,0,72,1106,0,73,0,0,0,0,0,0,0,0,0,0,0,0,45,146378,1102,6991,1,66,1101,0,1,67,1102,1,1481,68,1102,1,556,69,1101,0,1,71,1102,1,1483,72,1106,0,73,1,902,21,201574,1102,1,89867,66,1101,2,0,67,1101,1512,0,68,1101,0,302,69,1101,1,0,71,1102,1516,1,72,1106,0,73,0,0,0,0,5,10798,1102,1,61553,66,1102,1,1,67,1102,1,1545,68,1102,556,1,69,1101,0,6,71,1101,0,1547,72,1106,0,73,1,2,20,21493,17,104579,7,15754,26,244677,39,282985,39,339582,1101,73189,0,66,1102,2,1,67,1101,0,1586,68,1101,0,351,69,1102,1,1,71,1101,0,1590,72,1105,1,73,0,0,0,0,255,60251,1101,0,91463,66,1102,1,1,67,1101,1619,0,68,1101,556,0,69,1102,1,1,71,1101,0,1621,72,1105,1,73,1,6467743,28,37573,1102,1,34369,66,1101,0,1,67,1101,1650,0,68,1102,556,1,69,1102,1,1,71,1101,1652,0,72,1105,1,73,1,8933,21,100787,1102,1,77081,66,1101,0,1,67,1101,1681,0,68,1102,1,556,69,1102,1,1,71,1101,1683,0,72,1105,1,73,1,2310,33,7499,1101,0,44699,66,1101,0,1,67,1102,1712,1,68,1101,556,0,69,1101,3,0,71,1101,1714,0,72,1105,1,73,1,3,8,89867,5,5399,34,108292,1101,97387,0,66,1102,1,1,67,1102,1747,1,68,1102,556,1,69,1102,1,1,71,1102,1749,1,72,1105,1,73,1,4,20,107465,1101,0,13463,66,1101,1,0,67,1101,1778,0,68,1101,0,556,69,1102,0,1,71,1102,1,1780,72,1106,0,73,1,1250,1102,51581,1,66,1102,1,3,67,1102,1807,1,68,1101,302,0,69,1101,0,1,71,1102,1,1813,72,1105,1,73,0,0,0,0,0,0,2,113786,1102,1,73679,66,1102,1,1,67,1102,1842,1,68,1102,556,1,69,1101,1,0,71,1102,1,1844,72,1105,1,73,1,160,39,56597,1101,0,60251,66,1101,0,1,67,1101,1873,0,68,1102,556,1,69,1102,6,1,71,1101,1875,0,72,1106,0,73,1,22677,47,94099,1,51581,1,103162,9,14251,9,28502,9,42753,1101,0,81559,66,1101,0,3,67,1102,1914,1,68,1101,0,302,69,1101,1,0,71,1102,1920,1,72,1105,1,73,0,0,0,0,0,0,47,188198,1101,0,6653,66,1101,4,0,67,1102,1949,1,68,1101,302,0,69,1101,0,1,71,1101,0,1957,72,1106,0,73,0,0,0,0,0,0,0,0,39,226388,1101,63659,0,66,1101,0,1,67,1101,0,1986,68,1102,556,1,69,1102,1,1,71,1102,1,1988,72,1105,1,73,1,-2,34,27073,1101,94099,0,66,1101,2,0,67,1101,0,2017,68,1101,0,302,69,1102,1,1,71,1102,2021,1,72,1106,0,73,0,0,0,0,2,227572,1101,100787,0,66,1101,0,3,67,1101,2050,0,68,1102,1,302,69,1101,1,0,71,1101,0,2056,72,1105,1,73,0,0,0,0,0,0,6,19079,1101,0,47599,66,1102,1,1,67,1101,0,2085,68,1102,556,1,69,1102,1,1,71,1101,2087,0,72,1105,1,73,1,2677,33,22497,1102,1,7499,66,1101,0,3,67,1101,2116,0,68,1102,1,302,69,1101,0,1,71,1101,0,2122,72,1105,1,73,0,0,0,0,0,0,6,38158,1101,0,101359,66,1102,1,1,67,1101,2151,0,68,1102,1,556,69,1102,1,0,71,1102,1,2153,72,1105,1,73,1,1752,1101,48091,0,66,1101,1,0,67,1102,1,2180,68,1101,0,556,69,1101,0,0,71,1101,0,2182,72,1106,0,73,1,1463,1102,5399,1,66,1101,0,2,67,1102,1,2209,68,1101,0,302,69,1102,1,1,71,1101,0,2213,72,1106,0,73,0,0,0,0,6,57237
diff --git a/2019/inputs/day_24.txt b/2019/inputs/day_24.txt
new file mode 100644
index 0000000..ba900ad
--- /dev/null
+++ b/2019/inputs/day_24.txt
@@ -0,0 +1,5 @@
+##.#.
+.##..
+##.#.
+.####
+###..
diff --git a/2019/inputs/day_25.txt b/2019/inputs/day_25.txt
new file mode 100644
index 0000000..5351575
--- /dev/null
+++ b/2019/inputs/day_25.txt
@@ -0,0 +1 @@
+109,4795,21102,1,3124,1,21102,1,13,0,1106,0,1424,21102,1,166,1,21101,24,0,0,1105,1,1234,21102,31,1,0,1106,0,1984,1106,0,13,6,4,3,2,52,51,21,4,28,56,55,3,19,-9,-10,47,89,88,90,90,6,77,73,85,71,1,76,68,63,65,22,-27,70,76,81,87,5,105,105,107,108,95,4,97,92,109,109,5,110,105,110,108,95,4,115,96,109,109,13,-3,59,101,85,92,97,13,84,80,92,78,34,-15,26,-16,46,88,72,79,84,0,72,76,-3,85,74,79,75,-8,64,68,75,57,65,70,64,66,72,8,-41,32,-22,56,77,82,-4,60,76,62,70,-2,74,-11,55,52,68,67,73,56,60,52,-20,44,56,66,-24,48,58,42,49,54,-16,-53,10,0,56,99,96,95,82,94,83,45,-9,23,-13,61,85,88,74,71,82,73,79,73,89,67,65,-4,62,73,70,69,56,68,57,2,-35,24,-14,64,85,90,4,70,67,79,7,83,-2,68,75,-5,78,65,57,75,-10,76,53,76,0,-37,31,-21,57,78,83,-3,64,74,72,0,76,-9,73,58,57,-13,70,57,49,67,-18,54,64,48,55,-23,48,44,56,42,-14,-51,14,-4,74,95,100,14,97,77,86,79,9,92,79,75,5,27,-17,61,82,87,1,68,78,76,4,80,-5,66,58,78,60,-10,73,60,52,70,-15,57,67,51,58,-6,-43,14,-4,74,95,100,14,81,94,90,90,9,92,79,75,5,60,-50,23,42,38,-32,38,39,30,42,47,-38,30,36,28,25,41,38,34,31,18,23,29,19,33,-52,20,29,-55,27,27,27,8,15,-61,22,16,-64,24,13,18,-54,-69,-70,-14,7,12,-74,-8,-11,1,-71,5,-80,-4,-3,3,-15,-84,-85,-109,29,-19,59,80,85,-1,82,62,71,64,-6,77,64,60,-10,62,66,57,59,63,57,67,51,-19,56,58,57,57,-10,-47,44,-34,39,58,54,-16,60,61,57,64,48,56,-23,52,40,60,38,-28,44,53,-31,55,32,55,-35,48,42,41,-39,32,38,42,-42,-44,12,33,38,-48,28,19,25,32,-52,-76,-77,59,-49,13,55,-30,42,51,-33,49,50,32,31,31,39,36,48,-42,24,35,32,34,29,21,35,19,25,37,-53,14,10,26,18,-57,-59,-3,18,23,-63,1,17,3,-67,1,-4,14,-2,6,-73,-8,14,-76,-12,-78,-40,2,4,-13,-82,-106,-107,35,-25,53,74,79,0,74,60,-10,65,53,72,64,52,56,52,50,-19,53,57,62,56,-24,58,54,38,39,40,-29,-31,2,56,35,-34,-58,-59,138,-128,-74,-108,-33,-31,-26,-44,-101,-114,-33,-37,-51,-39,-35,-47,-54,-122,-37,-45,-52,-59,-58,-128,-46,-65,-42,-49,-133,-132,-102,-60,-68,-56,-55,-139,-141,-106,-61,-65,-72,-78,-64,-148,-70,-72,-151,-68,-81,-81,-72,-156,-74,-86,-86,-80,-161,-97,-81,-95,-165,-94,-98,-103,-83,-97,-102,-90,-173,-90,-103,-111,-99,-178,-95,-108,-112,-182,-115,-115,-101,-117,-120,-104,-120,-122,-191,-106,-128,-118,-110,-127,-196,-196,-199,-135,-123,-134,-203,-115,-126,-121,-207,-143,-127,-141,-211,-143,-139,-145,-148,-132,-148,-150,-219,-154,-156,-155,-148,-224,-141,-147,-227,-144,-157,-161,-231,-165,-161,-165,-168,-161,-157,-159,-166,-162,-157,-228,-265,138,-128,-74,-108,-33,-31,-26,-44,-101,-114,-33,-37,-51,-39,-35,-47,-54,-122,-37,-45,-52,-59,-58,-128,-46,-65,-42,-49,-133,-132,-102,-60,-68,-56,-55,-139,-141,-106,-61,-65,-72,-78,-64,-148,-70,-72,-151,-68,-81,-81,-72,-156,-74,-86,-86,-80,-161,-97,-81,-95,-165,-90,-94,-97,-97,-86,-102,-90,-173,-90,-103,-111,-99,-178,-95,-108,-112,-182,-115,-115,-101,-117,-120,-104,-120,-122,-191,-106,-128,-118,-110,-127,-196,-196,-199,-135,-123,-134,-203,-115,-126,-121,-207,-143,-127,-141,-211,-143,-139,-145,-148,-132,-148,-150,-219,-154,-156,-155,-148,-224,-141,-147,-227,-144,-157,-161,-231,-165,-161,-165,-168,-161,-157,-159,-166,-162,-157,-228,-265,263,-253,-199,-233,-158,-156,-151,-169,-226,-239,-158,-162,-176,-164,-160,-172,-179,-247,-162,-170,-177,-184,-183,-253,-171,-190,-167,-174,-258,-257,-227,-183,-197,-187,-175,-182,-193,-184,-268,-202,-191,-194,-192,-197,-205,-191,-207,-276,-278,-222,-201,-196,-282,-206,-219,-196,-286,-207,-206,-210,-223,-222,-223,-225,-280,-293,-296,-232,-220,-231,-300,-212,-223,-218,-304,-236,-228,-223,-239,-227,-310,-227,-240,-244,-314,-248,-237,-250,-243,-239,-247,-237,-308,-345,-273,-260,-248,-243,-263,-329,-252,-252,-248,-260,-267,-266,-253,-337,-249,-260,-255,-259,-342,-260,-267,-280,-270,-271,-348,-281,-268,-272,-279,-285,-342,-355,-280,-278,-279,-284,-277,-361,-282,-278,-274,-275,-290,-298,-300,-369,-300,-292,-290,-373,-309,-375,-299,-298,-301,-310,-302,-297,-370,-383,-302,-316,-321,-311,-315,-299,-321,-308,-392,-306,-322,-330,-312,-397,-326,-334,-317,-401,-330,-338,-324,-325,-337,-329,-339,-341,-398,-411,-347,-335,-346,-415,-334,-352,-350,-346,-341,-338,-422,-334,-345,-340,-344,-427,-345,-357,-357,-351,-432,-365,-361,-353,-367,-370,-354,-363,-351,-427,-464,-441,-397,-373,-434,-447,-376,-380,-374,-375,-373,-452,-454,-398,-377,-372,-458,-376,-388,-382,-377,-387,-396,-465,-400,-398,-468,-404,-404,-395,-403,-473,-390,-396,-476,-406,-409,-395,-480,-408,-404,-483,-418,-396,-486,-403,-399,-409,-417,-413,-421,-493,37,-5,73,71,-8,75,62,58,-12,62,55,74,64,48,50,-19,45,63,-22,61,48,44,-26,50,37,44,48,-31,33,40,48,41,43,30,37,-25,-38,-63,0,0,109,7,21101,0,0,-2,22208,-2,-5,-1,1205,-1,1169,22202,-2,-4,1,22201,1,-6,1,21202,-2,1,2,21102,1162,1,0,2105,1,-3,21201,-2,1,-2,1106,0,1136,109,-7,2106,0,0,109,6,2101,0,-5,1182,20101,0,0,-2,21102,0,1,-3,21201,-5,1,-5,22208,-3,-2,-1,1205,-1,1229,2201,-5,-3,1205,20101,0,0,1,22102,1,-3,2,21202,-2,1,3,21102,1,1222,0,2105,1,-4,21201,-3,1,-3,1105,1,1192,109,-6,2106,0,0,109,2,21202,-1,1,1,21101,1256,0,2,21102,1251,1,0,1106,0,1174,109,-2,2105,1,0,109,5,22201,-4,-3,-1,22201,-2,-1,-1,204,-1,109,-5,2106,0,0,109,3,1202,-2,1,1280,1006,0,1303,104,45,104,32,1201,-1,66,1291,21002,0,1,1,21101,1301,0,0,1105,1,1234,104,10,109,-3,2105,1,0,0,0,109,2,2101,0,-1,1309,1102,1,0,1308,21102,1,4601,1,21102,13,1,2,21101,4,0,3,21102,1,1353,4,21101,1343,0,0,1105,1,1130,20102,1,1308,-1,109,-2,2106,0,0,63,109,3,1201,-2,0,1360,20008,0,1309,-1,1206,-1,1419,1005,1308,1398,1102,1,1,1308,21008,1309,-1,-1,1206,-1,1387,21102,106,1,1,1106,0,1391,21101,0,92,1,21102,1,1398,0,1106,0,1234,104,45,104,32,1201,-2,1,1407,21002,0,1,1,21102,1417,1,0,1105,1,1234,104,10,109,-3,2105,1,0,109,3,1202,-2,1,1128,21102,1,34,1,21101,0,1441,0,1106,0,1234,1001,1128,0,1447,20101,0,0,1,21102,1,1456,0,1105,1,1234,21102,1,41,1,21101,1467,0,0,1105,1,1234,1001,1128,1,1472,21002,0,1,1,21101,1482,0,0,1105,1,1234,21102,46,1,1,21102,1493,1,0,1105,1,1234,21001,1128,3,1,21102,4,1,2,21102,1,1,3,21102,1,1273,4,21101,1516,0,0,1106,0,1130,21001,1128,0,1,21102,1,1527,0,1105,1,1310,1001,1128,2,1532,21002,0,1,-1,1206,-1,1545,21101,0,1545,0,2105,1,-1,109,-3,2106,0,0,109,0,99,109,2,1102,1,0,1550,21101,0,4601,1,21102,13,1,2,21101,4,0,3,21101,1664,0,4,21102,1,1582,0,1105,1,1130,2,2486,1352,1551,1102,0,1,1552,21001,1550,0,1,21102,1,33,2,21101,0,1702,3,21102,1,1609,0,1106,0,2722,21007,1552,0,-1,1205,-1,1630,20107,0,1552,-1,1205,-1,1637,21102,1,1630,0,1106,0,1752,21101,0,548,1,1106,0,1641,21101,687,0,1,21101,0,1648,0,1105,1,1234,21101,0,4457,1,21101,1659,0,0,1106,0,1424,109,-2,2105,1,0,109,4,21202,-2,-1,-2,2102,1,-3,1675,21008,0,-1,-1,1206,-1,1697,1201,-3,2,1687,20101,-27,0,-3,22201,-3,-2,-3,2001,1550,-3,1550,109,-4,2105,1,0,109,5,21008,1552,0,-1,1206,-1,1747,1201,-3,1901,1717,20101,0,0,-2,1205,-4,1736,20207,-2,1551,-1,1205,-1,1747,1102,-1,1,1552,1105,1,1747,22007,1551,-2,-1,1205,-1,1747,1102,1,1,1552,109,-5,2105,1,0,109,1,21101,826,0,1,21102,1765,1,0,1105,1,1234,21002,1550,1,1,21102,1776,1,0,1105,1,2863,21102,1090,1,1,21102,1787,1,0,1106,0,1234,99,1106,0,1787,109,-1,2106,0,0,109,1,21101,512,0,1,21101,0,1809,0,1106,0,1234,99,1105,1,1809,109,-1,2105,1,0,109,1,1102,1,1,1129,109,-1,2106,0,0,109,1,21102,1,377,1,21101,0,1842,0,1105,1,1234,1106,0,1831,109,-1,2106,0,0,109,1,21101,407,0,1,21101,1863,0,0,1105,1,1234,99,1106,0,1863,109,-1,2106,0,0,109,1,21102,1,452,1,21101,1885,0,0,1106,0,1234,99,1106,0,1885,109,-1,2105,1,0,1941,1947,1953,1958,1965,1972,1978,4083,3936,4362,4458,4463,4254,3769,4145,4116,3848,4384,3957,4371,4258,3951,4063,3935,4053,4163,4259,3817,4062,4500,3970,4331,4022,3969,4163,4483,4089,3810,4092,4196,2281,2468,2418,2450,2487,2125,2505,5,95,108,104,104,23,5,96,91,108,108,1,4,101,105,112,3,6,104,104,106,107,94,-1,6,109,104,109,107,94,-1,5,111,91,100,93,23,5,114,95,108,108,1,109,3,21102,1993,1,0,1106,0,2634,1006,1129,2010,21101,0,316,1,21101,0,2007,0,1106,0,1234,1106,0,2076,21101,0,0,-1,1201,-1,1894,2019,21001,0,0,1,21102,0,1,2,21102,1,0,3,21101,0,2037,0,1106,0,2525,1206,1,2054,1201,-1,1934,2050,21102,2051,1,0,106,0,0,1105,1,2076,21201,-1,1,-1,21207,-1,7,-2,1205,-2,2014,21101,0,177,1,21102,1,2076,0,1105,1,1234,109,-3,2105,1,0,109,3,2001,1128,-2,2088,21002,0,1,-1,1205,-1,2108,21101,201,0,1,21101,2105,0,0,1105,1,1234,1106,0,2119,22101,0,-1,1,21101,2119,0,0,1106,0,1424,109,-3,2105,1,0,0,109,1,1101,0,0,2124,21101,0,4601,1,21101,0,13,2,21101,0,4,3,21102,2173,1,4,21102,2154,1,0,1106,0,1130,1005,2124,2168,21102,226,1,1,21102,2168,1,0,1106,0,1234,109,-1,2106,0,0,109,3,1005,2124,2275,1201,-2,0,2183,20008,0,1128,-1,1206,-1,2275,1201,-2,1,2195,20102,1,0,-1,21202,-1,1,1,21102,5,1,2,21102,1,1,3,21102,2216,1,0,1106,0,2525,1206,1,2275,21102,1,258,1,21101,2230,0,0,1105,1,1234,21202,-1,1,1,21101,0,2241,0,1106,0,1234,104,46,104,10,1101,1,0,2124,1201,-2,0,2256,1101,0,-1,0,1201,-2,3,2262,21002,0,1,-1,1206,-1,2275,21101,2275,0,0,2105,1,-1,109,-3,2106,0,0,0,109,1,1101,0,0,2280,21101,4601,0,1,21101,0,13,2,21102,1,4,3,21102,1,2329,4,21102,1,2310,0,1106,0,1130,1005,2280,2324,21102,1,273,1,21102,1,2324,0,1105,1,1234,109,-1,2105,1,0,109,3,1005,2280,2413,1201,-2,0,2339,21008,0,-1,-1,1206,-1,2413,1201,-2,1,2351,20102,1,0,-1,22101,0,-1,1,21102,5,1,2,21101,1,0,3,21102,2372,1,0,1105,1,2525,1206,1,2413,21102,301,1,1,21102,2386,1,0,1106,0,1234,22102,1,-1,1,21102,2397,1,0,1106,0,1234,104,46,104,10,1102,1,1,2280,1201,-2,0,2412,101,0,1128,0,109,-3,2106,0,0,109,1,21101,0,-1,1,21102,1,2431,0,1105,1,1310,1205,1,2445,21102,1,133,1,21101,0,2445,0,1106,0,1234,109,-1,2106,0,0,109,1,21102,3,1,1,21101,2463,0,0,1106,0,2081,109,-1,2106,0,0,109,1,21101,4,0,1,21102,1,2481,0,1105,1,2081,109,-1,2106,0,0,70,109,1,21102,5,1,1,21102,2500,1,0,1105,1,2081,109,-1,2105,1,0,109,1,21102,6,1,1,21102,2518,1,0,1105,1,2081,109,-1,2106,0,0,0,0,109,5,2102,1,-3,2523,1101,0,1,2524,21202,-4,1,1,21101,0,2585,2,21101,2550,0,0,1105,1,1174,1206,-2,2576,2101,0,-4,2558,2001,0,-3,2566,101,3094,2566,2566,21008,0,-1,-1,1205,-1,2576,1102,0,1,2524,21001,2524,0,-4,109,-5,2105,1,0,109,5,22201,-4,-3,-4,22201,-4,-2,-4,21208,-4,10,-1,1206,-1,2606,21102,-1,1,-4,201,-3,2523,2615,1001,2615,3094,2615,21002,0,1,-1,22208,-4,-1,-1,1205,-1,2629,1101,0,0,2524,109,-5,2106,0,0,109,4,21101,0,3094,1,21102,30,1,2,21101,1,0,3,21102,1,2706,4,21102,1,2659,0,1105,1,1130,21101,0,0,-3,203,-2,21208,-2,10,-1,1205,-1,2701,21207,-2,0,-1,1205,-1,2663,21207,-3,29,-1,1206,-1,2663,2101,3094,-3,2693,2102,1,-2,0,21201,-3,1,-3,1106,0,2663,109,-4,2105,1,0,109,2,1201,-1,0,2715,1102,-1,1,0,109,-2,2105,1,0,0,109,5,2102,1,-2,2721,21207,-4,0,-1,1206,-1,2739,21102,1,0,-4,21202,-4,1,1,21202,-3,1,2,21102,1,1,3,21101,0,2758,0,1105,1,2763,109,-5,2106,0,0,109,6,21207,-4,1,-1,1206,-1,2786,22207,-5,-3,-1,1206,-1,2786,21201,-5,0,-5,1105,1,2858,22101,0,-5,1,21201,-4,-1,2,21202,-3,2,3,21101,0,2805,0,1105,1,2763,21202,1,1,-5,21101,0,1,-2,22207,-5,-3,-1,1206,-1,2824,21102,0,1,-2,22202,-3,-2,-3,22107,0,-4,-1,1206,-1,2850,22102,1,-2,1,21201,-4,-1,2,21101,0,2850,0,105,1,2721,21202,-3,-1,-3,22201,-5,-3,-5,109,-6,2105,1,0,109,3,21208,-2,0,-1,1205,-1,2902,21207,-2,0,-1,1205,-1,2882,1105,1,2888,104,45,21202,-2,-1,-2,21201,-2,0,1,21102,2899,1,0,1106,0,2909,1106,0,2904,104,48,109,-3,2106,0,0,109,4,22102,1,-3,1,21101,10,0,2,21101,0,2926,0,1105,1,3010,21201,1,0,-2,21201,2,0,-1,1206,-2,2948,22101,0,-2,1,21101,0,2948,0,1106,0,2909,22101,48,-1,-1,204,-1,109,-4,2105,1,0,1,2,4,8,16,32,64,128,256,512,1024,2048,4096,8192,16384,32768,65536,131072,262144,524288,1048576,2097152,4194304,8388608,16777216,33554432,67108864,134217728,268435456,536870912,1073741824,2147483648,4294967296,8589934592,17179869184,34359738368,68719476736,137438953472,274877906944,549755813888,1099511627776,2199023255552,4398046511104,8796093022208,17592186044416,35184372088832,70368744177664,140737488355328,281474976710656,562949953421312,1125899906842624,109,8,21101,0,0,-4,21101,0,0,-3,21102,1,51,-2,21201,-2,-1,-2,1201,-2,2959,3034,20101,0,0,-1,21202,-3,2,-3,22207,-7,-1,-5,1205,-5,3059,21201,-3,1,-3,22102,-1,-1,-5,22201,-7,-5,-7,22207,-3,-6,-5,1205,-5,3078,22102,-1,-6,-5,22201,-3,-5,-3,22201,-1,-4,-4,1205,-2,3024,21202,-4,1,-7,21202,-3,1,-6,109,-8,2106,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3131,3143,0,3252,3527,0,0,11,61,105,95,94,17,50,97,83,78,79,83,108,-19,2,7,-79,-9,-2,2,-83,-11,-7,-86,-3,-16,-7,-11,-6,-21,-21,-94,-30,-96,-25,-19,-23,-31,-101,-29,-25,-104,-21,-34,-38,-108,-39,-34,-32,-33,-31,-114,-43,-47,-35,-49,-105,-120,-69,-43,-123,-49,-56,-57,-47,-128,-40,-51,-46,-50,-133,-51,-63,-63,-57,-138,-69,-58,-62,-65,-143,-79,-69,-63,-68,-148,-79,-68,-82,-83,-63,-81,-77,-85,-145,-158,-75,-88,-92,-162,-91,-85,-89,-97,-167,-96,-104,-87,-171,-106,-104,-105,-97,-176,-94,-109,-114,-104,-112,-114,-169,3259,3267,0,3344,0,3124,0,7,65,89,99,98,108,85,108,76,8,27,27,36,-48,16,32,18,13,-53,18,10,27,-57,8,10,9,17,-62,16,16,19,7,10,5,21,-1,-3,-72,-3,5,7,-76,6,1,-2,-11,3,-10,-10,-6,-14,-59,-87,1,-10,-5,-84,-10,-24,-94,-21,-11,-14,-14,-99,-22,-22,-18,-103,-23,-20,-33,-23,-39,-109,-27,-26,-30,-44,-114,-28,-44,-52,-34,-105,3351,3359,0,0,3408,3252,0,7,76,108,102,104,86,91,88,48,36,55,51,-19,46,58,66,46,59,-25,48,58,55,55,-30,36,47,45,50,30,37,41,-38,38,39,41,27,-43,22,34,42,22,35,-35,-50,-51,-2,16,13,30,26,26,15,27,9,15,27,-49,3415,3423,0,0,3458,4392,3344,7,76,108,88,88,97,89,102,34,48,66,69,73,62,62,61,73,3,72,61,77,55,53,-2,-17,34,53,49,68,-15,59,45,-25,39,49,48,-29,39,46,48,51,55,-21,3465,3486,0,3584,0,4053,3408,20,51,84,80,93,8,62,88,70,84,83,75,79,71,-1,33,66,74,79,63,75,40,32,70,77,-11,57,63,69,54,-16,51,61,-19,69,58,63,-23,63,57,39,53,-28,51,52,38,51,36,44,49,47,-37,41,39,-40,43,30,26,-44,26,33,-16,3534,3548,0,0,0,0,3124,13,54,100,86,103,15,63,98,77,93,94,78,90,90,35,49,68,64,-6,59,61,59,73,-11,53,69,55,-15,49,59,58,-19,64,58,57,-23,59,52,39,49,48,-29,40,48,50,-33,55,44,49,-23,3591,3600,0,0,3732,3458,3673,8,75,96,89,96,20,53,83,106,72,11,44,38,37,35,37,38,36,-48,17,29,33,20,-53,-4,14,12,-44,-12,20,23,8,6,-63,-14,4,7,11,0,0,-1,11,-72,4,-5,-7,-3,-10,-5,-1,-11,-81,-17,-5,-16,-85,-4,-18,-17,-4,-14,-26,-10,-93,-12,-26,-23,-19,-30,-30,-31,-19,-102,-26,-35,-37,-33,-40,-35,-31,-41,-97,3680,3703,0,3901,3584,0,4241,22,50,88,92,7,41,77,83,70,81,77,65,83,67,-3,34,74,79,71,76,56,63,67,28,55,82,79,70,72,78,85,9,-4,68,78,0,75,-9,73,73,61,63,62,-15,71,62,64,56,53,57,49,-9,3739,3748,0,3828,0,3981,3584,8,59,102,104,103,93,87,97,99,79,5,24,20,-50,26,17,31,11,21,-56,30,7,17,16,22,-62,2,14,3,-66,17,4,0,-70,6,-3,11,-9,1,-76,-7,-2,0,-1,1,-82,-18,-2,-16,-86,-4,-12,-16,-19,-19,-8,-17,-5,-95,-28,-24,-28,-29,-31,-19,-33,-25,-20,-105,-39,-28,-32,-30,-28,-28,-98,-113,-67,-33,-116,-52,-36,-50,-120,-37,-50,-54,-35,-94,3835,3844,0,4166,0,3732,0,8,64,102,98,100,88,88,85,92,56,27,54,51,42,51,49,39,-31,51,36,35,42,47,-37,46,40,-40,31,23,43,25,-45,30,22,22,35,-50,22,32,-53,25,23,-56,27,14,10,-60,-22,11,2,14,19,-66,-28,14,4,-2,-71,11,-4,10,9,-3,1,-7,-65,3908,3920,0,0,0,3673,0,11,68,86,102,87,99,102,80,98,92,94,100,60,24,43,39,51,37,-33,31,47,33,-37,27,-39,30,28,45,-43,40,24,30,22,35,18,29,29,17,30,-27,-55,28,15,11,30,-53,21,7,-63,1,11,10,-67,-2,10,6,13,-3,-5,-74,-7,3,10,0,-67,-80,3,-10,-4,1,-14,-14,-73,3988,3997,0,3732,4095,0,0,8,72,88,105,104,85,90,87,100,55,29,48,44,63,-20,54,40,-30,34,-32,43,39,49,48,39,31,-39,44,46,31,40,40,44,-46,18,30,19,-50,32,32,12,28,29,17,21,13,-59,24,18,-62,13,15,14,9,-67,-3,7,6,-71,-7,3,-1,0,-7,-63,4060,4068,0,3458,0,0,0,7,68,97,107,89,93,89,97,26,43,91,73,85,91,85,72,72,76,68,3,78,-6,63,74,60,59,79,57,0,54,67,57,52,50,-5,4102,4114,0,0,0,4337,3981,11,58,98,90,91,95,85,84,96,86,90,82,51,38,59,64,-22,60,45,44,-26,38,-28,58,42,42,52,36,32,44,29,45,30,-39,47,32,42,29,-44,35,30,18,30,34,-50,19,27,29,-54,-4,24,25,15,19,11,7,20,16,9,3,-66,19,-50,-55,4173,4185,0,0,0,3828,0,11,72,87,92,87,95,83,84,14,57,77,77,55,34,55,60,-26,56,41,40,-30,38,54,40,34,34,42,30,31,-39,32,28,40,26,-44,34,24,-47,32,33,29,33,27,31,35,25,13,-57,22,20,16,28,15,6,18,-65,2,2,15,4,1,7,-72,14,5,7,-1,-63,4248,4259,0,0,3673,0,0,10,68,86,106,92,89,82,100,88,93,91,77,6,38,18,36,36,33,-25,-52,-2,30,27,9,21,10,10,8,-47,-62,-15,12,4,-1,16,1,-69,13,14,8,7,2,14,-76,0,-9,-14,3,4,0,-14,-7,-16,-8,-3,-5,-89,-20,-9,-13,-16,-94,-25,-23,-27,-14,-10,-100,-18,-18,-38,-22,-22,-106,-23,-29,-109,-28,-42,-45,-48,-38,-42,-50,-35,-53,-35,-51,-107,4344,4351,0,4095,0,0,0,6,59,107,91,88,90,90,40,38,70,68,58,-12,66,56,-15,68,55,51,-19,47,44,44,50,54,44,58,56,-28,54,39,38,45,-33,50,44,-36,35,27,47,29,-41,38,36,43,24,36,-33,4399,4422,0,3408,0,4457,0,22,65,74,90,87,6,41,86,76,88,70,0,44,63,70,74,79,63,71,57,69,57,58,34,39,81,-4,60,74,73,61,56,72,72,-12,71,65,-15,50,52,-18,68,59,61,53,50,54,46,-26,51,51,53,47,34,44,43,55,-21,4464,4484,0,4392,4556,0,0,19,64,81,78,95,91,81,91,95,5,39,75,71,68,75,79,77,70,74,79,71,2,38,-41,42,29,25,-45,32,22,40,35,-50,31,27,26,23,-43,-56,8,-58,21,22,8,21,20,21,17,3,-54,15,0,8,12,1,11,-1,11,-7,-77,-8,-3,-1,-2,0,-83,3,-12,-10,-11,-88,-3,-21,-9,-19,-23,-5,-95,-7,-18,-13,-17,-100,-28,-34,-34,-26,-21,-33,-23,-19,-95,4563,4588,1553,0,0,0,4457,24,56,89,75,88,87,88,84,70,13,50,67,75,79,68,78,66,78,60,-10,27,64,66,65,67,12,53,97,83,93,105,105,87,91,83,25,24,23,3981,4653,16777243,0,3344,4659,32796,0,4166,4672,67108893,0,3252,4683,46,0,3673,4699,31,1818,3527,4719,536870944,0,3408,4727,268435489,0,3584,4741,34,1829,3828,4755,35,1850,4241,4767,36,1796,4053,4778,1061,0,4337,4782,38,1872,3901,4790,41,0,5,110,98,94,100,99,12,95,95,87,90,94,15,80,92,96,95,86,78,10,106,86,97,85,97,102,98,88,92,82,15,104,85,80,98,85,81,93,10,86,73,74,78,78,82,72,19,84,85,76,88,93,8,76,82,74,71,87,84,80,77,64,69,75,65,79,7,90,102,107,91,99,98,84,13,102,98,96,95,91,14,92,82,11,77,74,92,29,13,92,96,87,89,93,87,97,81,11,86,88,87,87,11,98,99,95,102,86,94,15,90,78,98,76,10,91,104,87,84,98,86,16,95,93,81,3,106,113,98,7,105,96,102,106,100,98,102,4,95,92,101,94
diff --git a/2019/inputs/day_3.txt b/2019/inputs/day_3.txt
new file mode 100644
index 0000000..504e9fe
--- /dev/null
+++ b/2019/inputs/day_3.txt
@@ -0,0 +1,2 @@
+R995,D882,R144,U180,L638,U282,L907,D326,R731,D117,R323,U529,R330,U252,R73,U173,R345,U552,R230,U682,R861,U640,L930,U590,L851,D249,R669,D878,R951,D545,L690,U392,R609,D841,R273,D465,R546,U858,L518,U567,L474,D249,L463,D390,L443,U392,L196,U418,R433,U651,R520,D450,R763,U714,R495,D716,L219,D289,L451,D594,R874,U451,R406,U662,R261,D242,R821,D951,R808,D862,L871,U133,R841,D465,R710,U300,R879,D497,R85,U173,R941,U953,R705,U972,R260,D315,L632,U182,L26,D586,R438,U275,L588,U956,L550,D576,R738,U974,R648,D880,R595,D510,L789,U455,R627,U709,R7,D486,L184,U999,L404,U329,L852,D154,L232,U398,L587,U881,R938,D40,L657,D164,R45,D917,R106,U698,L824,D426,R879,U700,R847,D891,L948,U625,R663,D814,R217,U30,R610,D781,L415,D435,L904,U815,R152,U587,R287,U141,R866,D636,L290,D114,L751,D660,R6,U383,L263,U799,R330,U96,L6,U542,L449,D361,R486,U278,L990,U329,L519,U605,R501,D559,R916,U198,L499,D174,R513,U396,L473,D565,R337,D770,R211,D10,L591,D920,R367,D748,L330,U249,L307,D645,R661,U266,R234,D403,L513,U443,L989,D1,L674,D210,L537,D872,L607,D961,R894,U632,L195,U744,L426,U531,R337,D821,R113,U436,L700,U779,R555,U891,R268,D30,R958,U411,R904,U24,R760,D958,R231,U229,L561,D134,L382,D961,L237,U676,L223,U324,R663,D186,R833,U188,R419,D349,L721,U152,L912,U490,R10,D995,L98,U47,R140,D815,R826,U730,R808,U256,R479,D322,L504,D891,L413,D848,L732,U375,L307,U7,R682,U270,L495,D248,R691,D945,L70,U220,R635,D159,R269,D15,L161,U214,R814,D3,R354,D632,R469,D36,R85,U215,L243,D183,R140,U179,R812,U180,L905,U136,L34,D937,L875
+L999,D22,L292,U843,R390,U678,R688,D492,L489,U488,R305,U951,L636,U725,R402,U84,L676,U171,L874,D201,R64,D743,R372,U519,R221,U986,L393,D793,R72,D184,L553,D137,L187,U487,L757,U880,L535,U887,R481,U236,L382,D195,L388,D90,R125,U414,R512,D382,R972,U935,L172,D1,R957,U593,L151,D158,R396,D42,L30,D178,R947,U977,R67,D406,R744,D64,L677,U23,R792,U864,R259,U315,R314,U17,L37,D658,L642,U135,R624,U601,L417,D949,R203,D122,R76,D493,L569,U274,L330,U933,R815,D30,L630,D43,R86,U926,L661,D491,L541,D96,R868,D565,R664,D935,L336,D152,R63,U110,L782,U14,R172,D945,L732,D870,R404,U767,L907,D558,R748,U591,R461,D153,L635,D457,R241,U478,L237,U218,R393,U468,L182,D745,L388,D360,L222,D642,L151,U560,R437,D326,R852,U525,R717,U929,L470,U621,R421,U408,L540,D176,L69,U753,L200,U251,R742,U628,R534,U542,R85,D71,R283,U905,L418,D755,L593,U335,L114,D684,L576,D645,R652,D49,R86,D991,L838,D309,L73,U847,L418,U675,R991,U463,R314,D618,L433,U173,R869,D115,L18,U233,R541,U516,L570,U340,R264,D442,L259,U276,R433,D348,R524,D353,R336,D883,R580,U157,R79,D27,L134,D161,L748,D278,R322,D581,R654,D156,L930,D293,L156,U311,R807,D618,R408,U719,R366,D632,R307,D565,R478,D620,R988,D821,R365,D581,L946,D138,L943,U69,R620,U208,L407,U188,L122,U353,L751,U565,R849,D874,R668,D794,L140,D474,R289,D773,R344,D220,L55,D385,L394,U208,R305,U736,L896,D376,R331,D855,L466,U516,L741,U124,L825,U467,L525,D911,R76,U220,L610,U102,L261,D891,L585,U397,L152,U753,R822,D252,R106,U145,L7,U524,R343,U352,L357,D399,L446,D140,L723,U46,R687,D409,R884
diff --git a/2019/inputs/day_4.txt b/2019/inputs/day_4.txt
new file mode 100644
index 0000000..f62320b
--- /dev/null
+++ b/2019/inputs/day_4.txt
@@ -0,0 +1,2 @@
+138241
+674034
diff --git a/2019/inputs/day_5.txt b/2019/inputs/day_5.txt
new file mode 100644
index 0000000..f8c2724
--- /dev/null
+++ b/2019/inputs/day_5.txt
@@ -0,0 +1 @@
+3,225,1,225,6,6,1100,1,238,225,104,0,1102,57,23,224,101,-1311,224,224,4,224,1002,223,8,223,101,6,224,224,1,223,224,223,1102,57,67,225,102,67,150,224,1001,224,-2613,224,4,224,1002,223,8,223,101,5,224,224,1,224,223,223,2,179,213,224,1001,224,-469,224,4,224,102,8,223,223,101,7,224,224,1,223,224,223,1001,188,27,224,101,-119,224,224,4,224,1002,223,8,223,1001,224,7,224,1,223,224,223,1,184,218,224,1001,224,-155,224,4,224,1002,223,8,223,1001,224,7,224,1,224,223,223,1101,21,80,224,1001,224,-101,224,4,224,102,8,223,223,1001,224,1,224,1,224,223,223,1101,67,39,225,1101,89,68,225,101,69,35,224,1001,224,-126,224,4,224,1002,223,8,223,1001,224,1,224,1,224,223,223,1102,7,52,225,1102,18,90,225,1101,65,92,225,1002,153,78,224,101,-6942,224,224,4,224,102,8,223,223,101,6,224,224,1,223,224,223,1101,67,83,225,1102,31,65,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,1007,226,226,224,102,2,223,223,1005,224,329,1001,223,1,223,108,677,226,224,1002,223,2,223,1005,224,344,1001,223,1,223,1007,677,677,224,1002,223,2,223,1005,224,359,1001,223,1,223,1107,677,226,224,102,2,223,223,1006,224,374,1001,223,1,223,8,226,677,224,1002,223,2,223,1006,224,389,101,1,223,223,8,677,677,224,102,2,223,223,1006,224,404,1001,223,1,223,1008,226,226,224,102,2,223,223,1006,224,419,1001,223,1,223,107,677,226,224,102,2,223,223,1006,224,434,101,1,223,223,7,226,226,224,1002,223,2,223,1005,224,449,1001,223,1,223,1107,226,226,224,1002,223,2,223,1006,224,464,1001,223,1,223,1107,226,677,224,1002,223,2,223,1005,224,479,1001,223,1,223,8,677,226,224,1002,223,2,223,1006,224,494,1001,223,1,223,1108,226,677,224,1002,223,2,223,1006,224,509,101,1,223,223,1008,677,677,224,1002,223,2,223,1006,224,524,1001,223,1,223,1008,677,226,224,102,2,223,223,1006,224,539,1001,223,1,223,1108,677,677,224,102,2,223,223,1005,224,554,101,1,223,223,108,677,677,224,102,2,223,223,1006,224,569,101,1,223,223,1108,677,226,224,102,2,223,223,1005,224,584,1001,223,1,223,108,226,226,224,1002,223,2,223,1005,224,599,1001,223,1,223,1007,226,677,224,102,2,223,223,1005,224,614,1001,223,1,223,7,226,677,224,102,2,223,223,1006,224,629,1001,223,1,223,107,226,226,224,102,2,223,223,1005,224,644,101,1,223,223,7,677,226,224,102,2,223,223,1005,224,659,101,1,223,223,107,677,677,224,1002,223,2,223,1005,224,674,1001,223,1,223,4,223,99,226
diff --git a/2019/inputs/day_6.txt b/2019/inputs/day_6.txt
new file mode 100644
index 0000000..49d849c
--- /dev/null
+++ b/2019/inputs/day_6.txt
@@ -0,0 +1,2306 @@
+21X)BWV
+YZJ)YLQ
+FQS)PZW
+R64)71F
+ZH4)QVZ
+LWB)H4Q
+4HQ)PVJ
+TZ5)VBV
+LF1)FKZ
+GKS)BGN
+45B)2NS
+14W)2JY
+1XY)FJ8
+ZRC)WR9
+GCL)6PB
+LP4)GQ8
+26V)HTK
+3M8)1GJ
+47Q)JYK
+WDB)N2R
+KH8)TGY
+LFX)N2X
+VSZ)7PC
+M6W)4WL
+HH9)8PC
+L59)8Y8
+Q49)LWH
+CJ5)XDG
+K51)FGH
+H31)2RJ
+39M)Y4M
+12C)VLF
+PZW)7DW
+MP2)19Q
+R76)CHH
+N6J)KBW
+WR9)W25
+T99)ZF1
+1TS)8SM
+8WW)YX7
+PW6)B2J
+7KX)YM5
+HM6)GVX
+DNB)2YP
+6WC)2LW
+BG5)SB6
+KK1)JTF
+YDT)244
+GGQ)2DJ
+GCP)Q8H
+S1Y)J69
+LBV)DYG
+ZKN)JBS
+8XY)Y8Z
+XMH)NHD
+XVM)2LX
+SYP)BC8
+PXH)YYG
+F29)G9Y
+BYX)4QS
+8MY)S1D
+N2Y)BZK
+FRC)72W
+S2K)YH5
+7JF)K65
+DJ9)K4L
+P26)WXT
+DW9)1DJ
+NP4)3SB
+XS7)CDL
+6XH)4ZT
+2DJ)GCP
+2K4)VV1
+Q6P)NNN
+HQW)ZR9
+9G2)FNB
+H9N)5ZJ
+13Z)GKD
+9MW)37Y
+VDY)BG9
+BL3)12C
+LNN)JST
+Z3V)T39
+XS3)WYG
+8J5)QFQ
+7DW)DXY
+JMV)DM4
+VL3)V7Q
+GZC)ZHV
+3N6)R2H
+FQ6)7LG
+SR9)D66
+1M8)K2L
+24N)M94
+JST)WM9
+7SB)99Q
+58J)YN7
+WWH)5KS
+C39)X9J
+58S)KBP
+TVF)VNG
+TKC)Y34
+KKP)4S6
+XSP)939
+N6J)DZP
+JXP)N6R
+KNJ)7FS
+N3V)LMJ
+JVF)R94
+21C)R4Z
+NYK)5GN
+GVJ)Q6C
+R69)NRS
+GLS)C7D
+T4J)46R
+5GB)51S
+9WD)7PN
+HHX)KK2
+H2P)ZML
+DWD)Q9F
+FKZ)LC3
+Q9F)M8N
+CRZ)LM1
+6DP)YML
+NSR)L2X
+PMX)Q7K
+37R)1GF
+L4G)P4W
+17N)X6D
+JTF)89B
+JGJ)DVJ
+VF9)GMW
+NHD)DJ3
+TRY)F6S
+J11)BVW
+95X)XB5
+3XD)HPM
+7BB)1LW
+FJ8)TV4
+JV3)M9W
+T7L)6SS
+R48)LSB
+F2P)9D2
+PTY)QBY
+KXM)6G1
+N1H)Q2R
+P27)SR9
+1S2)N3G
+V7Q)642
+891)TW7
+B9Y)BRL
+GW4)3XZ
+QWM)G46
+WVK)S6N
+N82)317
+8PG)S21
+NT3)1VX
+QB5)Y3H
+PTT)639
+G8M)WM8
+B36)LX9
+M9M)4P3
+3F9)Q3R
+DND)TJL
+VQB)6N3
+PJT)JTK
+BBN)T4L
+LYP)M3V
+T9R)HH9
+XBR)3X5
+MX3)SWF
+SF1)MXT
+X67)6DQ
+82Z)FQ4
+L64)FNG
+CDG)5D9
+JKZ)XZ5
+MH1)1KD
+5NW)ZH4
+P3T)76Z
+2M4)CKW
+54L)8P7
+JSH)5H5
+LGR)P2V
+QNV)SJ7
+KPS)XMQ
+F2H)49M
+8NJ)KKP
+XZ1)LRZ
+RVK)J5Z
+QT9)NGQ
+1TK)P7X
+39M)595
+DN9)HKY
+HK1)ZRH
+SH1)JV5
+B25)GQ6
+QZC)WYC
+6CJ)F5D
+5R1)HQ7
+FNT)P4J
+4R6)P49
+LG4)QT9
+GWH)RY1
+1FX)ZK8
+HK4)G2N
+4WL)GPR
+SQT)KK1
+RT4)FCN
+NRF)P84
+DQW)4L4
+52N)T4J
+69D)2FV
+RMV)J7N
+S9J)1WM
+B88)9GT
+5M7)GXN
+3XF)6FX
+FL9)8VZ
+X88)JZR
+ZVZ)8J2
+Q83)94V
+82Y)HT7
+7Y7)7X3
+KNK)R1W
+469)PMG
+D9Z)GD1
+Z62)WR1
+YDF)6B6
+5KS)6GW
+57T)ML7
+GXC)R89
+S2N)99C
+JFH)RP9
+KPH)R26
+DZX)93P
+CWT)C2H
+VKN)5M7
+VNG)SH1
+G2N)F6Q
+NFV)FK3
+R65)TQL
+Z6T)4NG
+RQN)KPR
+972)9TB
+KZ1)6TY
+8K2)HKL
+KHJ)H1W
+6N3)XTR
+25Q)T49
+8HF)K9M
+GQX)PHP
+5ZJ)9S7
+C7D)VMJ
+JXV)SJD
+J17)64C
+5XN)WN7
+PH9)WQH
+43T)Q9V
+Z5F)NZ8
+VHQ)D95
+244)7KX
+6N7)JPH
+HC8)HND
+ZF1)39F
+24X)ZPF
+BWV)HQW
+R3N)5R1
+QB9)6XY
+KHW)KFZ
+S2V)DRQ
+S21)1RQ
+C9V)TSD
+Q1Y)LC2
+93Y)W5C
+8ST)T4P
+R5Z)CL4
+424)WNZ
+R7M)5JS
+4R6)H97
+ZXZ)S62
+FRH)SBJ
+ZK8)N82
+6FX)MTK
+Z5M)BRQ
+YYP)FX8
+RZJ)DRK
+V8G)TKQ
+5L9)J1G
+RZG)69H
+R9G)X79
+WFS)ZJQ
+4P8)GXC
+TYW)S54
+R2H)QH7
+6HX)F2H
+BBD)DC5
+DDB)6WC
+2G3)4JN
+FKC)K7V
+XTK)8BD
+Z7X)QGY
+8CG)3F9
+F39)MM9
+F1L)1R7
+ZVH)JDC
+BVW)PXM
+PRV)BF7
+FX8)1XR
+FB2)XN6
+R9L)Z1V
+YDT)H52
+6Z5)XZ1
+QD2)Z7Y
+TLS)6T3
+54C)DL7
+KPR)4TY
+19N)415
+1QG)GNN
+S6N)4MK
+4L8)LD2
+5Z7)PRY
+5C4)2MC
+94B)DY3
+CVK)GTS
+7N7)P27
+5MW)GGH
+2HQ)JYL
+L9J)HLP
+5Y4)NGN
+2BZ)GWN
+HD8)CZS
+HQ7)M9D
+DC5)RK6
+66W)2VT
+3D4)GHZ
+T49)VTP
+PL4)ZS9
+SJ7)TRC
+NKT)G5Y
+K1G)3GN
+37V)4LG
+KWL)VDZ
+7XF)1P8
+64C)FX4
+DY4)J3F
+RV8)8KF
+DRQ)KQ7
+HND)2N7
+HQS)HMW
+J24)9VX
+7DK)3PM
+467)VBK
+Q6C)TZC
+SZY)9TC
+BMM)4S4
+HFH)2S6
+K5K)4QP
+N6W)RZG
+TKQ)489
+4R1)F22
+J1G)YDF
+FVW)9WD
+CV7)TMC
+R6K)H31
+GDL)X14
+H1B)NKT
+XTR)PL6
+BSC)SM7
+MLT)S7B
+22S)R7T
+X8Y)4WX
+NR9)NK9
+FSM)J3S
+WHF)VSG
+ZBG)Q3D
+RMY)7KM
+XBX)1M8
+MHY)1C2
+GSS)X9G
+86F)Y4W
+VL6)6H9
+1VH)L3B
+SF8)CDG
+GTK)45F
+49M)NLL
+FN6)PN3
+KSC)R3Z
+6TN)3QN
+FNG)742
+X45)WWH
+SF5)2WH
+JSJ)B1H
+95L)M8F
+L59)C4Y
+93P)M89
+K1C)6ZZ
+21T)8M6
+X9M)7NX
+WPK)LNG
+393)F6N
+M4L)JXP
+VKN)X88
+NFK)ZVZ
+LKV)C2V
+SWX)TM8
+V7F)8ZN
+3RW)FD8
+9SM)H27
+TP3)1YB
+6MG)D8X
+8S7)345
+9SV)X67
+25P)JDD
+BFX)TNG
+36J)VBH
+HN7)WVK
+ZR3)3NR
+M3V)GPY
+52M)MFV
+MZB)CJ5
+MX3)XLQ
+LCG)PHS
+HZD)RNC
+GWN)DWD
+XBM)WP4
+2FV)YXW
+ZTP)QD2
+R1G)JY6
+KY4)8CG
+H54)RVK
+5HG)WYQ
+BVC)SK1
+948)P3T
+SV8)5MW
+V4D)YLT
+69X)LNZ
+BL3)Y97
+DXG)WLZ
+VV1)SS3
+ZCD)VXB
+X6D)XL2
+B9H)2NB
+KHK)WPK
+YLT)KFT
+P49)CC5
+KBW)CRH
+8KQ)LJ4
+8JJ)VTJ
+TKM)428
+3SB)273
+GPY)R2Z
+WTX)P6W
+LB1)3PR
+Y1R)DJM
+25P)CY5
+SVB)PJM
+56N)S2V
+H82)8D5
+CYB)GP4
+HJ2)BSH
+2J1)F1T
+C4Y)PRM
+TZC)PM5
+K55)NBJ
+X43)LPP
+WYG)3FW
+WFG)N2Y
+Q37)5L9
+WSF)KSH
+V2H)S9J
+HN2)DW9
+3LL)PFH
+6X3)XVM
+8XZ)991
+26L)WTX
+Y97)5C5
+XXL)79Y
+NK9)RR8
+L7W)83Q
+8TX)45B
+GMJ)1H4
+ZRW)58J
+36X)PRS
+8B2)HTL
+8JZ)L94
+PRY)QTW
+PL4)X8Y
+89N)1RJ
+DFJ)62K
+5QZ)CN3
+RYQ)SL6
+1H4)PGZ
+B1H)J88
+JCC)111
+V6W)GG7
+BZK)97X
+49J)WVY
+1WM)21X
+TCN)KSC
+RRD)26V
+VC6)WPS
+Y5S)YJS
+DVR)2J8
+LJF)839
+64D)GZC
+79Y)SZY
+JHT)D6J
+K4K)L59
+YHB)QWM
+6H9)MRR
+X79)M62
+LW7)GGB
+469)TRQ
+14K)951
+L9Y)K51
+W7C)Y73
+XD1)CYL
+1XQ)HYK
+Q19)PWG
+F4M)KHW
+SM1)J3Q
+MV1)1X9
+NMV)3SM
+8ZD)L61
+VWX)6R6
+S4Z)JK4
+9GT)R13
+F66)89X
+DLT)K6R
+H4C)NW9
+R3D)6Z5
+MKN)M5V
+H4C)22S
+BFM)J2V
+KQW)G8D
+V61)6HG
+JX4)LH3
+PHS)P68
+V9M)56X
+1Q6)Y8V
+319)KX2
+M8F)881
+974)KSL
+LRP)XXL
+M3Y)Q39
+LC3)B9H
+4T8)ZRW
+KYB)T7L
+DXJ)72V
+SRP)D3M
+BRN)NGD
+43S)NJ1
+KWJ)VGZ
+DNY)F2J
+DKW)YT1
+6B4)6N5
+GRQ)RYT
+4KV)WFG
+6PG)T9R
+Q3T)V2P
+4M5)HLG
+WKZ)9ZP
+XTP)JMC
+PVZ)JN1
+5F2)26L
+76Z)R5P
+FVW)NS1
+MWS)PXD
+Z7Z)8S7
+CTH)7C2
+837)48K
+3SM)HYY
+J2B)1TS
+Y8V)BS6
+YYD)3XH
+4F7)BFM
+6S1)95D
+4KN)JV3
+GSZ)HVF
+9CP)GPZ
+BFN)LB1
+N72)741
+K6R)3WF
+P4J)QQW
+54G)469
+36T)GJ4
+HXM)X6W
+MR9)M29
+XMQ)SP9
+71F)TJR
+95X)DLT
+1ZX)QVK
+F1L)1SY
+B7X)XDB
+FJW)ZCR
+43X)1XH
+D5H)93V
+FQH)5RJ
+CLW)1RG
+X4Y)X9M
+CRH)DWH
+XWX)GWZ
+36J)TKC
+YFN)YJ6
+15X)MBT
+6T3)NDG
+8SY)4R7
+XMG)HR5
+KSZ)WKZ
+PM5)3K8
+BR4)J1T
+F72)GV7
+317)P1W
+CV7)SPK
+H53)PMX
+NDG)56N
+N68)ZXZ
+X3W)XGJ
+JRJ)S7X
+MKN)DBW
+8CM)953
+M2K)3XL
+95K)95X
+58S)4HL
+D95)L9Y
+FRH)KQW
+NLL)C3D
+X1H)FM1
+R1M)GGQ
+Y8Z)W1B
+KLD)G1V
+6CJ)R5X
+5C5)HN7
+T7M)ZXT
+SZF)B5W
+RPW)6TG
+3VP)2W9
+X2J)RXH
+DWG)C9V
+9FB)524
+1PZ)8ZD
+ZKZ)6S1
+L36)ZKN
+F1J)2D4
+LWC)6SW
+SWF)Y4V
+51L)MWS
+KFZ)52N
+GD1)HFH
+LFK)L36
+KPZ)ZQ6
+3NT)W48
+2CD)G3D
+345)JXV
+2LW)SWX
+9ZY)XTJ
+VWR)576
+STH)NHY
+L4X)M4L
+ZML)RN7
+RDF)7PB
+7FK)3KR
+GVX)DCF
+1WX)DD2
+971)H6W
+H6H)BPX
+BWQ)Z4J
+JPL)3SV
+QWJ)TR8
+376)H9P
+Q3D)1YS
+1N2)FQ6
+2LM)53K
+VSG)6DP
+KNM)8B7
+S7B)YXF
+YHB)JHP
+Y7N)CPB
+M29)3FB
+J37)C8B
+MK3)WHL
+MRG)TQ8
+BFM)DLH
+H4Q)9HF
+D81)R7M
+LRQ)ZKZ
+C1B)413
+BKC)PW6
+GP4)6MX
+C39)JSH
+BW8)TL2
+71Q)3YP
+415)H2V
+DBH)BR4
+JJ7)J2H
+G52)87N
+YV2)JN3
+7PR)Z3V
+999)G8M
+S7Y)JRJ
+G3D)88H
+SR3)NTR
+JY5)FC8
+MYL)B7X
+K7V)HM6
+FXY)L47
+NNN)GYH
+8JJ)Y5S
+3G5)37V
+FLP)4B2
+839)83S
+H27)CV7
+X4F)RXV
+S3P)WMZ
+LD2)SF8
+DYG)77S
+LGR)2LM
+7BX)G2K
+KNF)9S5
+JBS)R45
+T6C)CGH
+CNV)2BZ
+356)1KP
+P93)54J
+VGZ)31Y
+GNG)HDL
+RHW)222
+4T4)4T8
+WVY)M5Z
+KQ7)XMG
+K7F)S2N
+X6Z)Z9S
+XYH)WFC
+7BM)J2B
+H9F)LKV
+WDJ)HWH
+MWM)83M
+YM5)7J5
+Z62)8NR
+99Q)TVF
+VDP)C2N
+9VX)B5T
+YS6)KNF
+35R)ZH5
+JN5)Y4H
+MSN)XSP
+776)CJ4
+3FB)HXT
+HZV)6HY
+Q6N)HXS
+MBT)FTN
+3JP)YJ2
+4DC)KSD
+8PG)5QZ
+YSP)CNV
+THM)CST
+3X5)BPC
+ZG9)4KY
+8M6)MZ5
+FDF)XNB
+H4X)N72
+ZH5)J79
+KN7)ZXV
+1GP)R76
+K5R)CLZ
+W8G)XVF
+YJQ)HB8
+BWC)TB6
+WFH)T6C
+DPB)VYF
+K8N)KWJ
+C2V)HMF
+H93)HF3
+TR8)MFW
+RJ4)F66
+BS6)FVW
+QFW)5B2
+ML7)FB2
+TGY)X9Z
+PRM)ZV3
+4YX)4YV
+36D)N6X
+XLQ)TLS
+WMZ)NRF
+BCM)2CV
+M74)CHT
+JYL)LQ4
+RSN)KXR
+KNK)3Y2
+89X)BJK
+C2H)4YQ
+YYQ)VMB
+164)11H
+WYQ)WSF
+1RG)DRH
+GKD)LLT
+H53)T2F
+X2Q)F82
+B5D)5F8
+JK1)4F7
+1YB)P26
+B6F)552
+RTD)883
+ZPF)DWG
+JRV)DL1
+MLQ)S1Y
+TX8)5QV
+NDT)2MF
+HFS)61F
+HD8)TCN
+8BL)F2X
+4MK)R6Z
+WVN)RMY
+GGX)JCC
+GQ8)J11
+H4V)5FJ
+3JD)VNC
+7KS)9SM
+NTR)YV2
+4LG)JK1
+3XZ)GGX
+SVZ)P96
+4WG)N3V
+QY7)8N9
+XMP)LKL
+T4P)RLM
+J7C)JJZ
+7PC)Y23
+LPP)M6T
+F82)9KL
+9XR)VT4
+SF1)4T3
+FW6)N66
+QBY)D49
+BCM)17Y
+H1W)R6K
+ZVN)7QK
+BRH)7JF
+LKL)39C
+LV1)BJS
+8PC)FN6
+CHB)TBS
+ZLR)3XD
+8BD)BSC
+NVC)9FB
+Z9L)HK1
+FT3)BWL
+446)S8V
+LM1)D8G
+KH3)Q6P
+J8C)WFH
+YT1)SDH
+CGZ)X3V
+77B)V9M
+2RJ)H4V
+NHY)H47
+89B)HM7
+Z1V)58S
+17Y)1Q7
+J3F)891
+WDG)VSZ
+PJM)21T
+3YL)74D
+8XJ)15N
+Z2X)VHH
+N6R)R93
+5QV)8XY
+KSD)RYF
+6DQ)X8F
+Z2Q)MZB
+ZFG)972
+5LK)FT3
+D25)1CF
+RMQ)2HQ
+85N)HDY
+952)WFS
+T4J)B88
+2MC)JFH
+BRL)D64
+GJ4)65N
+ZC2)QLQ
+69T)3WV
+W4F)WMG
+74D)NCN
+3YY)19K
+JKG)6CJ
+S68)GGZ
+6N6)H2P
+3XL)ZVG
+S1D)14K
+GMK)DW3
+HJF)1D5
+9DP)P9D
+18K)Z2Q
+248)YD2
+DTK)MR3
+LH8)1GZ
+7ZC)RZJ
+YJ2)ZVN
+JN1)1FX
+3WV)289
+53D)GJX
+883)FXW
+79K)ZXD
+DLH)9X5
+BRQ)KHK
+2XW)R65
+RGD)GCY
+RNC)TR9
+HYV)54C
+SJF)BBD
+T81)F2T
+GZ2)KBQ
+G2K)48L
+PL6)B5D
+R76)Z4Z
+QVK)TDX
+F6N)M6X
+8XQ)3JP
+HXD)WNB
+CLZ)37R
+K6R)SY1
+X9G)8CM
+2W9)W4X
+ZXV)JC5
+HKY)1Q4
+KV1)QZC
+LMT)CLW
+Y4M)P57
+1YS)SJF
+NGV)N1R
+VLF)RGD
+FJ5)8WN
+PWG)V4K
+XDC)KY2
+3DJ)RV8
+1RJ)2GN
+WXT)MP2
+R89)JLR
+GGB)RDG
+Z6L)GQX
+ZJQ)TLG
+3WF)FQH
+5YP)5Z3
+C1B)CCD
+SBW)BQB
+41C)W4H
+1P5)YYP
+R5X)36J
+DZL)KNW
+P57)CN4
+C85)78L
+6YB)S7R
+CYB)LNN
+881)Z5X
+642)B5K
+X9J)SQT
+BJK)M39
+BMW)SHT
+2NS)VKN
+1C2)JHT
+H46)ZGD
+JY6)RF8
+V1D)82Y
+Z4Z)FW6
+CRP)JRG
+1VX)77V
+M2F)MHH
+B7X)JJV
+H29)7JR
+Z4C)N13
+HN2)PRV
+FTN)5FY
+8HS)Z4M
+JTP)GLS
+JST)8XZ
+4GX)T2P
+1GZ)V8W
+5MW)RT4
+9G2)QPQ
+X6C)NGV
+GP8)8SY
+J67)ZBL
+R45)BWC
+DDF)S37
+31R)PHR
+V4K)2L6
+J69)SYP
+DVF)R29
+DLS)1BQ
+72W)JKH
+JPV)FL9
+TSK)69T
+93V)T9M
+CST)WPW
+37Y)BJ8
+JR2)V4Z
+B7C)X1V
+WN7)GCD
+K65)TM5
+HFS)KYB
+1XR)TX8
+7L2)NXY
+57Z)M6W
+WMG)5HG
+F6S)3YF
+FMB)N6Q
+HS4)QNV
+XN6)X2C
+56X)Z5F
+NJ1)3M8
+65K)S2S
+MSJ)Z3P
+3RW)YJQ
+YRB)L4G
+5DZ)5YP
+TB6)TGV
+PDM)H9F
+MTR)B36
+GGH)2LS
+4S6)4KV
+SVB)MV1
+JQN)18K
+SRN)ZFK
+ZFX)HXD
+YNR)GCL
+8QM)GDK
+17G)B9Y
+JKZ)19N
+MJD)5BH
+NSR)24N
+T48)CF2
+Q3R)3TZ
+741)T7M
+P2C)G9Q
+V8G)17G
+GCC)54L
+53K)TC8
+ZGD)F7V
+J5Z)Z7X
+4YV)HZV
+GPZ)69X
+RYT)RTK
+Z6T)7ZC
+FMT)ZVJ
+56X)7KS
+M89)YDR
+F6Q)V8G
+Y4V)MY7
+1Q7)17N
+YV7)HQS
+YLQ)GJ2
+5WT)VQB
+YN7)DR2
+MPX)JBC
+LFL)DPB
+TNG)5Q1
+LW7)HC8
+HBR)Q6N
+9K2)DNB
+GXN)MHW
+SGZ)1HF
+WFS)N4R
+3GN)2K4
+5Y4)1MH
+M9W)7PR
+WCK)DMQ
+COM)TKH
+6XY)LTM
+WQF)1S2
+Z6N)3BD
+CF2)LFL
+GDX)ZQ4
+PGZ)1VH
+X5D)6CP
+TDX)MKV
+3XX)BHR
+SPL)DXS
+GM5)TZR
+M8W)DBH
+PFH)KGJ
+W4H)MKN
+SPK)LRQ
+V4P)63V
+5LQ)WDG
+L2G)49J
+HB2)6Q9
+YV4)NTM
+H47)9MW
+ZB8)Y8J
+C3D)HTQ
+9HF)9K2
+XDG)GDX
+FMS)239
+JJP)PKV
+6C1)BL3
+FNX)JX4
+SN2)237
+TSD)PNN
+RY1)JL3
+TX5)B2R
+BS5)HJK
+TBS)JNC
+1BQ)PR5
+NRS)FX1
+5GX)BKC
+8Y8)FRH
+GP1)KFR
+H1W)ZLJ
+FX1)WT6
+HJK)WFT
+7Z4)GT9
+FD8)RGG
+8VZ)5PJ
+1LW)PTY
+PTT)15X
+QVZ)6LR
+Q9V)WMP
+BLW)4DX
+554)35D
+YML)DND
+997)CTW
+L2L)6WB
+PR9)K5K
+6TY)5Y4
+2RQ)DVF
+5PL)NK7
+3WB)KJ7
+PXM)HN2
+NBJ)FMB
+BGN)BRP
+BTH)C2B
+9X5)MLT
+XGJ)KGD
+TDC)SBW
+56Q)K7F
+HF3)Z2X
+RP9)952
+PKV)K4K
+222)95K
+LX9)4WG
+RYF)HB2
+5CL)C4P
+J2H)6PG
+CXP)5GB
+38R)L7N
+NJ1)YDZ
+LBC)42B
+6WB)NCK
+524)YOU
+D8X)YNZ
+KY2)BRH
+W5X)DZX
+SP9)G1J
+JKT)LGJ
+J2V)PJT
+6SS)R9G
+8MF)2L8
+X4J)8JJ
+T1P)DLS
+NWC)76R
+YXW)RMQ
+Y64)9NF
+XB5)52M
+JKP)YC1
+FZ2)ZCD
+Q3S)CWT
+YCS)QDR
+S3M)792
+Q7K)N5M
+952)MYL
+GPR)F37
+Y7G)TFK
+V7H)2G3
+CHW)BVC
+FSM)TRY
+RS7)BFX
+KF6)3RW
+TGV)6BJ
+3TP)CXP
+DXS)BW8
+8QM)NT3
+R4Z)X43
+7X3)7N7
+JJZ)3WB
+GWZ)K7Z
+XQF)R1M
+2L8)4YX
+891)F1D
+S73)KS9
+289)3TB
+XJF)PDZ
+C29)K7N
+YH5)8F3
+9NF)8LD
+YX7)1NW
+ZLJ)ZGS
+DWS)CY2
+Z4P)XBM
+HKY)K55
+P6W)BWQ
+P1H)L64
+54T)25P
+W38)6KP
+CNV)9S2
+7FS)75T
+9SV)PQQ
+H46)VL3
+3FW)W91
+JBW)T99
+J89)MLR
+CJC)4B6
+NYK)189
+R2K)3CT
+S54)BHJ
+98D)HRL
+F1T)GRQ
+T9M)NZJ
+5B2)FNX
+PQJ)D89
+WG3)2W2
+ZS9)WW8
+FSG)5SS
+DW4)ZFG
+78L)49Z
+NGQ)2TJ
+M6X)GDP
+KXR)95L
+1WQ)FNT
+BRP)L4X
+J3F)5C4
+2NB)JJD
+SZL)5PT
+FNB)DN9
+LNZ)ZBG
+Z4J)NQV
+D6J)H54
+1CF)SZF
+QQF)1N2
+FFS)VF9
+NK7)KRM
+6HY)TDQ
+C2Q)16T
+JTK)ZLR
+1KD)N3R
+2XH)JKP
+BJ8)QHR
+G9Y)5F2
+4R7)HGM
+JGH)XS7
+72G)LLM
+QLQ)Q1Y
+TJL)8JW
+N8F)8SX
+JY8)HZD
+3W9)JPV
+WK4)HBD
+8X9)6XH
+YYG)WJQ
+HZL)NQZ
+BLY)JJG
+6CH)CR4
+GQ6)248
+DWH)5LK
+LQM)Z7Q
+SN2)4DC
+BF7)BTH
+Z9S)NG8
+F5D)HK4
+2S6)5NW
+LTM)757
+FC8)89N
+SBJ)4T4
+XLM)XQR
+S29)TDC
+1YK)RL3
+6J2)7NB
+SK1)7CS
+GBD)H77
+9KL)HJF
+LJ4)VST
+S9W)4KN
+99C)Z6N
+L58)M2K
+5JS)LR8
+WR5)9XR
+V6W)WK4
+9S7)FRC
+TM8)C39
+F4Q)Y86
+BN1)MTR
+BGG)GP8
+GJN)MV8
+TLG)XYH
+83S)CHW
+Z1H)GX4
+3TB)HHX
+J3Q)JQL
+5Q1)75N
+W91)57T
+DVJ)HBR
+B6F)M9M
+WMP)5XN
+WXQ)B17
+83M)XMH
+8N9)SAN
+LVG)8ZV
+L2J)7SB
+FNT)KM7
+BPC)B9T
+1TQ)K27
+JZR)RJ4
+L9S)H93
+189)36D
+TZG)2Z4
+5LZ)HXM
+SJD)Q3S
+WJQ)D81
+GP8)GZ2
+1TP)ZNV
+X2J)837
+DJM)KDJ
+7GP)NYK
+TQ8)446
+HZL)4L8
+29G)3VP
+4LZ)XTK
+KFX)6N6
+HPM)WWQ
+X1V)KVV
+Y64)V4C
+5GN)54T
+SJ1)QS3
+DM4)83W
+KDT)ZB8
+DL7)DKC
+TML)SPL
+LC2)K1W
+MHW)5Z7
+MXT)RQN
+9KL)K9L
+M3T)YRM
+KFR)Q49
+1DJ)SN2
+F82)2J1
+PWN)5PX
+YT1)V7F
+T6S)T1F
+B8L)WB2
+Q79)LKF
+853)RTD
+KBQ)356
+HTL)54G
+43T)53D
+B5W)PH9
+7KQ)8TX
+T2Z)1WQ
+8HY)29M
+552)M74
+STR)6HX
+FRV)HMM
+45F)J7C
+4Y9)HFS
+GNN)WJ6
+HXT)JQ8
+PNN)51L
+PHR)RK5
+MM8)H1B
+N66)G85
+C4P)W7Z
+991)FSM
+7QK)SLP
+GDP)71Q
+5MC)MRG
+F2X)HY1
+B9B)CWM
+SVZ)HN8
+XDB)4P8
+BS3)VFP
+VXM)KCL
+9G6)831
+9Z8)FNJ
+GX4)C2Q
+WFB)MZ9
+63V)MX3
+V8W)82Z
+RTK)319
+427)WY1
+4T3)VVN
+T2P)4LC
+CR4)FQS
+K4L)DTK
+HLP)WCK
+4YQ)H9N
+RK5)QFW
+GT9)SRN
+YXF)FXY
+V74)L3W
+MY7)2RQ
+JLR)JNS
+9S5)LPH
+H54)J37
+8XR)BLY
+QMC)T48
+4TY)1QG
+Z4J)H82
+BZC)LKD
+4CP)86F
+Z24)L58
+1FN)X15
+5FJ)QWJ
+K27)2CD
+3Z9)3W9
+L6V)J1J
+51V)HJ2
+WD5)Q99
+49Z)G6N
+Y4V)DDF
+MFV)3GH
+B1T)9CM
+X9Z)BG5
+2M6)1XQ
+2J8)3G5
+VMB)13Z
+51S)BMW
+1MH)LFK
+VBK)3D4
+SDM)8XR
+7NX)S2K
+52L)4NL
+LRS)664
+JDD)43S
+JJV)H6X
+62K)7L2
+WR1)L3D
+LN4)WXQ
+S52)C85
+F22)9SV
+LH3)8B2
+YBD)8MY
+TGM)N6H
+ZVJ)MSN
+S2S)5HV
+2MF)GP1
+9ZP)3ZK
+1LW)H44
+QTW)T9P
+GHZ)YV7
+W7Z)M3Y
+5FK)NWC
+97X)36T
+G7X)K5R
+GLP)XQF
+WQH)ZM7
+8YP)KF6
+WNB)WG1
+W21)1TQ
+VBH)XM4
+CY5)3N6
+G1V)K1G
+L2X)L9S
+2CV)3LL
+BKC)LC8
+R5P)JDL
+JL3)T5B
+HDY)FRM
+XL2)F29
+8Y8)N86
+C8B)FDF
+L3W)Z9L
+WJ6)6FW
+5HV)157
+DW9)1WX
+C2B)JR2
+6HK)7GP
+N86)971
+GZ6)KHJ
+V4Z)376
+WT6)F4Q
+H97)FP5
+M4L)MCT
+D8G)BCQ
+XPG)NP5
+8CG)GBD
+6SD)6X3
+54L)1TP
+N1W)MJD
+ZXT)VXM
+QH7)JN5
+S7H)4M5
+QSC)44B
+19K)QLJ
+951)25C
+PJZ)W21
+X8F)X4F
+CZW)SV8
+ZYJ)F5C
+XNR)KPH
+658)47Q
+D66)3GD
+ZGK)D65
+4ZT)YBT
+3NR)K3P
+WMD)HRP
+VGN)554
+2GN)WH3
+8SX)DXJ
+Z4M)MR9
+R1V)VDY
+1D1)CRZ
+CC5)MH1
+2NS)PXH
+SLP)1FN
+PTB)LYC
+V4D)Z5M
+Z2N)X77
+DR4)7KQ
+646)98D
+9PN)F21
+PB8)728
+WXT)4S9
+3YP)TGM
+6PG)776
+9KY)T7C
+5SS)LV1
+8HR)53Z
+972)FZ2
+XJ8)9PN
+6PB)Q35
+ZCR)42N
+NNP)YPG
+SL6)XL4
+1CG)YZJ
+QKG)5GX
+L94)HD8
+ZVH)GVJ
+R93)3YL
+4GC)2XH
+FNJ)ZL5
+2LR)YBD
+YDW)HMN
+S8V)YRB
+YV2)HS4
+6B6)6WZ
+SVG)LB5
+DMQ)VWX
+72Y)997
+MHY)3YY
+JX9)XHT
+MTV)DSB
+413)6SD
+DSB)25Q
+9HF)BRG
+B5W)P93
+9TB)XTP
+JN3)6W2
+TFK)MKW
+T49)4NY
+742)MSJ
+8F6)ZKW
+TRQ)3JD
+F2T)R8H
+LQ4)GMJ
+B9T)H46
+T2F)ZC2
+VC6)TJF
+YDZ)R48
+RGG)974
+DTK)H4C
+DTF)QCP
+7KM)Z4C
+GTS)MLJ
+296)424
+664)H86
+2YP)ZYJ
+V18)VC6
+7CS)SQH
+DZS)3X8
+QYT)8HS
+62Y)SQW
+D8X)YXX
+N2X)D3B
+P84)6J2
+JPH)DZL
+WM9)KWM
+TM5)GM5
+W4X)YYR
+TNG)LRP
+1KP)ZQX
+MZ9)72Y
+WJZ)MPF
+NP5)SQ3
+D66)5QS
+H7H)ZCB
+16T)V74
+X15)1WS
+8NR)Y7N
+237)DYP
+N4Y)CGZ
+Z8K)BYX
+8KF)N6W
+RF8)NMV
+WFC)7XF
+449)DDB
+D49)X1H
+TM8)78Q
+G6N)73R
+HGM)GD7
+F21)Y1R
+TRC)5HH
+N14)S73
+ZXT)BS5
+NG8)4L5
+8ZN)Q79
+4HJ)Q3T
+837)NDT
+1R7)R2K
+77S)6YB
+S7R)1XY
+2VT)KNJ
+WQ4)64D
+M5Z)PVZ
+RQN)8V9
+VVN)K2K
+V2B)N3K
+B17)7BX
+1W5)LMT
+1YW)X2J
+XJC)XJF
+P4W)4J1
+PRS)Q4P
+BMM)QB5
+L7N)H29
+4W5)GKS
+8WN)KH8
+N4R)39M
+4NY)14W
+19Q)ZG9
+W6W)J8C
+PWZ)4RW
+8F3)JBW
+BC8)F4N
+QG8)VDP
+YG1)GBY
+KRM)WJZ
+4HL)2TH
+W1V)FMT
+1BL)NC2
+RTN)R6C
+QLJ)PLT
+SQH)93Y
+KM7)9G2
+5Z3)JY8
+WB2)YSP
+3S1)4W5
+5BH)SXV
+28Q)5Q7
+PDZ)XD1
+D79)WHF
+6BJ)DQT
+5F8)C29
+46R)XNR
+NC2)2Y8
+T5B)863
+TJF)PDM
+L47)5QW
+F59)JX9
+RK6)QG8
+GD7)RWP
+863)7DK
+97R)LJF
+6N7)X32
+WLZ)XDM
+RXH)79K
+WG1)NQW
+BNR)1P5
+ZXV)QQF
+ZJX)GSZ
+X2C)L5L
+NVC)L2G
+T1F)FK2
+GGZ)KH3
+TZC)R9K
+157)FRV
+3CX)Z1J
+NS1)BGG
+MFW)36X
+DW3)C53
+88H)LP4
+FX4)F4M
+676)7BB
+9TR)Q3H
+P5H)Z1H
+LB1)XBR
+SWS)FLP
+4S4)QMC
+KNW)5LZ
+3PR)TVL
+JYK)46F
+ZM7)Z6T
+Q99)427
+5R1)MYP
+3TZ)YHB
+QPD)L6V
+HB8)K7P
+2W2)ZFX
+BS3)GWH
+953)S2C
+1BC)WKC
+S7X)9PL
+1RQ)KLD
+1XY)JRV
+D37)SF5
+PXD)P2C
+4L4)CVV
+MYP)2VZ
+WPW)SFQ
+N6H)8D7
+8B7)9RM
+297)Q93
+LNG)R64
+BXB)NSR
+DKC)MTV
+6C1)81V
+75N)21C
+XY7)THS
+BRG)YY2
+F37)RMV
+831)LYP
+M1P)GZ6
+ZXD)NR9
+6G1)35R
+H2V)51V
+Q9F)RRD
+FXW)3XX
+ZV3)CDP
+JC5)JGH
+Y73)KFX
+V6G)1W5
+7BB)DR7
+RN7)56M
+3GV)8X9
+HMM)41C
+JK4)V1D
+MFV)2J4
+QQW)H62
+N1R)CCC
+B5T)3GV
+G8D)8QM
+JNB)Z75
+8D7)ST5
+JXX)C1B
+G5Y)Y92
+G46)DW4
+3CQ)R9L
+FR9)Q83
+N6Q)JR4
+ZG2)S4Z
+JDC)NCF
+ZLX)2XW
+JJD)QLN
+YY2)FJ5
+Z3P)W7C
+LSB)N68
+64D)8BL
+PR9)J67
+N6X)M2F
+SQ3)XZ7
+MKW)KVM
+L61)PL4
+R2Z)2BF
+HGM)KQK
+222)RJQ
+4LC)PY4
+54C)N14
+MLR)Z7Z
+BBD)W1V
+JK1)32M
+SY1)3S1
+65N)3TK
+1X9)4HQ
+6F3)H6H
+489)GFB
+Y86)52L
+HN7)R1G
+48K)5MC
+4P3)Z6L
+CHT)8R9
+3M8)HKP
+RK6)PP4
+X77)V4D
+YDR)LCG
+DZP)3CY
+75T)TKM
+ZFK)5LQ
+6R6)8NV
+TVL)RHW
+HMN)BNR
+PG2)VN1
+FVQ)SQ5
+1HF)W5X
+WVY)TGX
+VYF)2N1
+BJS)LTJ
+72V)GCC
+8NV)BS3
+ZL5)P1H
+3KR)69D
+CZS)8WW
+4N2)72G
+KK2)JXX
+5Q7)KPZ
+4QP)HYV
+1SY)V7H
+CN4)JTP
+9TC)SVG
+K7P)T6S
+QFQ)999
+NGN)QKG
+BHR)DR4
+TGX)XPG
+DY3)YG1
+M5Z)PHZ
+KBQ)HVY
+9D2)N5J
+GMF)4LZ
+1P8)BFN
+GBY)KY4
+49M)LWB
+FNZ)FFS
+JL3)V2H
+LB5)7FK
+PM5)1BL
+PHZ)LH8
+NCF)YNR
+HSK)W6W
+5RJ)C95
+RPK)ZRK
+Y34)54N
+5QW)TZ5
+KGJ)43X
+P2V)Q9T
+NQZ)L7W
+WP4)S29
+J3S)C9G
+5C2)TX5
+3PM)PK2
+3GD)393
+CCD)3Z9
+QKQ)PB8
+FCN)LRS
+FQ4)M3T
+45B)B1T
+NPJ)MK3
+KGD)JJP
+F5Y)JKZ
+C6D)HSK
+TR9)7SS
+2TX)H73
+NFV)X5D
+C2V)43T
+M6T)KPS
+PK2)1CG
+TP1)N4Y
+1D5)D9Z
+MTR)97R
+3TK)X3W
+R7T)3VC
+PHP)1LV
+5GB)2H5
+YC1)24X
+S5H)W79
+FQS)JVF
+DML)6F3
+Z75)LXP
+DMJ)29G
+54N)GSS
+RWP)D79
+VBV)XWX
+VST)CMS
+GZ2)676
+N72)FP3
+792)ZJX
+H73)J17
+M8N)WQ4
+H6X)L5G
+3VC)LBC
+YBT)YR2
+LYC)4GX
+3VP)17F
+F5Y)9ZY
+8LD)BCM
+7JR)X45
+MV8)FY7
+JN6)31R
+MZ5)CVK
+239)S7Y
+DJ3)S7H
+RVK)6HK
+G85)WR5
+LKF)TZG
+SQ5)NP4
+HN8)H53
+CTW)MCJ
+8ZV)6YF
+2RQ)SR3
+MRR)Z4P
+WQ3)TYW
+6SW)L2J
+HFC)CTH
+N5M)1TK
+757)RDF
+R5Z)MHY
+NW9)V3P
+K3P)PWN
+GD7)GDL
+B2J)FN2
+BRJ)GK8
+S62)3NT
+9BH)38R
+KQK)WXW
+2LS)T8V
+4J1)5WT
+7J5)H3D
+W1B)F72
+F4N)NFK
+QCP)4HJ
+DWH)V5B
+87N)XY7
+F13)LWC
+7VH)67W
+PMG)DY4
+JMC)WQ3
+6HY)PTT
+YJ8)DML
+9CM)DM1
+54J)DNJ
+1Q6)8ST
+CKW)XS3
+ZKW)JPL
+111)YFN
+H6W)R5Z
+THS)X4J
+DTM)PWZ
+ZH5)8PG
+JR4)Z24
+NCN)8HF
+3BD)B8L
+76R)LN4
+N3K)97M
+JJG)N1H
+5JW)P48
+YJS)XMP
+4RW)T2Z
+D65)DNY
+KWM)ZGK
+5FY)9BK
+Y8J)7DR
+5PJ)1YW
+24L)PTB
+XTR)PJZ
+LLM)QSC
+R6Z)V6W
+H62)PQJ
+HT7)V18
+6CP)S3M
+WXW)N6J
+GJX)F5Y
+Q35)QY7
+3K8)F59
+8SX)SWS
+B2R)6N7
+R8H)CRP
+CGH)HFC
+NWC)QKQ
+P9D)BLW
+NK3)YLD
+CDP)2M4
+Q39)QB9
+F2J)X7D
+J79)QHD
+VXM)948
+X7D)GLP
+NP4)Q37
+69H)K1C
+FF1)65K
+P7X)YDW
+HTK)B6F
+273)CTT
+D25)164
+QGY)DXG
+G46)BMM
+QPQ)SZL
+HM7)G7X
+VMJ)J24
+5QS)RD6
+KVV)4CP
+6W2)8KQ
+1JP)PR9
+4B2)SF1
+FX4)NNP
+2N7)ZRC
+JQ8)N1W
+LKD)83V
+345)CJC
+HVF)QYT
+Y4H)7VH
+5LR)4MJ
+S2C)FSG
+V5B)BBN
+5X5)SJ1
+MKC)NPJ
+BWL)F39
+VDZ)Z27
+7GP)YB3
+8R9)R3N
+SQW)GNG
+3X8)V2B
+D89)SM1
+Z4P)RSN
+YB3)5LR
+V4C)1JP
+FGH)FF1
+GKS)R69
+M5V)H4X
+3CY)KXM
+G4S)D5H
+12P)1YK
+3Y2)R1V
+KTZ)DQW
+KD3)L2L
+KSL)F13
+R3Z)JKT
+G9Q)1D1
+2J4)5DZ
+X3V)MM8
+Z7Y)1BC
+G1J)G4S
+W4X)LFX
+YJ6)JMV
+FP5)KN7
+PCQ)8HR
+FN2)W8G
+31P)WFB
+YXX)CYB
+NXY)77B
+NCK)Z8K
+VPX)3TG
+CN3)JY5
+HXS)WQF
+FK3)DZS
+WFT)9DP
+XZ5)F1L
+639)T81
+R26)PCQ
+2VZ)YYD
+4S9)1PZ
+HVY)V4P
+K55)K8N
+2Y8)WMD
+69T)24L
+MHH)SRP
+WPS)YWV
+9PL)NHB
+D3B)KDT
+SHT)GJN
+42N)6MG
+K9F)YDT
+N2R)FVQ
+F3Q)296
+YML)8XQ
+6YF)B9B
+R13)Y64
+DNJ)DKW
+H44)ZTP
+1Q4)5JW
+RLM)BRJ
+LMJ)8HY
+CL4)LF1
+6GW)TMM
+VTP)JWQ
+TQL)G52
+3QN)VWR
+BFN)VPX
+T39)TSK
+Z1J)S3R
+F7V)XBX
+VNC)LW7
+WM8)788
+HBD)K9F
+JQL)JGJ
+3SV)WVN
+DM1)297
+VHQ)467
+PVJ)12P
+3GH)2M6
+6MG)KD3
+1NW)4GC
+VTJ)FKC
+Q8H)P86
+5QW)BXB
+ML7)V61
+94V)NK3
+XM4)TML
+V2P)5Y3
+CR6)JKG
+7LG)S9W
+8TX)V6G
+2JY)ZG2
+DVR)57Z
+VN1)Z2R
+ZC3)N2C
+SB6)RPW
+58W)1ZX
+VFP)X6C
+JQN)ZC3
+53Z)LQM
+KWL)TP1
+HKP)4BW
+S9T)Q19
+K2K)WD5
+WLM)YV4
+SFQ)4R1
+6KP)CTQ
+V3P)XDC
+CXM)MKC
+31Y)Z62
+XHT)L7R
+FK2)S52
+LVY)HFP
+RJQ)KV1
+9S2)2LR
+NZ8)DVR
+JKH)PG2
+ZQX)3TP
+81V)9CP
+42B)WDJ
+7PB)S68
+39C)6C1
+RR8)KSZ
+XL4)RTN
+3XH)RYQ
+78Q)TP3
+GCD)5YQ
+R29)LVG
+Q3H)646
+TMM)ZLX
+4B2)WDB
+6N5)449
+3XL)NFV
+CDL)6JS
+TMC)B7C
+R1W)ZWC
+LH3)XJC
+CHH)DFJ
+1FN)MLQ
+LMT)658
+HK8)BN1
+73R)1GP
+ZQ6)6B4
+Z5X)D37
+YPG)GTK
+8SM)VL6
+W5C)C6D
+4BW)YS6
+DYP)2TX
+R9K)BRN
+KS9)L9J
+XTJ)B25
+Y23)CHB
+NHB)LG4
+L5L)7Z4
+DRK)9SL
+ST5)NVC
+2WH)DTM
+1LV)SDM
+788)256
+TW7)6TN
+6FW)3CX
+BG9)4Y9
+67W)JJ7
+2D4)FR9
+Z8K)F1J
+LTJ)31P
+R94)YJ8
+5PT)MPX
+9SL)LGR
+FKZ)9G6
+DR7)SGZ
+SM7)9KY
+TKH)8MF
+VXB)4N2
+XQR)W38
+21F)HK8
+Y3H)XLM
+DBW)M8W
+11H)853
+1WS)66W
+DW4)KNK
+NQV)SVB
+6ZZ)8YP
+ZWC)5PL
+PP4)3CQ
+T8V)THM
+J1J)HMK
+CPB)Y7G
+GYH)9BH
+WPK)FMS
+95D)FJW
+HM7)CJJ
+ZGS)LBV
+HMK)BZC
+2BF)DWS
+LWC)85N
+L3B)M1P
+7C2)WG3
+3ZK)7BM
+GDK)8XJ
+LGJ)4R6
+DL1)JSJ
+44B)6T9
+KFT)CXM
+Q4P)STR
+LBC)6ZD
+GDK)STH
+6MX)F2P
+Y92)21F
+6ZD)YYQ
+HYK)58W
+3YF)KNM
+X9G)8K2
+QWN)JQN
+17F)KTZ
+CJ4)62Y
+KQW)GMF
+15N)S9T
+G1V)GMK
+M62)X6J
+8V9)SVZ
+WW8)DJ9
+FP3)28Q
+PMX)F3Q
+N3G)56Q
+46F)ZN3
+D3M)S3P
+D64)LVY
+72Y)ZHM
+LPH)WLM
+HY1)HZL
+L3D)QPD
+Q9T)X6Z
+6HG)3DJ
+KBP)9TR
+25C)9Z8
+ZR9)RYK
+TJR)5C2
+56M)X4Y
+TL2)5CL
+939)ZVH
+595)DTF
+Z27)D25
+54T)MWM
+ZBL)W4F
+6JS)H7H
+YWV)QWN
+5D9)S5H
+P96)KZ1
+TDQ)8JZ
+NQW)VHQ
+K9L)DMJ
+H6W)8F6
+2TJ)8NJ
+MCJ)T1P
+M94)JNB
+5ZJ)9BG
+KCL)RS7
+X6J)ZGQ
+PQQ)JN6
+S2K)5FK
+K7N)X2Q
+HTQ)GW4
+LTJ)RPK
+DD2)8J5
+7NX)Z2N
+6LR)R3D
+YR2)7Y7
+JBS)CZW
+ZRK)XJ8
+4L5)3XF
+GJ2)FNZ
+XTP)YCS
+HRP)P5H
+BRJ)J89
+RD6)ZR3
+YNZ)N8F
+2N1)XGH
+JDL)DLD
+YLD)94B
+ZNV)1Q6
+6TG)CR6
+GMW)KWL
+TZR)698
+RDG)VGN
+F1D)5X5
+3CT)6CH
diff --git a/2019/inputs/day_7.txt b/2019/inputs/day_7.txt
new file mode 100644
index 0000000..b21d6af
--- /dev/null
+++ b/2019/inputs/day_7.txt
@@ -0,0 +1 @@
+3,8,1001,8,10,8,105,1,0,0,21,46,59,84,93,110,191,272,353,434,99999,3,9,101,2,9,9,102,3,9,9,1001,9,5,9,102,4,9,9,1001,9,4,9,4,9,99,3,9,101,3,9,9,102,5,9,9,4,9,99,3,9,1001,9,4,9,1002,9,2,9,101,2,9,9,102,2,9,9,1001,9,3,9,4,9,99,3,9,1002,9,2,9,4,9,99,3,9,102,2,9,9,1001,9,5,9,1002,9,3,9,4,9,99,3,9,102,2,9,9,4,9,3,9,102,2,9,9,4,9,3,9,102,2,9,9,4,9,3,9,102,2,9,9,4,9,3,9,101,1,9,9,4,9,3,9,102,2,9,9,4,9,3,9,101,2,9,9,4,9,3,9,101,2,9,9,4,9,3,9,1001,9,1,9,4,9,3,9,101,2,9,9,4,9,99,3,9,102,2,9,9,4,9,3,9,1002,9,2,9,4,9,3,9,1002,9,2,9,4,9,3,9,1001,9,1,9,4,9,3,9,1001,9,2,9,4,9,3,9,101,1,9,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,1001,9,2,9,4,9,99,3,9,101,1,9,9,4,9,3,9,1001,9,1,9,4,9,3,9,101,1,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,1001,9,1,9,4,9,3,9,102,2,9,9,4,9,3,9,101,1,9,9,4,9,99,3,9,1001,9,1,9,4,9,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,1001,9,2,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,1001,9,1,9,4,9,3,9,102,2,9,9,4,9,99,3,9,102,2,9,9,4,9,3,9,1002,9,2,9,4,9,3,9,1002,9,2,9,4,9,3,9,1001,9,1,9,4,9,3,9,101,1,9,9,4,9,3,9,102,2,9,9,4,9,3,9,1002,9,2,9,4,9,3,9,101,2,9,9,4,9,3,9,1002,9,2,9,4,9,3,9,1001,9,2,9,4,9,99
diff --git a/2019/inputs/day_8.txt b/2019/inputs/day_8.txt
new file mode 100644
index 0000000..21110e8
--- /dev/null
+++ b/2019/inputs/day_8.txt
@@ -0,0 +1 @@
+211202121222222222221222212222202022222222222122221220222222222222222222222202222222222222122121022222212222222222212212222222210222202212222222012222200222021222222222220222222222202222222222222022220221222222222222222222222222222222222222022022022222222222222222222212222222221222222202220222202222220202021222222222221222202222212222222222222122222220222222222222222222222222222222222222122220022222212222222222202222222222220222202212221222102222211202020222222222221222222222212222222222222022220221222222222222222222222212222222222222122022122222202222222222212202222222212222202212222222202222220222022222222222221222212222202022222222222222221220222222222222222222222212222222222222022122222222222222222222202202222222220222222202222222212222210002122222222222221222212222222022222222222122221221222222222222222212222202222222222222022220222222202222222222212222222222221222222222220222112222211012121222222222222222222222222221222222222122220222222222222222222212222212222222222222022120222222222222222222212202222222221222212202221222122222212122121222222222222222212222122022222222222222221220222222222222222212222212222220222222122021022222222222222222212202222222221222222202220222102222200212020222022222222222212222012221222222222122221221222222222222222212222202222222222222222121122222212222222222212212222222221222212222222222111222212022021222122222220222202222022022222222222122220221222222222222222202222222222222222222122120222222222222222222202212222222210222212212221222020222201222222222022222222222222222122222222222222022221220222222222222222202222212222222222222222222022222222222222222202222222222221222212202221222002222220202020222122222220222202222112221222222222022220222222222222222222222222212222220222222022120022222212222022222202202222222200222202202221222210222220022122222222222222222212222022021222222222222220221222222222222222202222202222221222222222020122222212220122222202212222222201222202212221222112222220002222222022222220222222222122121222222222022222221222222222222222212222202222201222222222120222222222221222222222202222222212222202222220222101222200212021222022222221222202222122222222222222222221220222222222222222222222212222210222222022022122222222220022222202202222222222222222222222222220222221022022222122222220222222222012020222220222122220221222222222222222212222212222212222222222220022222212222022222212222222222212222212212221222011222222012022222122222220222202222220122222222222122220221222222222222222222222212222221222222122020022222222222222222222222222202220222202212220222022222212102221222122222222222202222112021222222222022222220222222222222222222222222222202222222022120020222212221022222202202222212210222212202220222211222210102220222222222220222222222120122222222222022220220222222222222222222222222222202222222222222120222222220122222222202222202200222202222222222220222200012022222122222220222202222220122222222222122220222222222222222222202222212222220220222122122022222212222022222222222222202201222212212221222221222212122221222022222220222200222112022222222222222220020222222222222222202222202222220221222222020222222202221122222212212222212212222222212221222212222211012221222022222222222220222201121222220222022222021222222222222222212222222222200221222122220221222202220122222222202222222211222222202220222022222212002120222222222220222220222100222222221222022222122222222202222222212222212222221222222022121122222202222022222202202222212200222222202220222010222212102222222002222221222221222011022222222222022222120222222202222222222222212222210221222022221021222212220222222202212222212202222222202220222001222220012020222112222222222221222121122222220222122220020222222212222222212222212222220222222122022221222202220022222222202222222210222202202220222010222211022120222212222221222220222202120222221222122221122222222220222222202222202222210221222222221122222222220022222202212222202201222202212220222012222200212022222122222222222222222212222222222222122220121222222210222222202222212222201220222122121122222222222022222222222222212210222212212220222200222200012122222112222221222202222201220222222222222221221222222201222222212222222222210220222222122121222222221022222222222222212220222202212220222202222202012220222212222220222201222010121222220222222220020222222201222222212222212222220220222222122221222222221022222202202222202202222212222220222211222201112021222012222220222221222101121222220222222221121222222201222222212222202222022220222022221122222222222122222212222222222201222222222222222220222201202122222102222222222201222102220222222222122220222222222220222222222222202222211222222122120221222212221122222212202222202200222222222222222020222222222121222222222222222212222012021202222222022220021222222222222222202222222222200220222022221020222212220122222202222222222221222222212220212220222210122220222222222222222212222110222212220222222220021222222212222222222222212222001221222122020021222212222022222202202222212212222222202222212102222210022121222102222121222210222021121202221222122221022222222210222222222222202222001221222222121120212222220022222202212222202220222222212222212012222200022221222022222020222200222222122222221222022222122222222201222222202222202222110222222122221121222202221222222222202222222222222222202222212220222220202121222222222121222201222111221212221222022220120222222210222222202222212222202222222020021020202212222122222202212222202211222222202221212002222212122222222022222121222202222102121212221222022220022222202200222222212220222222211222222121221021222222221022222202222222222212222222202222212010222202102121222022222120222220222201021202222222022222222222222220222222212221212222200221222122221120222212221122222222222222202201222222212222212222222221222120222002222121222201222100021222221222222222120222212211222222222222202222001221222022020122210222221022222222212222222212222202222222212120222202022221222122202122222221222002221212222222022222222222202200222222212220222222111221222122221220210212221022222222202222212202222212212221222010222222102222222002220020222210222212120222222222022220022222202212222222222222212222002222222220121221210202221122222212212222222222222202202222202122222200222111222122220122222210222000020202221222022222221222222222222222202222212222211220222022220020212222220222222212212222222211222212212220202200222222102112222222222222222221222112021222221222222221222222222200222222202221222222212221022020220022220202222122222222202222210222222212202222202122222220112100222002200020222212222010120202220222022221020222212210222222202220202222011220220121121022022222221222222202212222222222222202222220222221222211012110222102221021222222222200220002222222022220121222212201222222202222212222212222221120220020121202222222222222202222222220222222212222202210222200022210222212220122222221222012220102220222222022221222212222222222202221212222021222022122222121012212222022222222222222200222222212212222212202222221102110222012212122222220222001222202221222222120021222212201222222212222222222011221120020221220111202220022222222202222201221222222222220202110222202012021222122220020222202222121220002222222122122122222222222222222212221212222220221122120020221110202222122222222212222212210222212112222222010222200112110222022222121222221222212020002220222222222121222202211222222212220202222222222220122120121011222221222222202202222222220222212102221222101222210222002222110221222202211222001021022222222022121220222212221222222222220222222012221121121021020121202220221222202212222001220222212112222202210222220212101222110211020222202222000220022222222122020222222222221222222222220222222022221122121121222002222221221222222202222210210222212212222202101222211102022222100220120212220222010020102220222222020222222222211222222202220222222221220121001022021110222221221222222222222011222222222022221202000222221022201222200221221010200222011220202220222022220220222212202222222222221222222212221220221220021210202221120222202012222112221222222022220202111222222102112222200220121110202222011020112221222222122101222212220222222202222202222101222222121122220001212221121222222202222220222222202112221222200212212112110222201201020101220222000220002221222022220011222212211222222202222202222012222122001122022210222220222222222022222222220222212102221222120202221202010222011201220010212222001221212220222122121100222222222222222212220212221001220221001120220221212221120222212002222010212222212222220202200212212112022222020220022001201222000020222222222122121002222202220222222212222202221200222220112120122211222222122222222212222012210222202212221212121212201202110222002200220211201222210022222220222122222010222222222222222222220212222122220222222122122200222221122222222012222221201222222112221212002212211022212222122211121222210222212222112222222022222211222220210222222222221222222102221221211022121110222222020222222012222201212222212202221212110222202102021222210211222210221222010020212021222022221021222200212222222222221202200111221121110122021020202221222222222202222022121222212012220212212212202212122222021220020120222222202122102220222122021211222201111222222222221212220101222022200022120002222222220222222002222022110222202202221222202222212202221222120220021210202222020122102020222022020102222220112022222202220202210100222122221122022202202222221222212012222110001222212202221212202212222212100222220211121101220222210021002122222022222222222212102222222202221222200002221020021022022002212222121222212112222100100212212112222202212222212002220220100211220102211222020021012120222022221222222211222022222202220212220102221021111020021201202220120222202222222012200212202102221212212202211022221222121212020221210222210100202222222122220212222201102022222222220212202000221222202222120212212221122222212102222111010222212122222202210212212002120221202221222002200222212020022221222022120000222210211122222202221212220012222022212020121120212222222222202112222111011202202022220202220212212002201220002212021002200222122222112221222122121222222210211222222222220222200111221020122122022121202220121222222022222220210212222022222222020222202022102221222202120112212222200112212020222122122111222212020222222202220212211101221222211221220120202220120222212102222120222222202102222222021202221122212222010210021122210222102120022220222122222210222202220122222202220222220001222020211220220020212220221022212222122010102212212222221202112222220002220221101212221021211222221200202021222222222012222221011222222222220222220222221120112221221012212220122222212022122122101222202022221212020212210022112221000220221102221222100120022221222022022001222210212022222222220222202220222222120121022002202221220222212012122200201202222202222222210212201012011221020221222212222222200220202122222022220102222222011222222212222222202012221221100221121212212222222122212112122222002202202112222222002212202212212221112220221111211222201000122121222122022020222201010222222202222212202221220122120120120120212221021222202012122021021212222112222212112210200122222220002212220112210222110021012022222222021021222212011122222222220202220110221020202121022212202221022022212212222101020222202202222222000222201202110221200222222010201212200221222022222222020000222201112222222220221212222012221120111220022102212221122122222112222012122222222122221202200222212122101221210210022001221222112122222122222122221111222212002222222210221212201120211021110120021201222222021022202022022101000222200022222212120220201212210221210222220222220212011221202220222222122000222210120022222220221202222021210020120120020221222221221122222122222202222222201022221210112212222122122220110202121112202222210022112022222122020122021210212222222011221222210010221222221022222121222221120122222122022012022202202012222222210200201002012221012221020200220202120211102222222222022110022202001122222112220212211120221222200221021020212220222122222112122201111202212102221220010200211002101221111211120121222212120102222022222222022000222212220022222021222212221012212122120021021100202222022222212012222002221222000002221212121201220222010222012210122002211202202201202020222222121101212202112122222212221102211011222120012221221210222221222122202122122212122202022102222202010221201002010221121210020102211222210220112021222122020221200210202222222200222122221200201222121122221112202222121022202022122001102222022112221220120222201212200221011200221212220202200211102020222022122212101221022022221122220112210220212220112222121012222222222222212012022201202212122212200200122210211122100222002210021201200222212202012021222222120112001220220122221102220012221201220221120002022011202221220022202212122210002202001202220212110222222002201221111222221220200212122022222220222222020120010211200022222212221212202110210222110000221120222220220222222102022122211222010222211221202202220112001222010211201201211222112002222220212222220112202221122222220101020022002211202221112210022212022220021120212202122122220222122001202222012201202102100221112210110120210212222111222222212022020111000222122022221202220002111220212121222222221020102222222222212222222222001222020022211221221200221012212220222202212101211222120010222121200022020200002210210222222102221022200220222020210212201101202221121021202122122220110212101100220220101202210202201220121200102211210212201122022020201022020000221202200122221011222012001022221022002211101122122221222120202202222222101212212201210220202211212102222222200200012220011212121100022222201122021212200201001122222022020012120011002222021201010021122221121022202122122110122222211021220200212202222222220221020200001011010202122210002020202022021012002202201222220011022110210112121221222112102000122221220220220012222102002202101112221211222210222222020022210210120112200222211111122021220122022002000211020022222010020022201021221121000100000202212221022021212112222202112212222222200221021200222102100121121221221010212202102200012220212120022212102222011022220220220211200121211220211001122222102221221020202202222010121212200100221202012222212112011222020210010010221212122200102022220221020002000212022122221202021122000112210021200010000210222220120121201122222021102212102111222201121202201202002020120200201212110202101010102022200121222211012221121122221000122021100210212222122211220212102221020122210202222110002212200011201200021201220022012110200222202010110002212220010120010022120110012200120022222122021212000212022122022010021101012221222020212102122120000212202002202202222222210012200102200200111220022112012202102021122021120011121200020122220001221102112201201020102122212202112220122122212222022110111222010201211210002212202112020020222212100211112122120200002020201020021202021200200022222010120111011000012120121101212002212222122121200022022212122202211001220201122201201012022011111200001112022002112002200220221121202120002212010122222010222121211010100220111112122101222222021021211212122121120212202000200210112220002211221002010102121110201000000011200112100002201220112102201101001200002222202202212002201221110202000102001202000200100102121000220100101111222110
diff --git a/2019/inputs/day_9.txt b/2019/inputs/day_9.txt
new file mode 100644
index 0000000..6ec0b92
--- /dev/null
+++ b/2019/inputs/day_9.txt
@@ -0,0 +1 @@
+1102,34463338,34463338,63,1007,63,34463338,63,1005,63,53,1101,0,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,1102,23,1,1004,1102,1,26,1000,1102,897,1,1028,1101,27,0,1012,1102,33,1,1001,1102,32,1,1007,1101,39,0,1005,1101,0,29,1018,1101,0,0,1020,1101,1,0,1021,1101,0,21,1002,1102,1,35,1014,1101,0,36,1009,1102,1,38,1006,1102,1,251,1024,1102,28,1,1017,1102,37,1,1008,1102,1,329,1026,1102,25,1,1011,1102,31,1,1013,1102,892,1,1029,1102,242,1,1025,1102,1,881,1022,1102,22,1,1003,1102,874,1,1023,1101,20,0,1016,1101,24,0,1019,1101,0,326,1027,1101,0,34,1015,1102,1,30,1010,109,-2,2102,1,7,63,1008,63,36,63,1005,63,205,1001,64,1,64,1105,1,207,4,187,1002,64,2,64,109,9,21101,40,0,6,1008,1013,43,63,1005,63,227,1105,1,233,4,213,1001,64,1,64,1002,64,2,64,109,26,2105,1,-9,4,239,1001,64,1,64,1106,0,251,1002,64,2,64,109,-15,1205,2,263,1105,1,269,4,257,1001,64,1,64,1002,64,2,64,109,-9,2102,1,0,63,1008,63,36,63,1005,63,295,4,275,1001,64,1,64,1106,0,295,1002,64,2,64,109,-14,1207,10,38,63,1005,63,311,1105,1,317,4,301,1001,64,1,64,1002,64,2,64,109,28,2106,0,4,1106,0,335,4,323,1001,64,1,64,1002,64,2,64,109,-8,1206,6,351,1001,64,1,64,1106,0,353,4,341,1002,64,2,64,109,-1,2107,33,-7,63,1005,63,369,1106,0,375,4,359,1001,64,1,64,1002,64,2,64,109,-9,2108,26,-1,63,1005,63,395,1001,64,1,64,1106,0,397,4,381,1002,64,2,64,109,3,1201,-2,0,63,1008,63,38,63,1005,63,419,4,403,1105,1,423,1001,64,1,64,1002,64,2,64,109,-13,2101,0,9,63,1008,63,23,63,1005,63,445,4,429,1105,1,449,1001,64,1,64,1002,64,2,64,109,11,1208,1,32,63,1005,63,471,4,455,1001,64,1,64,1106,0,471,1002,64,2,64,109,17,21108,41,38,-4,1005,1019,487,1105,1,493,4,477,1001,64,1,64,1002,64,2,64,109,6,1206,-9,511,4,499,1001,64,1,64,1106,0,511,1002,64,2,64,109,-23,21102,42,1,8,1008,1014,42,63,1005,63,533,4,517,1106,0,537,1001,64,1,64,1002,64,2,64,109,-3,2107,36,5,63,1005,63,555,4,543,1106,0,559,1001,64,1,64,1002,64,2,64,109,-6,1202,5,1,63,1008,63,21,63,1005,63,581,4,565,1106,0,585,1001,64,1,64,1002,64,2,64,109,1,1208,10,40,63,1005,63,605,1001,64,1,64,1106,0,607,4,591,1002,64,2,64,109,7,1201,0,0,63,1008,63,42,63,1005,63,631,1001,64,1,64,1106,0,633,4,613,1002,64,2,64,109,1,21107,43,42,7,1005,1013,649,1105,1,655,4,639,1001,64,1,64,1002,64,2,64,109,7,21108,44,44,3,1005,1016,677,4,661,1001,64,1,64,1106,0,677,1002,64,2,64,109,-7,21102,45,1,9,1008,1015,44,63,1005,63,701,1001,64,1,64,1106,0,703,4,683,1002,64,2,64,109,13,21101,46,0,-7,1008,1012,46,63,1005,63,729,4,709,1001,64,1,64,1105,1,729,1002,64,2,64,109,-13,2101,0,3,63,1008,63,33,63,1005,63,753,1001,64,1,64,1106,0,755,4,735,1002,64,2,64,109,14,1205,1,773,4,761,1001,64,1,64,1105,1,773,1002,64,2,64,109,-23,1202,10,1,63,1008,63,30,63,1005,63,797,1001,64,1,64,1105,1,799,4,779,1002,64,2,64,109,13,2108,22,-7,63,1005,63,817,4,805,1106,0,821,1001,64,1,64,1002,64,2,64,109,-11,1207,5,24,63,1005,63,843,4,827,1001,64,1,64,1105,1,843,1002,64,2,64,109,11,21107,47,48,7,1005,1017,861,4,849,1106,0,865,1001,64,1,64,1002,64,2,64,109,15,2105,1,-2,1001,64,1,64,1106,0,883,4,871,1002,64,2,64,109,10,2106,0,-7,4,889,1106,0,901,1001,64,1,64,4,64,99,21102,1,27,1,21102,1,915,0,1105,1,922,21201,1,28510,1,204,1,99,109,3,1207,-2,3,63,1005,63,964,21201,-2,-1,1,21102,1,942,0,1106,0,922,22102,1,1,-1,21201,-2,-3,1,21101,957,0,0,1106,0,922,22201,1,-1,-2,1105,1,968,21202,-2,1,-2,109,-3,2106,0,0
diff --git a/2019/readme.org b/2019/readme.org
new file mode 100644
index 0000000..c674de4
--- /dev/null
+++ b/2019/readme.org
@@ -0,0 +1,26 @@
+* Advent of Code 2019
+
+** Personal challenge
+
+Try to keep the solution pure. Only main can do IO things, like return
+different results when it's called differently. The rest of the
+program should only be pure expressions.
+
+** Optimizations
+
+- Limit the use of statements. Try to use expressions instead, or move
+ the statement out to a function.
+
+** Findings
+
+- Having iterators that you can't clone (like stdin) makes certain
+ things difficult. Eg, doing part 1 and 2 together.
+- Using "new type" structs can be a pain. derive_more crate made most
+ of that pain go away.
+- With immutable types, 'reset the machine to try again' type
+ constraints were handled for free. This made many later puzzles easier.
+- The 'no statement' constraint meant that some functions ended up
+ nested in a way that makes it harder to name and read.
+- The persistent data structures don't integrate with Rayon iterators.
+- Easier to test subsets, but harder to inspect and audit runtime behaviour.
+- Although it isn't frequently used, Rust supports functions inside functions.
diff --git a/2019/src/bin/day_1.rs b/2019/src/bin/day_1.rs
new file mode 100644
index 0000000..572d287
--- /dev/null
+++ b/2019/src/bin/day_1.rs
@@ -0,0 +1,93 @@
+use derive_more;
+use std::io;
+use std::io::prelude::*;
+use std::iter;
+use std::process;
+
+use structopt::StructOpt;
+
+#[derive(Debug, StructOpt)]
+#[structopt(name = "Day 1: The Tyranny of the Rocket Equation")]
+/// Calculates the fuel needed for your rocket to save Santa.
+///
+/// The weight of each module is read from stdin, one module weight
+/// per line. See https://adventofcode.com/2019/day/1 for details.
+struct Opt {
+ /// Includes the weight of fuel
+ #[structopt(short = "i", long = "include-fuel-weight")]
+ include_fuel_weight: bool,
+}
+
+fn main() {
+ let stdin = io::stdin();
+ let opt = Opt::from_args();
+
+ let input = stdin.lock().lines().map(|l| match l {
+ Ok(s) => match s.parse::<Module>() {
+ Ok(module) => module,
+ Err(e) => {
+ eprintln!("Invalid input \"{}\": {}", s, e);
+ process::exit(1);
+ }
+ },
+ Err(e) => {
+ eprintln!("Error reading input: {}", e);
+ process::exit(1);
+ }
+ });
+
+ println!("{}", fuel_required(input, opt.include_fuel_weight))
+}
+
+fn fuel_required(it: impl Iterator<Item = Module>, include_fuel_weight: bool) -> Fuel {
+ it.map(if include_fuel_weight {
+ Module::fuel_including_fuel_weight
+ } else {
+ Module::fuel_excluding_fuel_weight
+ })
+ .sum()
+}
+
+#[derive(Debug, derive_more::FromStr, Clone, Copy)]
+struct Module {
+ weight: Weight,
+}
+
+impl Module {
+ fn fuel_excluding_fuel_weight(self) -> Fuel {
+ self.weight.required_fuel()
+ }
+
+ fn fuel_including_fuel_weight(self) -> Fuel {
+ iter::successors(Some(self.weight.required_fuel()), |fuel| {
+ if fuel.is_zero() {
+ None
+ } else {
+ Some(fuel.weight().required_fuel())
+ }
+ })
+ .sum()
+ }
+}
+
+#[derive(Debug, derive_more::FromStr, Clone, Copy)]
+struct Weight(u32);
+
+impl Weight {
+ fn required_fuel(self) -> Fuel {
+ Fuel((self.0 / 3).saturating_sub(2))
+ }
+}
+
+#[derive(Debug, derive_more::Add, derive_more::Sum, Clone, Copy, derive_more::Display)]
+struct Fuel(u32);
+
+impl Fuel {
+ fn weight(self) -> Weight {
+ Weight(self.0)
+ }
+
+ fn is_zero(self) -> bool {
+ self.0 == 0
+ }
+}
diff --git a/2019/src/bin/day_10.rs b/2019/src/bin/day_10.rs
new file mode 100644
index 0000000..f25c3d2
--- /dev/null
+++ b/2019/src/bin/day_10.rs
@@ -0,0 +1,158 @@
+use aoc2019::*;
+use std::io;
+use std::io::prelude::*;
+use std::iter::FromIterator;
+use std::process;
+use structopt::StructOpt;
+
+#[derive(Debug, StructOpt)]
+#[structopt(name = "Day 10: Monitoring Station")]
+/// Finds the asteroid with the best view of the other asteroids. If
+/// an n is provided, then it will print the nth asteroid destroyed by
+/// a laser from the asteroid with the best view. Otherwise, it will
+/// print the number of asteroids visible.
+///
+/// Takes a map of asteroids in on stdin.
+///
+/// See https://adventofcode.com/2019/day/10 for details.
+struct Opt {
+ /// indexed from 0
+ #[structopt(short = "n")]
+ n: Option<usize>,
+}
+
+fn main() {
+ let opt = Opt::from_args();
+ let stdin = io::stdin();
+ let map: AsteroidMap = stdin
+ .lock()
+ .lines()
+ .map(|l| exit_on_failed_assertion(l, "Error reading input"))
+ .collect();
+
+ match opt.n {
+ Some(n) => println!("{:?}", map.nth_destroyed_asteroid(n)),
+ None => println!("{}", map.best_asteroid_line_of_sight_count()),
+ };
+}
+
+fn exit_on_failed_assertion<A, E: std::error::Error>(data: Result<A, E>, message: &str) -> A {
+ match data {
+ Ok(data) => data,
+ Err(e) => {
+ eprintln!("{}: {}", message, e);
+ process::exit(1);
+ }
+ }
+}
+
+#[derive(Debug)]
+struct AsteroidMap {
+ asteroids: Vec<Asteroid>,
+}
+
+impl FromIterator<String> for AsteroidMap {
+ fn from_iter<T: IntoIterator<Item = String>>(iter: T) -> Self {
+ AsteroidMap {
+ asteroids: iter
+ .into_iter()
+ .enumerate()
+ .flat_map(move |(y, line)| {
+ line.chars()
+ .enumerate()
+ .map(move |(x, c)| (x, y, c))
+ .collect::<Vec<_>>()
+ })
+ .filter(|(_x, _y, c)| *c == '#')
+ .map(|(x, y, _x)| Asteroid {
+ x: x as i32,
+ y: y as i32,
+ })
+ .collect(),
+ }
+ }
+}
+
+impl AsteroidMap {
+ fn best_asteroid_line_of_sight_count(&self) -> usize {
+ self.optimal_view_asteroid()
+ .map(|a| self.count_visible_from(&a))
+ .unwrap_or(0)
+ }
+
+ fn nth_destroyed_asteroid(&self, n: usize) -> Option<Asteroid> {
+ self.optimal_view_asteroid()
+ .and_then(|source| self.nth_destroyed_asteroid_from(&source, n))
+ }
+
+ fn nth_destroyed_asteroid_from(&self, source: &Asteroid, n: usize) -> Option<Asteroid> {
+ if self.asteroids.len() - 1 < n {
+ None
+ } else if self.count_visible_from(source) >= n {
+ sort_by_key(
+ self.asteroids
+ .iter()
+ .filter(|b| self.has_line_of_sight(source, b)),
+ |b| (source.angle_to(b) * 100000.) as i32,
+ )
+ .nth(n)
+ .cloned()
+ } else {
+ self.remove_visible_to(source)
+ .nth_destroyed_asteroid_from(source, n - self.count_visible_from(source))
+ }
+ }
+
+ fn optimal_view_asteroid(&self) -> Option<Asteroid> {
+ self.asteroids
+ .iter()
+ .max_by_key(|a| self.count_visible_from(a))
+ .cloned()
+ }
+
+ fn count_visible_from(&self, a: &Asteroid) -> usize {
+ self.asteroids
+ .iter()
+ .filter(|b| a != *b && self.has_line_of_sight(a, b))
+ .count()
+ }
+
+ fn remove_visible_to(&self, source: &Asteroid) -> AsteroidMap {
+ AsteroidMap {
+ asteroids: self
+ .asteroids
+ .iter()
+ .filter(|b| self.has_line_of_sight(source, b))
+ .cloned()
+ .collect(),
+ }
+ }
+
+ fn has_line_of_sight(&self, a: &Asteroid, b: &Asteroid) -> bool {
+ a != b
+ && !self.asteroids.iter().any(|c| {
+ a != c
+ && b != c
+ && a.angle_to(b) == a.angle_to(c)
+ && a.distance_squared(b) > a.distance_squared(c)
+ })
+ }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq)]
+struct Asteroid {
+ x: i32,
+ y: i32,
+}
+
+impl Asteroid {
+ fn angle_to(&self, other: &Asteroid) -> f32 {
+ ((self.x as f32 - other.x as f32).atan2(other.y as f32 - self.y as f32)
+ + std::f32::consts::PI)
+ % (2. * std::f32::consts::PI)
+ }
+
+ fn distance_squared(&self, other: &Asteroid) -> i32 {
+ (self.x - other.x).pow(2) + (self.y - other.y).pow(2)
+ }
+}
diff --git a/2019/src/bin/day_11.rs b/2019/src/bin/day_11.rs
new file mode 100644
index 0000000..da3e1fd
--- /dev/null
+++ b/2019/src/bin/day_11.rs
@@ -0,0 +1,205 @@
+use aoc2019::*;
+use rpds::list;
+use rpds::list::List;
+use rpds::RedBlackTreeMap;
+use std::fmt;
+use std::io;
+use std::io::prelude::*;
+use std::iter;
+use std::process;
+use structopt::StructOpt;
+
+#[derive(Debug, StructOpt)]
+#[structopt(name = "Day 11: Space Police")]
+/// Calculates how many blocks a painting robot would paint.
+///
+/// Takes the program to run on the robot in on stdin.
+///
+/// See https://adventofcode.com/2019/day/11 for details.
+struct Opt {
+ /// debug mode prints the size of the painted area on a black background
+ #[structopt(short = "d", long = "debug")]
+ debug: bool,
+}
+
+fn main() {
+ let opt = Opt::from_args();
+ let stdin = io::stdin();
+ let program: IntcodeProgram = stdin
+ .lock()
+ .split(b',')
+ .map(|x| exit_on_failed_assertion(x, "Error reading input"))
+ .map(|x| exit_on_failed_assertion(String::from_utf8(x), "Input was not valid UTF-8"))
+ .map(|x| exit_on_failed_assertion(x.trim().parse::<Intcode>(), "Invalid number"))
+ .collect::<IntcodeProgram>();
+
+ let finished_robot = exit_on_failed_assertion(
+ Robot::new(program, !opt.debug).execute(),
+ "Robot encountered an error",
+ );
+ if opt.debug {
+ println!("{}", finished_robot.canvas.size());
+ } else {
+ println!("{}", finished_robot);
+ }
+}
+
+fn exit_on_failed_assertion<A, E: std::error::Error>(data: Result<A, E>, message: &str) -> A {
+ match data {
+ Ok(data) => data,
+ Err(e) => {
+ eprintln!("{}: {}", message, e);
+ process::exit(1);
+ }
+ }
+}
+
+#[derive(Debug, Clone)]
+struct Robot {
+ program: IntcodeProgram,
+ position: (i32, i32),
+ facing: Direction,
+ canvas: RedBlackTreeMap<(i32, i32), bool>,
+ background: bool,
+}
+
+impl fmt::Display for Robot {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ (self.min_white_y()..=self.max_white_y())
+ .map(move |y| {
+ (self.min_white_x()..=self.max_white_x())
+ .map(move |x| (x, y))
+ .map(|coord| self.canvas.get(&coord).cloned().unwrap_or(self.background))
+ .map(|c| write!(f, "{}", if c { '#' } else { ' ' }))
+ .collect::<fmt::Result>()
+ .and_then(|_| writeln!(f, ""))
+ })
+ .collect()
+ }
+}
+
+#[derive(Debug, Clone)]
+enum Direction {
+ Up,
+ Down,
+ Left,
+ Right,
+}
+
+impl Robot {
+ fn new(program: IntcodeProgram, background: bool) -> Robot {
+ Robot {
+ program: program.run_to_termination_or_input(),
+ position: (0, 0),
+ facing: Direction::Up,
+ canvas: RedBlackTreeMap::new(),
+ background,
+ }
+ }
+
+ fn execute(&self) -> Result<Robot, IntcodeProgramError> {
+ iter::successors(Some(self.clone()), |robot| Some(robot.next()))
+ .find(|robot| {
+ robot.program.error.is_some()
+ || (robot.program.halted && robot.program.output.is_empty())
+ })
+ .unwrap() // infinite iterator won't terminate unless this is Some
+ .as_result()
+ }
+
+ fn as_result(&self) -> Result<Robot, IntcodeProgramError> {
+ match self.program.error {
+ Some(ref error) => Err(error.clone()),
+ None => Ok(self.clone()),
+ }
+ }
+
+ fn next(&self) -> Robot {
+ match (
+ self.program.output.get(0).map(intcode_to_bool),
+ self.program.output.get(1).map(intcode_to_bool),
+ ) {
+ (Some(paint), Some(rot)) => Robot {
+ program: self
+ .program
+ .with_cleared_output()
+ .with_input(list![bool_to_intcode(
+ self.canvas
+ .get(&self.facing.rotate(rot).move_position(self.position))
+ .cloned()
+ .unwrap_or(self.background),
+ )])
+ .run_to_termination_or_input(),
+ position: self.facing.rotate(rot).move_position(self.position),
+ facing: self.facing.rotate(rot),
+ canvas: self.canvas.insert(self.position, paint),
+ background: self.background,
+ },
+ _ => Robot {
+ program: self
+ .program
+ .with_input(list![bool_to_intcode(
+ self.canvas
+ .get(&self.position)
+ .cloned()
+ .unwrap_or(self.background),
+ )])
+ .run_to_termination_or_input(),
+ ..self.clone()
+ },
+ }
+ }
+
+ fn min_white_x(&self) -> i32 {
+ self.white_blocks().map(|(x, _y)| x).min().unwrap_or(0)
+ }
+ fn min_white_y(&self) -> i32 {
+ self.white_blocks().map(|(_x, y)| y).min().unwrap_or(0)
+ }
+ fn max_white_x(&self) -> i32 {
+ self.white_blocks().map(|(x, _y)| x).max().unwrap_or(0)
+ }
+ fn max_white_y(&self) -> i32 {
+ self.white_blocks().map(|(_x, y)| y).max().unwrap_or(0)
+ }
+
+ fn white_blocks<'a>(&'a self) -> impl 'a + Iterator<Item = (i32, i32)> {
+ self.canvas
+ .iter()
+ .filter(|(_, val)| **val)
+ .map(|(coord, _)| coord)
+ .cloned()
+ }
+}
+
+impl Direction {
+ fn rotate(&self, clockwise: bool) -> Direction {
+ use Direction::*;
+
+ if clockwise {
+ match self {
+ Up => Right,
+ Right => Down,
+ Down => Left,
+ Left => Up,
+ }
+ } else {
+ match self {
+ Up => Left,
+ Left => Down,
+ Down => Right,
+ Right => Up,
+ }
+ }
+ }
+
+ fn move_position(&self, position: (i32, i32)) -> (i32, i32) {
+ use Direction::*;
+ match self {
+ Up => (position.0, position.1 + 1),
+ Down => (position.0, position.1 - 1),
+ Left => (position.0 - 1, position.1),
+ Right => (position.0 + 1, position.1),
+ }
+ }
+}
diff --git a/2019/src/bin/day_12.rs b/2019/src/bin/day_12.rs
new file mode 100644
index 0000000..7e42f4c
--- /dev/null
+++ b/2019/src/bin/day_12.rs
@@ -0,0 +1,205 @@
+use std::io;
+use std::io::prelude::*;
+use std::iter;
+use std::num::ParseIntError;
+use std::ops;
+use std::process;
+use std::str::FromStr;
+use structopt::StructOpt;
+
+#[derive(Debug, StructOpt)]
+#[structopt(name = "Day 12: The N-Body Problem")]
+/// Simulates N bodies, physically interacting
+///
+/// See https://adventofcode.com/2019/day/12 for details.
+struct Opt {
+ #[structopt(short = "n")]
+ n: Option<u64>,
+}
+
+fn main() {
+ let stdin = io::stdin();
+ let opt = Opt::from_args();
+
+ let planets: Vec<Planet> = stdin
+ .lock()
+ .lines()
+ .map(|x| exit_on_failed_assertion(x, "Error reading input"))
+ .map(|x| exit_on_failed_assertion(x.parse::<Planet>(), "Input was not a valid planet"))
+ .collect();
+
+ match opt.n {
+ Some(n) => println!("{}", energy(simulate_planets_n_iterations(planets, n))),
+ None => println!("{}", simulate_planets_to_duplicate(planets)),
+ };
+}
+
+fn exit_on_failed_assertion<A, E: std::error::Error>(data: Result<A, E>, message: &str) -> A {
+ match data {
+ Ok(data) => data,
+ Err(e) => {
+ eprintln!("{}: {}", message, e);
+ process::exit(1);
+ }
+ }
+}
+
+fn energy(planets: Vec<Planet>) -> i32 {
+ planets.into_iter().map(|p| p.energy()).sum()
+}
+
+fn simulate_planets_n_iterations(planets: Vec<Planet>, n: u64) -> Vec<Planet> {
+ simulate_planets_iter(planets)
+ .find(|(i, _)| *i == n)
+ .unwrap()
+ .1
+}
+
+fn simulate_planets_to_duplicate(planets: Vec<Planet>) -> u64 {
+ lowest_common_multiple(
+ simulate_planets_to_duplicate_1d(planets.clone(), |(p, o)| p.equal_x(o)),
+ simulate_planets_to_duplicate_1d(planets.clone(), |(p, o)| p.equal_y(o)),
+ simulate_planets_to_duplicate_1d(planets.clone(), |(p, o)| p.equal_z(o)),
+ )
+}
+
+fn simulate_planets_to_duplicate_1d(
+ planets: Vec<Planet>,
+ eq: impl FnMut((&Planet, &Planet)) -> bool + Copy,
+) -> u64 {
+ simulate_planets_iter(planets.clone())
+ .skip(1)
+ .find(|(_i, ps)| ps.iter().zip(planets.iter()).all(eq))
+ .unwrap()
+ .0
+}
+
+fn lowest_common_multiple(x: u64, y: u64, z: u64) -> u64 {
+ (1..)
+ .map(|i| x * i)
+ .find(|mx| multiples(y, *mx) && multiples(z, *mx))
+ .unwrap()
+}
+
+fn multiples(x: u64, target: u64) -> bool {
+ target % x == 0
+}
+
+fn simulate_planets_iter(planets: Vec<Planet>) -> impl Iterator<Item = (u64, Vec<Planet>)> {
+ iter::successors(Some((0, planets.clone())), |(i, planets)| {
+ Some((i + 1, simulate_planets(planets.clone())))
+ })
+}
+
+fn simulate_planets(planets: Vec<Planet>) -> Vec<Planet> {
+ simulate_velocity(simulate_gravity(planets))
+}
+
+fn simulate_gravity(planets: Vec<Planet>) -> Vec<Planet> {
+ planets
+ .iter()
+ .map(|p| Planet {
+ pos: p.pos.clone(),
+ vel: planets
+ .iter()
+ .filter(|o| p != *o)
+ .map(|o| p.acc(o))
+ .fold(p.vel, |acc, next| acc + next),
+ })
+ .collect()
+}
+
+fn simulate_velocity(planets: Vec<Planet>) -> Vec<Planet> {
+ planets
+ .into_iter()
+ .map(|p| Planet {
+ pos: p.pos + p.vel,
+ vel: p.vel,
+ })
+ .collect()
+}
+
+#[derive(Debug, Default, Clone, PartialEq)]
+struct Planet {
+ pos: Vec3d,
+ vel: Vec3d,
+}
+
+#[derive(Debug, Default, Clone, Copy, PartialEq)]
+struct Vec3d {
+ x: i32,
+ y: i32,
+ z: i32,
+}
+
+impl FromStr for Planet {
+ type Err = ParseIntError;
+
+ fn from_str(s: &str) -> Result<Self, ParseIntError> {
+ s.replace(|c| "<>xyz= ".contains(c), "")
+ .split(',')
+ .map(|i| i.parse::<i32>())
+ .collect::<Result<Vec<_>, _>>()
+ .and_then(|v| match &v[..] {
+ [x, y, z] => Ok(Planet {
+ pos: Vec3d {
+ x: *x,
+ y: *y,
+ z: *z,
+ },
+ vel: Vec3d::default(),
+ }),
+ _ => "wrong number of fields"
+ .parse::<i32>()
+ .map(|_x| Planet::default()),
+ })
+ }
+}
+
+impl Planet {
+ fn acc(&self, other: &Planet) -> Vec3d {
+ Vec3d {
+ x: gravity(self.pos.x, other.pos.x),
+ y: gravity(self.pos.y, other.pos.y),
+ z: gravity(self.pos.z, other.pos.z),
+ }
+ }
+
+ fn energy(&self) -> i32 {
+ (self.pos.x.abs() + self.pos.y.abs() + self.pos.z.abs())
+ * (self.vel.x.abs() + self.vel.y.abs() + self.vel.z.abs())
+ }
+
+ fn equal_x(&self, other: &Planet) -> bool {
+ self.pos.x == other.pos.x && self.vel.x == other.vel.x
+ }
+
+ fn equal_y(&self, other: &Planet) -> bool {
+ self.pos.y == other.pos.y && self.vel.y == other.vel.y
+ }
+
+ fn equal_z(&self, other: &Planet) -> bool {
+ self.pos.z == other.pos.z && self.vel.z == other.vel.z
+ }
+}
+
+fn gravity(this: i32, that: i32) -> i32 {
+ if that > this {
+ 1
+ } else if this > that {
+ -1
+ } else {
+ 0
+ }
+}
+
+impl ops::Add<Vec3d> for Vec3d {
+ type Output = Vec3d;
+ fn add(self, rhs: Vec3d) -> Self::Output {
+ Vec3d {
+ x: self.x + rhs.x,
+ y: self.y + rhs.y,
+ z: self.z + rhs.z,
+ }
+ }
+}
diff --git a/2019/src/bin/day_13.rs b/2019/src/bin/day_13.rs
new file mode 100644
index 0000000..ac1c478
--- /dev/null
+++ b/2019/src/bin/day_13.rs
@@ -0,0 +1,149 @@
+use aoc2019::*;
+use rpds::list;
+use rpds::list::List;
+use rpds::vector::Vector;
+use rpds::RedBlackTreeMap;
+use std::cmp::Ordering;
+use std::io;
+use std::io::prelude::*;
+use std::iter;
+use std::process;
+use structopt::StructOpt;
+
+#[derive(Debug, StructOpt)]
+#[structopt(name = "Day 13: Care Package")]
+/// Executes an Intcode game
+///
+/// The program is read from stdin as a series of comma-separated
+/// values. Newlines are ignored.
+///
+/// See https://adventofcode.com/2019/day/13 for details.
+struct Opt {
+ #[structopt(short = "q", long = "quarters")]
+ quarters: Option<Intcode>,
+}
+
+fn main() {
+ let stdin = io::stdin();
+ let opt = Opt::from_args();
+
+ let program: IntcodeProgram = stdin
+ .lock()
+ .split(b',')
+ .map(|x| exit_on_failed_assertion(x, "Error reading input"))
+ .map(|x| exit_on_failed_assertion(String::from_utf8(x), "Input was not valid UTF-8"))
+ .map(|x| exit_on_failed_assertion(x.trim().parse::<Intcode>(), "Invalid number"))
+ .collect::<IntcodeProgram>();
+
+ match opt.quarters {
+ Some(quarters) => {
+ let result = score_on_won_game(program.with_mem_0(quarters));
+ println!("{}", result);
+ }
+ None => {
+ let result = exit_on_failed_assertion(program.execute(), "Program errored");
+ println!("{}", count_blocks(&result));
+ }
+ }
+}
+
+fn exit_on_failed_assertion<A, E: std::error::Error>(data: Result<A, E>, message: &str) -> A {
+ match data {
+ Ok(data) => data,
+ Err(e) => {
+ eprintln!("{}: {}", message, e);
+ process::exit(1);
+ }
+ }
+}
+
+#[derive(Default, Clone)]
+struct Screen {
+ screen: RedBlackTreeMap<(Intcode, Intcode), Intcode>,
+ previous_ball: (Intcode, Intcode),
+ ball: (Intcode, Intcode),
+ paddle: (Intcode, Intcode),
+ score: Intcode,
+}
+
+impl Screen {
+ fn render(output: &Vector<Intcode>) -> Screen {
+ (0..output.len() / 3)
+ .map(|i| i * 3)
+ .map(|i| {
+ (
+ output[i].clone(),
+ output[i + 1].clone(),
+ output[i + 2].clone(),
+ )
+ })
+ .fold(Screen::default(), |acc, (x, y, tile)| {
+ if x == Intcode::from(-1) && y == Intcode::from(0) {
+ Screen { score: tile, ..acc }
+ } else if tile == Intcode::from(4) {
+ Screen {
+ ball: (x, y),
+ previous_ball: acc.ball,
+ ..acc
+ }
+ } else if tile == Intcode::from(3) {
+ Screen {
+ paddle: (x.clone(), y.clone()),
+ screen: acc.screen.insert((x, y), tile),
+ ..acc
+ }
+ } else if tile == Intcode::from(0) {
+ Screen {
+ screen: acc.screen.remove(&(x, y)),
+ ..acc
+ }
+ } else {
+ Screen {
+ screen: acc.screen.insert((x, y), tile),
+ ..acc
+ }
+ }
+ })
+ }
+
+ fn paddle_required_direction(&self) -> Intcode {
+ match self.paddle.0.cmp(&self.ball.0) {
+ Ordering::Less => Intcode::from(1),
+ Ordering::Equal => Intcode::from(0),
+ Ordering::Greater => Intcode::from(-1),
+ }
+ }
+}
+
+fn count_blocks(output: &Vector<Intcode>) -> usize {
+ Screen::render(output)
+ .screen
+ .values()
+ .filter(|val| **val == Intcode::from(2))
+ .count()
+}
+
+fn score_on_won_game(program: IntcodeProgram) -> Intcode {
+ Screen::render(
+ &iter::successors(Some(program.run_to_termination_or_input()), |program| {
+ Some(next_game_state(program.clone()))
+ })
+ .take_while(|program| !program.halted)
+ .find(|program| count_blocks(&program.output) == 0)
+ .unwrap()
+ .output,
+ )
+ .score
+}
+
+fn next_game_state(program: IntcodeProgram) -> IntcodeProgram {
+ program_with_next_input(program.run_to_termination_or_input())
+}
+
+fn program_with_next_input(program: IntcodeProgram) -> IntcodeProgram {
+ program.with_input(list![next_input(&program.output)])
+}
+
+fn next_input(output: &Vector<Intcode>) -> Intcode {
+ Screen::render(output).paddle_required_direction()
+}
diff --git a/2019/src/bin/day_14.rs b/2019/src/bin/day_14.rs
new file mode 100644
index 0000000..0532f5f
--- /dev/null
+++ b/2019/src/bin/day_14.rs
@@ -0,0 +1,221 @@
+use rpds::map::red_black_tree_map::RedBlackTreeMap;
+use rpds::rbt_map;
+use rpds::vector::Vector;
+use std::fmt;
+use std::io;
+use std::io::prelude::*;
+use std::iter;
+use std::process;
+use std::str::FromStr;
+use structopt::StructOpt;
+
+#[derive(Debug, StructOpt)]
+#[structopt(name = "Day 14: Space Stoichiometry")]
+/// Finds how much ore you need to produce one fuel.
+///
+/// Recipes are passed in on stdin, one per line.
+///
+/// See https://adventofcode.com/2019/day/14 for details.
+struct Opt {
+ #[structopt(long = "available-ore")]
+ available_ore: Option<i64>,
+}
+
+fn main() {
+ let stdin = io::stdin();
+ let opt = Opt::from_args();
+
+ let recipes = stdin
+ .lock()
+ .lines()
+ .map(|x| exit_on_failed_assertion(x, "Error reading input"))
+ .map(|x| exit_on_failed_assertion(x.parse::<Recipe>(), "Input was not a valid recipe"))
+ .collect::<Vec<_>>();
+
+ match opt.available_ore {
+ Some(ore) => println!("{}", max_fuel_production(ore, &recipes)),
+ None => println!("{}", Desires::new(1).min_ore_required(&recipes)),
+ }
+}
+
+fn exit_on_failed_assertion<A, E: std::error::Error>(data: Result<A, E>, message: &str) -> A {
+ match data {
+ Ok(data) => data,
+ Err(e) => {
+ eprintln!("{}: {}", message, e);
+ process::exit(1);
+ }
+ }
+}
+
+fn max_fuel_production(ore_max: i64, recipes: &[Recipe]) -> i64 {
+ binary_search_max_fuel_production(
+ ore_max / Desires::new(1).min_ore_required(&recipes),
+ 2 * ore_max / Desires::new(1).min_ore_required(&recipes),
+ ore_max,
+ recipes,
+ )
+}
+
+fn binary_search_max_fuel_production(
+ fuel_min: i64,
+ fuel_max: i64,
+ ore_max: i64,
+ recipes: &[Recipe],
+) -> i64 {
+ if fuel_max - fuel_min <= 1 {
+ fuel_min
+ } else if Desires::new((fuel_min + fuel_max) / 2).min_ore_required(recipes) <= ore_max {
+ binary_search_max_fuel_production((fuel_min + fuel_max) / 2, fuel_max, ore_max, recipes)
+ } else {
+ binary_search_max_fuel_production(fuel_min, (fuel_min + fuel_max) / 2, ore_max, recipes)
+ }
+}
+
+#[derive(Debug, Clone)]
+struct Recipe {
+ ingredients: Vector<Chemical>,
+ output: Chemical,
+}
+
+#[derive(Default, Debug, Clone)]
+struct Chemical {
+ name: String,
+ quantity: i64,
+}
+
+impl FromStr for Recipe {
+ type Err = ParseErr;
+ fn from_str(s: &str) -> Result<Self, Self::Err> {
+ // 2 XSNKB, 15 ZVMCB, 3 KDFNZ => 2 RFLX
+ s.replace(" => ", "=")
+ .replace(", ", ",")
+ .split(|c| c == ',' || c == '=')
+ .map(|chem| chem.parse::<Chemical>())
+ .collect::<Result<Vector<Chemical>, ParseErr>>()
+ .map(|chemicals| Recipe {
+ ingredients: chemicals
+ .drop_last()
+ .expect("Assertion failed: line did not have any chemicals"),
+ output: chemicals
+ .last()
+ .cloned()
+ .expect("Assertion failed: line did not have any chemicals"),
+ })
+ }
+}
+
+impl Recipe {
+ fn required_scale(&self, desired_quantity: i64) -> i64 {
+ (desired_quantity + self.output.quantity - 1) / self.output.quantity
+ }
+}
+
+impl FromStr for Chemical {
+ type Err = ParseErr;
+ fn from_str(s: &str) -> Result<Self, Self::Err> {
+ // 1 FUEL
+ match s.split(' ').collect::<Vec<_>>()[..] {
+ [quantity, name] => quantity
+ .parse::<i64>()
+ .map_err(|_| ParseErr)
+ .map(|q| Chemical {
+ name: name.to_string(),
+ quantity: q,
+ }),
+ _ => Err(ParseErr),
+ }
+ }
+}
+
+impl Chemical {
+ fn scale(&self, scale: i64) -> Chemical {
+ Chemical {
+ name: self.name.clone(),
+ quantity: self.quantity * scale,
+ }
+ }
+}
+
+#[derive(Debug, Clone, Copy)]
+struct ParseErr;
+
+impl fmt::Display for ParseErr {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f, "Error parsing input")
+ }
+}
+
+impl std::error::Error for ParseErr {}
+
+#[derive(Debug, Clone)]
+struct Desires {
+ chemicals: RedBlackTreeMap<String, i64>,
+}
+
+impl Desires {
+ fn new(fuel: i64) -> Desires {
+ Desires {
+ chemicals: rbt_map!["FUEL".to_string() => fuel, "ORE".to_string() => 0],
+ }
+ }
+
+ fn min_ore_required(&self, recipes: &[Recipe]) -> i64 {
+ iter::successors(Some(self.clone()), |prev| Some(prev.next(recipes)))
+ .find(|desires| desires.is_only_ore())
+ .unwrap()
+ .chemicals
+ .get("ORE")
+ .cloned()
+ .unwrap()
+ }
+
+ fn is_only_ore(&self) -> bool {
+ !self
+ .chemicals
+ .iter()
+ .any(|(name, quantity)| *quantity > 0 && name != "ORE")
+ }
+
+ fn next(&self, recipes: &[Recipe]) -> Desires {
+ self.chemicals
+ .iter()
+ .find(|(name, quantity)| **quantity > 0 && *name != "ORE")
+ .map(|(mixing, quantity)| {
+ self.with_mixed_recipe(
+ recipes
+ .iter()
+ .find(|recipe| recipe.output.name == *mixing)
+ .expect("Required chemical without a recipe"),
+ *quantity,
+ )
+ })
+ .unwrap_or(self.clone())
+ }
+
+ fn with_mixed_recipe(&self, recipe: &Recipe, desired_quantity: i64) -> Desires {
+ recipe.ingredients.iter().fold(
+ self.with_chemical(
+ recipe
+ .output
+ .scale(-1 * recipe.required_scale(desired_quantity)),
+ ),
+ |acc, next_ingredient| {
+ acc.with_chemical(next_ingredient.scale(recipe.required_scale(desired_quantity)))
+ },
+ )
+ }
+
+ fn with_chemical(&self, chemical: Chemical) -> Desires {
+ Desires {
+ chemicals: match self.chemicals.get(&chemical.name) {
+ Some(existing_quantity) => self
+ .chemicals
+ .insert(chemical.name.clone(), existing_quantity + chemical.quantity),
+ None => self
+ .chemicals
+ .insert(chemical.name.clone(), chemical.quantity),
+ },
+ }
+ }
+}
diff --git a/2019/src/bin/day_15.rs b/2019/src/bin/day_15.rs
new file mode 100644
index 0000000..b2205bb
--- /dev/null
+++ b/2019/src/bin/day_15.rs
@@ -0,0 +1,183 @@
+use aoc2019::*;
+use rpds::list;
+use rpds::list::List;
+use rpds::rbt_set;
+use rpds::set::red_black_tree_set::RedBlackTreeSet;
+use rpds::vector;
+use rpds::vector::Vector;
+use std::io;
+use std::io::prelude::*;
+use std::iter;
+use std::process;
+use structopt::StructOpt;
+
+#[derive(Debug, StructOpt)]
+#[structopt(name = "Day 15: Oxygen System")]
+/// Executes an Intcode robot that's searching a map. Prints the
+/// time taken for oxygen to propagate to the whole area.
+///
+/// See https://adventofcode.com/2019/day/15 for details.
+struct Opt {
+ /// Run in 'find' mode, find the oxygen tank but don't see how long it takes the oxygen to propagate
+ #[structopt(short = "f")]
+ find: bool,
+}
+
+fn main() {
+ let stdin = io::stdin();
+ let opt = Opt::from_args();
+
+ let program: IntcodeProgram = stdin
+ .lock()
+ .split(b',')
+ .map(|x| exit_on_failed_assertion(x, "Error reading input"))
+ .map(|x| exit_on_failed_assertion(String::from_utf8(x), "Input was not valid UTF-8"))
+ .map(|x| exit_on_failed_assertion(x.trim().parse::<Intcode>(), "Invalid number"))
+ .collect::<IntcodeProgram>();
+
+ if opt.find {
+ println!("{}", shortest_distance(program));
+ } else {
+ println!("{}", max_depth_from_oxygen(program));
+ }
+}
+
+fn exit_on_failed_assertion<A, E: std::error::Error>(data: Result<A, E>, message: &str) -> A {
+ match data {
+ Ok(data) => data,
+ Err(e) => {
+ eprintln!("{}: {}", message, e);
+ process::exit(1);
+ }
+ }
+}
+
+fn shortest_distance(program: IntcodeProgram) -> usize {
+ iter::successors(
+ Some((
+ rbt_set![(0, 0)],
+ vector![((0, 0), program.run_to_termination_or_input())],
+ )),
+ |(visited, programs)| {
+ Some(next_depth_states(
+ visited.clone(),
+ next_program_states(programs, visited),
+ ))
+ },
+ )
+ .enumerate()
+ .find(|(_i, (_visited, programs))| {
+ programs
+ .iter()
+ .any(|(_location, program)| program.output == vector![2.into()])
+ })
+ .unwrap()
+ .0
+}
+
+fn max_depth_from_oxygen(program: IntcodeProgram) -> usize {
+ max_depth(
+ iter::successors(
+ Some((
+ rbt_set![(0, 0)],
+ vector![((0, 0), program.run_to_termination_or_input())],
+ )),
+ |(visited, programs)| {
+ Some(next_depth_states(
+ visited.clone(),
+ next_program_states(programs, visited),
+ ))
+ },
+ )
+ .find(|(_visited, programs)| {
+ programs
+ .iter()
+ .any(|(_location, program)| program.output == vector![2.into()])
+ })
+ .unwrap()
+ .1
+ .iter()
+ .find(|(_location, program)| program.output == vector![2.into()])
+ .cloned()
+ .unwrap()
+ .1,
+ )
+}
+
+fn max_depth(program: IntcodeProgram) -> usize {
+ iter::successors(
+ Some((
+ rbt_set![(0, 0)],
+ vector![((0, 0), program.run_to_termination_or_input())],
+ )),
+ |(visited, programs)| {
+ Some(next_depth_states(
+ visited.clone(),
+ next_program_states(programs, visited),
+ ))
+ },
+ )
+ .take_while(|(_visited, programs)| programs.len() > 0)
+ .count()
+ - 1
+}
+
+fn inputs() -> [((i32, i32), Intcode); 4] {
+ [
+ ((0, 1), Intcode::from(1)),
+ ((0, -1), Intcode::from(2)),
+ ((1, 0), Intcode::from(3)),
+ ((-1, 0), Intcode::from(4)),
+ ]
+}
+
+fn next_program_states(
+ programs: &Vector<((i32, i32), IntcodeProgram)>,
+ visited: &RedBlackTreeSet<(i32, i32)>,
+) -> Vector<((i32, i32), IntcodeProgram)> {
+ let inputs = inputs();
+ programs
+ .iter()
+ .flat_map(|(location, program)| {
+ inputs.iter().map(move |(vec, input)| {
+ (
+ (location.0 + vec.0, location.1 + vec.1),
+ program
+ .with_cleared_output()
+ .with_input(list![input.clone()])
+ .run_to_termination_or_input(),
+ )
+ })
+ })
+ .filter(|(location, program)| {
+ !visited.contains(location) && program.output != vector![0.into()]
+ })
+ .collect()
+}
+
+fn next_depth_states(
+ previous_visited: RedBlackTreeSet<(i32, i32)>,
+ programs: Vector<((i32, i32), IntcodeProgram)>,
+) -> (
+ RedBlackTreeSet<(i32, i32)>,
+ Vector<((i32, i32), IntcodeProgram)>,
+) {
+ (
+ programs
+ .iter()
+ .fold(previous_visited, |acc, (next, _)| acc.insert(*next)),
+ dedup_locations(programs),
+ )
+}
+
+fn dedup_locations(
+ programs: Vector<((i32, i32), IntcodeProgram)>,
+) -> Vector<((i32, i32), IntcodeProgram)> {
+ programs.iter().fold(Vector::new(), |acc, next| {
+ if acc.iter().any(|(loc, _)| *loc == next.0) {
+ acc
+ } else {
+ acc.push_back(next.clone())
+ }
+ })
+}
diff --git a/2019/src/bin/day_16.rs b/2019/src/bin/day_16.rs
new file mode 100644
index 0000000..aa53127
--- /dev/null
+++ b/2019/src/bin/day_16.rs
@@ -0,0 +1,112 @@
+use rayon::prelude::*;
+use std::io;
+use std::io::prelude::*;
+use std::iter;
+use std::num::ParseIntError;
+use std::process;
+use structopt::StructOpt;
+
+#[derive(Debug, StructOpt)]
+#[structopt(name = "Day 16: Flawed Frequency Transmission")]
+/// Performs the flawed frequency transform of a number.
+///
+/// See https://adventofcode.com/2019/day/16 for details.
+struct Opt {
+ /// the offset after which you start reading output
+ #[structopt(short = "o", long = "offset", default_value = "0")]
+ offset: usize,
+ input_repeats: usize,
+ fft_repeats: usize,
+}
+
+fn main() {
+ let stdin = io::stdin();
+ let opt = Opt::from_args();
+
+ stdin
+ .lock()
+ .lines()
+ .map(|x| exit_on_failed_assertion(x, "Error reading input"))
+ .map(|x| exit_on_failed_assertion(parse(&x), "Input was not a valid recipe"))
+ .for_each(|input| {
+ println!(
+ "{}",
+ transform(input, opt.input_repeats, opt.fft_repeats, opt.offset)
+ .into_iter()
+ .map(|c| c.to_string())
+ .collect::<String>()
+ );
+ });
+}
+
+fn exit_on_failed_assertion<A, E: std::error::Error>(data: Result<A, E>, message: &str) -> A {
+ match data {
+ Ok(data) => data,
+ Err(e) => {
+ eprintln!("{}: {}", message, e);
+ process::exit(1);
+ }
+ }
+}
+
+fn parse(s: &str) -> Result<Vec<i32>, ParseIntError> {
+ s.chars().map(|c| c.to_string().parse::<i32>()).collect()
+}
+
+fn transform(input: Vec<i32>, input_repeats: usize, fft_repeats: usize, offset: usize) -> Vec<i32> {
+ iter::successors(
+ Some(
+ input
+ .iter()
+ .cycle()
+ .take(input.len() * input_repeats)
+ .cloned()
+ .collect::<Vec<i32>>(),
+ ),
+ |input| Some(next_phase(input, offset)),
+ )
+ .nth(fft_repeats)
+ .unwrap()
+ .into_iter()
+ .skip(offset)
+ .take(8)
+ .collect()
+}
+
+fn next_phase(input: &Vec<i32>, offset: usize) -> Vec<i32> {
+ if offset > input.len() / 2 {
+ (0..input.len())
+ .into_par_iter()
+ .map(|digit| {
+ if digit < offset {
+ 0
+ } else {
+ input.iter().skip(digit).sum::<i32>().abs() % 10
+ }
+ })
+ .collect()
+ } else {
+ (0..input.len())
+ .into_par_iter()
+ .map(|digit| {
+ input
+ .iter()
+ .zip(pattern(digit))
+ .map(|(x, y)| x * y)
+ .sum::<i32>()
+ .abs()
+ % 10
+ })
+ .collect()
+ }
+}
+
+fn pattern(digit: usize) -> impl Iterator<Item = i32> {
+ iter::repeat(0)
+ .take(digit + 1)
+ .chain(iter::repeat(1).take(digit + 1))
+ .chain(iter::repeat(0).take(digit + 1))
+ .chain(iter::repeat(-1).take(digit + 1))
+ .cycle()
+ .skip(1)
+}
diff --git a/2019/src/bin/day_17.rs b/2019/src/bin/day_17.rs
new file mode 100644
index 0000000..e85373c
--- /dev/null
+++ b/2019/src/bin/day_17.rs
@@ -0,0 +1,78 @@
+use aoc2019::*;
+use std::io;
+use std::io::prelude::*;
+use std::process;
+use structopt::StructOpt;
+
+#[derive(Debug, StructOpt)]
+#[structopt(name = "Day 17: Set and Forget")]
+/// Pilots a vacuum robot around on a scaffold. What could go wrong?
+///
+/// See https://adventofcode.com/2019/day/17 for details.
+struct Opt {
+ /// Draw the map and exit
+ #[structopt(short = "d")]
+ draw_map: bool,
+}
+
+fn main() {
+ let stdin = io::stdin();
+ let opt = Opt::from_args();
+
+ let program: IntcodeProgram = stdin
+ .lock()
+ .split(b',')
+ .map(|x| exit_on_failed_assertion(x, "Error reading input"))
+ .map(|x| exit_on_failed_assertion(String::from_utf8(x), "Input was not valid UTF-8"))
+ .map(|x| exit_on_failed_assertion(x.trim().parse::<Intcode>(), "Invalid number"))
+ .collect::<IntcodeProgram>();
+
+ let result = exit_on_failed_assertion(
+ if opt.draw_map {
+ program.execute()
+ } else {
+ // L,12,L,8,R,10,R,10,L,6,L,4,L,12,L,12,L,8,R,10,R,10,L,6,L,4,L,12,R,10,L,8,L,4,R,10,L,6,L,4,L,12,L,12,L,8,R,10,R,10,R,10,L,8,L,4,R,10,L,6,L,4,L,12,R,10,L,8,L,4,R,10
+ // | | ||
+
+ let input = vec![
+ "A,B,A,B,C,B,A,C,B,C\n",
+ "L,12,L,8,R,10,R,10\n",
+ "L,6,L,4,L,12\n",
+ "R,10,L,8,L,4,R,10\n",
+ "y\n",
+ ];
+ program
+ .with_mem_0(Intcode::from(2))
+ .with_input(
+ input
+ .iter()
+ .flat_map(|line| line.chars().map(|c| Intcode::from(c as u8)))
+ .collect(),
+ )
+ .execute()
+ },
+ "Program failed",
+ );
+
+ println!(
+ "{}",
+ result
+ .drop_last()
+ .unwrap()
+ .iter()
+ .flat_map(|c| c.to_signed_bytes_be())
+ .map(|c| c as char)
+ .collect::<String>()
+ );
+ println!("{}", result.last().unwrap());
+}
+
+fn exit_on_failed_assertion<A, E: std::error::Error>(data: Result<A, E>, message: &str) -> A {
+ match data {
+ Ok(data) => data,
+ Err(e) => {
+ eprintln!("{}: {}", message, e);
+ process::exit(1);
+ }
+ }
+}
diff --git a/2019/src/bin/day_18.rs b/2019/src/bin/day_18.rs
new file mode 100644
index 0000000..255baa0
--- /dev/null
+++ b/2019/src/bin/day_18.rs
@@ -0,0 +1,365 @@
+use rpds::rbt_set;
+use rpds::vector::Vector;
+use rpds::RedBlackTreeMap;
+use rpds::RedBlackTreeSet;
+use std::io;
+use std::io::prelude::*;
+use std::iter;
+use std::iter::FromIterator;
+use std::process;
+use structopt::StructOpt;
+
+#[derive(Debug, StructOpt)]
+#[structopt(name = "Day 18: Many-Worlds Interpretation")]
+/// Finds the shortest path through a maze with keys
+///
+/// See https://adventofcode.com/2019/day/18 for details.
+struct Opt {}
+
+fn main() {
+ let stdin = io::stdin();
+ let _opt = Opt::from_args();
+
+ let maze: Maze = stdin
+ .lock()
+ .lines()
+ .map(|x| exit_on_failed_assertion(x, "Error reading input"))
+ .collect();
+
+ println!("{}", maze.shortest_route());
+}
+
+fn exit_on_failed_assertion<A, E: std::error::Error>(data: Result<A, E>, message: &str) -> A {
+ match data {
+ Ok(data) => data,
+ Err(e) => {
+ eprintln!("{}: {}", message, e);
+ process::exit(1);
+ }
+ }
+}
+
+struct Maze {
+ blocks: Vec<Vec<char>>,
+ start: BoardState,
+ keys: KeySet,
+}
+
+impl FromIterator<String> for Maze {
+ fn from_iter<T: IntoIterator<Item = String>>(iter: T) -> Self {
+ Maze::from_blocks(
+ iter.into_iter()
+ .map(|line| line.chars().collect())
+ .collect(),
+ )
+ }
+}
+
+impl Maze {
+ fn from_blocks(blocks: Vec<Vec<char>>) -> Maze {
+ Maze {
+ start: BoardState {
+ robots: blocks
+ .iter()
+ .enumerate()
+ .flat_map(|(y, line)| {
+ line.iter()
+ .enumerate()
+ .filter(|(_x, ch)| **ch == '@')
+ .map(move |(x, _ch)| Location { x, y })
+ })
+ .collect(),
+ keys: KeySet::default(),
+ },
+ keys: blocks
+ .iter()
+ .flat_map(|line| line.iter())
+ .fold(KeySet::default(), |acc, next| acc.add_key(*next)),
+ blocks,
+ }
+ }
+
+ fn block_at(&self, location: &Location) -> Option<char> {
+ self.blocks
+ .get(location.y)
+ .and_then(|line| line.get(location.x))
+ .cloned()
+ }
+
+ fn shortest_route(&self) -> usize {
+ iter::successors(
+ Some((
+ ExploredStates::default().insert(&self.start),
+ rbt_set![self.start.clone()],
+ )),
+ |(explored, locations)| {
+ Some(Maze::next_depth_states(
+ explored.clone(),
+ self.next_locations(locations, explored),
+ ))
+ },
+ )
+ // .inspect(|(explored, states)| eprintln!("{:?}", states))
+ .take_while(|(_explored, states)| states.size() > 0)
+ .enumerate()
+ .find(|(_i, (_explored, states))| states.iter().any(|state| state.keys == self.keys))
+ .unwrap()
+ .0
+ }
+
+ fn next_depth_states(
+ explored: ExploredStates,
+ locations: RedBlackTreeSet<BoardState>,
+ ) -> (ExploredStates, RedBlackTreeSet<BoardState>) {
+ (
+ locations
+ .iter()
+ .fold(explored, |acc, next| acc.insert(next)),
+ locations,
+ )
+ }
+
+ fn next_locations(
+ &self,
+ locations: &RedBlackTreeSet<BoardState>,
+ explored: &ExploredStates,
+ ) -> RedBlackTreeSet<BoardState> {
+ locations
+ .iter()
+ .flat_map(|current| {
+ (0..current.robots.len()).flat_map(move |i_robot| {
+ [(-1, 0), (1, 0), (0, -1), (0, 1)]
+ .iter()
+ .map(move |(dx, dy)| current.next(i_robot, *dx, *dy))
+ .map(move |(state, new_location)| {
+ self.block_at(&new_location)
+ .map(|c| state.with_key(c))
+ .unwrap_or(state)
+ })
+ })
+ })
+ .filter(|state| self.is_open(state))
+ .filter(|state| !explored.contains(state))
+ .collect()
+ }
+
+ fn is_open(&self, state: &BoardState) -> bool {
+ state.robots.iter().all(|location| {
+ self.block_at(location)
+ .map(|c| Maze::char_is_open(c, state.keys))
+ .unwrap_or(false)
+ })
+ }
+
+ fn char_is_open(c: char, keys: KeySet) -> bool {
+ c != '#' && !keys.door_is_locked(c)
+ }
+}
+
+#[derive(Default, Debug, Clone)]
+struct ExploredStates {
+ for_key: RedBlackTreeMap<KeySet, ExploredStatesForKey>,
+}
+
+#[derive(Default, Debug, Clone)]
+struct ExploredStatesForKey {
+ robots: Vector<RedBlackTreeSet<Location>>,
+}
+
+impl ExploredStates {
+ fn insert(&self, new: &BoardState) -> ExploredStates {
+ ExploredStates {
+ for_key: self.for_key.insert(
+ new.keys.clone(),
+ self.for_key
+ .get(&new.keys)
+ .map(|current| ExploredStatesForKey {
+ robots: current
+ .robots
+ .iter()
+ .zip(new.robots.iter())
+ .map(|(current_explored, robot)| current_explored.insert(robot.clone()))
+ .collect(),
+ })
+ .unwrap_or_else(|| ExploredStatesForKey {
+ robots: new
+ .robots
+ .iter()
+ .map(|robot| RedBlackTreeSet::new().insert(robot.clone()))
+ .collect(),
+ }),
+ ),
+ }
+ }
+
+ fn contains(&self, state: &BoardState) -> bool {
+ self.for_key
+ .get(&state.keys)
+ .filter(|for_key| {
+ state
+ .robots
+ .iter()
+ .zip(for_key.robots.iter())
+ .all(|(r_state, r_explored)| r_explored.contains(r_state))
+ })
+ .is_some()
+ }
+}
+
+#[derive(Default, Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
+struct BoardState {
+ robots: Vector<Location>,
+ keys: KeySet,
+}
+
+impl BoardState {
+ fn next(&self, i_robot: usize, dx: isize, dy: isize) -> (BoardState, Location) {
+ (
+ BoardState {
+ robots: self
+ .robots
+ .set(i_robot, self.robots[i_robot].next(dx, dy))
+ .unwrap(),
+ ..self.clone()
+ },
+ self.robots[i_robot].next(dx, dy),
+ )
+ }
+
+ fn with_key(&self, c: char) -> BoardState {
+ BoardState {
+ keys: self.keys.add_key(c),
+ ..self.clone()
+ }
+ }
+}
+
+#[derive(Default, Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
+struct Location {
+ x: usize,
+ y: usize,
+}
+
+impl Location {
+ fn next(&self, dx: isize, dy: isize) -> Location {
+ Location {
+ x: (self.x as isize + dx) as usize,
+ y: (self.y as isize + dy) as usize,
+ }
+ }
+}
+
+#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
+struct KeySet {
+ bitset: u32,
+}
+
+impl KeySet {
+ fn add_key(self, key: char) -> KeySet {
+ KeySet {
+ bitset: self.bitset | KeySet::key_to_bitset(key),
+ }
+ }
+
+ fn door_is_locked(self, door: char) -> bool {
+ KeySet::door_to_bitset(door) & (!self.bitset) > 0
+ }
+
+ fn key_to_bitset(key: char) -> u32 {
+ if key.is_ascii_alphabetic() && key.is_ascii_lowercase() {
+ 1 << (key as u8 - b'a')
+ } else {
+ 0
+ }
+ }
+
+ fn door_to_bitset(door: char) -> u32 {
+ if door.is_ascii_alphabetic() && door.is_ascii_uppercase() {
+ 1 << (door as u8 - b'A')
+ } else {
+ 0
+ }
+ }
+}
+
+#[test]
+fn doors_are_locked_without_key() {
+ assert_eq!(true, KeySet::default().door_is_locked('A'))
+}
+
+#[test]
+fn doors_are_unlocked_with_key() {
+ assert_eq!(false, KeySet::default().add_key('a').door_is_locked('A'))
+}
+
+#[test]
+fn example_1() {
+ let maze: Maze = r"
+#########
+#b.A.@.a#
+#########
+"
+ .split('\n')
+ .map(|s| s.to_string())
+ .collect();
+
+ assert_eq!(maze.shortest_route(), 8);
+}
+
+#[test]
+fn example_2() {
+ let maze: Maze = r"
+#################
+#i.G..c...e..H.p#
+########.########
+#j.A..b...f..D.o#
+########@########
+#k.E..a...g..B.n#
+########.########
+#l.F..d...h..C.m#
+#################
+"
+ .split('\n')
+ .map(|s| s.to_string())
+ .collect();
+
+ assert_eq!(maze.shortest_route(), 136);
+}
+
+#[test]
+fn example_3() {
+ let maze: Maze = r"
+#############
+#DcBa.#.GhKl#
+#.###@#@#I###
+#e#d#####j#k#
+###C#@#@###J#
+#fEbA.#.FgHi#
+#############
+"
+ .split('\n')
+ .map(|s| s.to_string())
+ .collect();
+
+ assert_eq!(maze.shortest_route(), 32);
+}
+
+#[test]
+fn example_4() {
+ let maze: Maze = r"
+#############
+#g#f.D#..h#l#
+#F###e#E###.#
+#dCba@#@BcIJ#
+#############
+#nK.L@#@G...#
+#M###N#H###.#
+#o#m..#i#jk.#
+#############
+"
+ .split('\n')
+ .map(|s| s.to_string())
+ .collect();
+
+ assert_eq!(maze.shortest_route(), 74);
+}
diff --git a/2019/src/bin/day_19.rs b/2019/src/bin/day_19.rs
new file mode 100644
index 0000000..73c8374
--- /dev/null
+++ b/2019/src/bin/day_19.rs
@@ -0,0 +1,102 @@
+use aoc2019::*;
+use cached::cached_key;
+use cached::UnboundCache;
+use rpds::list;
+use rpds::list::List;
+use rpds::vector;
+use std::io;
+use std::io::prelude::*;
+use std::process;
+use structopt::StructOpt;
+
+#[derive(Debug, StructOpt)]
+#[structopt(name = "Day 19: Tractor Beam")]
+/// Finds the effective area of a tractor beam in an n x n square, and
+/// how far away you need to be to capture Santa's ship.
+///
+/// See https://adventofcode.com/2019/day/19 for details.
+struct Opt {
+ /// The size for a diagnostics scan.
+ #[structopt(long = "diagnostics-size")]
+ diagnostics_size: Option<usize>,
+ /// The size of Santa's ship
+ #[structopt(long = "ship-size")]
+ ship_size: Option<usize>,
+}
+
+fn main() {
+ let stdin = io::stdin();
+ let opt = Opt::from_args();
+
+ let program: IntcodeProgram = stdin
+ .lock()
+ .split(b',')
+ .map(|x| exit_on_failed_assertion(x, "Error reading input"))
+ .map(|x| exit_on_failed_assertion(String::from_utf8(x), "Input was not valid UTF-8"))
+ .map(|x| exit_on_failed_assertion(x.trim().parse::<Intcode>(), "Invalid number"))
+ .collect::<IntcodeProgram>();
+
+ if let Some(size) = opt.diagnostics_size {
+ println!("{}", count_active_in_area(program.clone(), 0, 0, size));
+ }
+ if let Some(size) = opt.ship_size {
+ println!("{:?}", find_closest_ship_space(program, size))
+ }
+}
+
+fn exit_on_failed_assertion<A, E: std::error::Error>(data: Result<A, E>, message: &str) -> A {
+ match data {
+ Ok(data) => data,
+ Err(e) => {
+ eprintln!("{}: {}", message, e);
+ process::exit(1);
+ }
+ }
+}
+
+fn count_active_in_area(program: IntcodeProgram, left: usize, top: usize, size: usize) -> usize {
+ (left..left + size)
+ .flat_map(|x| (top..top + size).map(move |y| (x, y)))
+ .filter(|(x, y)| tractor_beam_is_active(program.clone(), *x, *y))
+ .count()
+}
+
+fn area_is_all_full(program: IntcodeProgram, left: usize, top: usize, size: usize) -> bool {
+ // This check with a grid that's aligned to 10 gives an early exit
+ // for most, that will have the program executions shared. This
+ // makes the memoized tractor function more effective at cutting
+ // down on execution, even though you need to do the whole lot
+ // again to verify if this passes.
+ (left..left + size)
+ .flat_map(|x| (top..top + size).map(move |y| (x, y)))
+ .filter(|(x, y)| x % 10 == 0 && y % 10 == 0)
+ .all(|(x, y)| tractor_beam_is_active(program.clone(), x, y))
+ && (left..left + size)
+ .flat_map(|x| (top..top + size).map(move |y| (x, y)))
+ .all(|(x, y)| tractor_beam_is_active(program.clone(), x, y))
+}
+
+fn find_closest_ship_space(program: IntcodeProgram, size: usize) -> (usize, usize) {
+ (0..)
+ .flat_map(|radius| {
+ (0..radius)
+ .flat_map(move |x| (0..radius).map(move |y| (x, y)))
+ .filter(move |(x, y)| {
+ (radius - 1) * (radius - 1) < x * x + y * y && x * x + y * y <= radius * radius
+ })
+ })
+ .find(|(x, y)| area_is_all_full(program.clone(), *x, *y, size))
+ .unwrap()
+}
+
+cached_key! {
+ TRACTOR_BEAM_IS_ACTIVE: UnboundCache<(usize, usize), bool> = UnboundCache::new();
+ Key = { (x, y) };
+ fn tractor_beam_is_active(program: IntcodeProgram, x: usize, y: usize) -> bool = {
+ program
+ .with_input(list![Intcode::from(x), Intcode::from(y)])
+ .execute()
+ == Ok(vector![Intcode::from(1)])
+
+ }
+}
diff --git a/2019/src/bin/day_2.rs b/2019/src/bin/day_2.rs
new file mode 100644
index 0000000..ba9e189
--- /dev/null
+++ b/2019/src/bin/day_2.rs
@@ -0,0 +1,96 @@
+use aoc2019::*;
+use std::io;
+use std::io::prelude::*;
+use std::process;
+use structopt::StructOpt;
+
+#[derive(Debug, StructOpt)]
+#[structopt(name = "Day 2: 1202 Program Alarm")]
+/// Executes an Intcode program
+///
+/// The program is read from stdin as a series of comma-separated
+/// values. Newlines are ignored. When the program halts, the value at
+/// position 0 is returned.
+///
+/// If an output is provided, all possible inputs are tried to find
+/// the input that results in the desired output. In this case, the
+/// inputs are returned in the format (noun, verb).
+///
+///See https://adventofcode.com/2019/day/2 for details.
+struct Opt {
+ #[structopt(short = "n", long = "noun")]
+ noun: Option<Intcode>,
+ #[structopt(short = "v", long = "verb")]
+ verb: Option<Intcode>,
+ #[structopt(short = "o", long = "output")]
+ output: Option<Intcode>,
+}
+
+fn main() {
+ let stdin = io::stdin();
+ let opt = Opt::from_args();
+
+ let program: IntcodeProgram = stdin
+ .lock()
+ .split(b',')
+ .map(|x| exit_on_failed_assertion(x, "Error reading input"))
+ .map(|x| exit_on_failed_assertion(String::from_utf8(x), "Input was not valid UTF-8"))
+ .map(|x| exit_on_failed_assertion(x.trim().parse::<Intcode>(), "Invalid number"))
+ .collect();
+
+ match (opt.noun, opt.verb, opt.output) {
+ (Some(noun), Some(verb), _) => {
+ let result = exit_on_failed_assertion(
+ program
+ .with_noun_verb_input(noun, verb)
+ .execute_returning_memory_0(),
+ "Program errored",
+ );
+ println!("{}", result);
+ }
+ (_, _, Some(output)) => {
+ let (noun, verb) =
+ exit_on_failed_assertion(find_input(&program, output), "Program errored");
+ println!("({}, {})", noun, verb);
+ }
+ (None, None, None) => {
+ let result =
+ exit_on_failed_assertion(program.execute_returning_memory_0(), "Program errored");
+ println!("{}", result);
+ }
+ _ => {
+ eprintln!("Either a noun and verb or an expected output must be provided");
+ process::exit(1);
+ }
+ }
+}
+
+fn exit_on_failed_assertion<A, E: std::error::Error>(data: Result<A, E>, message: &str) -> A {
+ match data {
+ Ok(data) => data,
+ Err(e) => {
+ eprintln!("{}: {}", message, e);
+ process::exit(1);
+ }
+ }
+}
+
+fn find_input(
+ program: &IntcodeProgram,
+ output: Intcode,
+) -> Result<(Intcode, Intcode), IntcodeProgramError> {
+ (0..99)
+ .flat_map(|noun| (0..99).map(move |verb| (Intcode::from(noun), Intcode::from(verb))))
+ .map(|(noun, verb)| {
+ (
+ noun.clone(),
+ verb.clone(),
+ program
+ .with_noun_verb_input(noun, verb)
+ .execute_returning_memory_0(),
+ )
+ })
+ .find(|(_noun, _verb, out)| *out == Ok(output.clone()))
+ .map(|(noun, verb, _out)| Ok((noun, verb)))
+ .unwrap_or(Err(IntcodeProgramError::Unknown))
+}
diff --git a/2019/src/bin/day_20.rs b/2019/src/bin/day_20.rs
new file mode 100644
index 0000000..953df75
--- /dev/null
+++ b/2019/src/bin/day_20.rs
@@ -0,0 +1,310 @@
+use rpds::rbt_set;
+use rpds::vector::Vector;
+use rpds::RedBlackTreeMap;
+use rpds::RedBlackTreeSet;
+use std::io;
+use std::io::prelude::*;
+use std::iter;
+use std::iter::FromIterator;
+use std::process;
+use structopt::StructOpt;
+
+#[derive(Debug, StructOpt)]
+#[structopt(name = "Day 20: Donut Maze")]
+/// Finds the shortest path through a maze with portals.
+///
+/// See https://adventofcode.com/2019/day/20 for details.
+struct Opt {
+ /// include the rule that going through portals changes your depth
+ #[structopt(short = "d")]
+ include_depth: bool,
+}
+
+fn main() {
+ let stdin = io::stdin();
+ let opt = Opt::from_args();
+
+ let maze = stdin
+ .lock()
+ .lines()
+ .map(|x| exit_on_failed_assertion(x, "Error reading input"))
+ .collect::<MazeBuilder>()
+ .build();
+
+ println!("{}", maze.shortest_route(opt.include_depth));
+}
+
+fn exit_on_failed_assertion<A, E: std::error::Error>(data: Result<A, E>, message: &str) -> A {
+ match data {
+ Ok(data) => data,
+ Err(e) => {
+ eprintln!("{}: {}", message, e);
+ process::exit(1);
+ }
+ }
+}
+
+struct MazeBuilder {
+ map: Vector<Vector<char>>,
+}
+
+impl FromIterator<String> for MazeBuilder {
+ fn from_iter<T: IntoIterator<Item = String>>(iter: T) -> Self {
+ MazeBuilder {
+ map: iter
+ .into_iter()
+ .map(|line| line.chars().collect())
+ .collect(),
+ }
+ }
+}
+
+impl MazeBuilder {
+ fn build(self) -> Maze {
+ Maze {
+ walls: self
+ .map
+ .iter()
+ .map(|line| line.iter().map(|ch| *ch != '.').collect())
+ .collect(),
+ portals: self.grouped_portals(),
+ entrance: self
+ .all_portals()
+ .find(|(id, _)| *id == ['A', 'A'])
+ .unwrap()
+ .1,
+ exit: self
+ .all_portals()
+ .find(|(id, _)| *id == ['Z', 'Z'])
+ .unwrap()
+ .1,
+ }
+ }
+
+ fn grouped_portals(&self) -> Vector<(Point, Point)> {
+ self.all_portals()
+ .fold(
+ (Vector::new(), RedBlackTreeMap::new()),
+ |(matched, unmatched): (
+ Vector<(Point, Point)>,
+ RedBlackTreeMap<[char; 2], Point>,
+ ),
+ (next_id, next_p)| match unmatched.get(&next_id) {
+ Some(pair) => (
+ matched.push_back(pair.clone().inside_out(
+ next_p,
+ self.map[0].len(),
+ self.map.len(),
+ )),
+ unmatched.remove(&next_id),
+ ),
+ None => (matched, unmatched.insert(next_id, next_p)),
+ },
+ )
+ .0
+ }
+
+ fn all_portals(&self) -> impl Iterator<Item = ([char; 2], Point)> + '_ {
+ self.horizontal_trailing_portals()
+ .chain(self.horizontal_leading_portals())
+ .chain(self.vertical_trailing_portals())
+ .chain(self.vertical_leading_portals())
+ }
+
+ fn horizontal_trailing_portals(&self) -> impl Iterator<Item = ([char; 2], Point)> + '_ {
+ // .XX
+ (0..self.map.len())
+ .flat_map(move |y| (0..self.map[y].len() - 2).map(move |x| Point { x, y }))
+ .filter(move |p| {
+ self.map[p.y][p.x] == '.'
+ && self.map[p.y][p.x + 1].is_alphabetic()
+ && self.map[p.y][p.x + 2].is_alphabetic()
+ })
+ .map(move |p| ([self.map[p.y][p.x + 1], self.map[p.y][p.x + 2]], p))
+ }
+
+ fn horizontal_leading_portals(&self) -> impl Iterator<Item = ([char; 2], Point)> + '_ {
+ // XX.
+ (0..self.map.len())
+ .flat_map(move |y| (0..self.map[y].len() - 2).map(move |x| Point { x, y }))
+ .filter(move |p| {
+ self.map[p.y][p.x + 2] == '.'
+ && self.map[p.y][p.x + 1].is_alphabetic()
+ && self.map[p.y][p.x].is_alphabetic()
+ })
+ .map(move |p| {
+ (
+ [self.map[p.y][p.x], self.map[p.y][p.x + 1]],
+ Point { x: p.x + 2, y: p.y },
+ )
+ })
+ }
+
+ fn vertical_trailing_portals(&self) -> impl Iterator<Item = ([char; 2], Point)> + '_ {
+ // .XX
+ (0..self.map[0].len())
+ .flat_map(move |x| (0..self.map.len() - 2).map(move |y| Point { x, y }))
+ .filter(move |p| {
+ self.map[p.y][p.x] == '.'
+ && self.map[p.y + 1][p.x].is_alphabetic()
+ && self.map[p.y + 2][p.x].is_alphabetic()
+ })
+ .map(move |p| ([self.map[p.y + 1][p.x], self.map[p.y + 2][p.x]], p))
+ }
+
+ fn vertical_leading_portals(&self) -> impl Iterator<Item = ([char; 2], Point)> + '_ {
+ // XX.
+ (0..self.map[0].len())
+ .flat_map(move |x| (0..self.map.len() - 2).map(move |y| Point { x, y }))
+ .filter(move |p| {
+ self.map[p.y + 2][p.x] == '.'
+ && self.map[p.y + 1][p.x].is_alphabetic()
+ && self.map[p.y][p.x].is_alphabetic()
+ })
+ .map(move |p| {
+ (
+ [self.map[p.y][p.x], self.map[p.y + 1][p.x]],
+ Point { x: p.x, y: p.y + 2 },
+ )
+ })
+ }
+}
+
+#[derive(Debug)]
+struct Maze {
+ walls: Vector<Vector<bool>>,
+ portals: Vector<(Point, Point)>,
+ entrance: Point, // AA
+ exit: Point, // ZZ
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
+struct Point {
+ x: usize,
+ y: usize,
+}
+
+impl Point {
+ fn add(&self, x: isize, y: isize) -> Point {
+ Point {
+ x: (self.x as isize + x) as usize,
+ y: (self.y as isize + y) as usize,
+ }
+ }
+
+ fn inside_out(self, other: Point, width: usize, height: usize) -> (Point, Point) {
+ if self.closest_side(width, height) > other.closest_side(width, height) {
+ (self, other)
+ } else {
+ (other, self)
+ }
+ }
+
+ fn closest_side(&self, width: usize, height: usize) -> usize {
+ self.x.min(width - self.x).min(self.y).min(height - self.y)
+ }
+}
+
+impl Maze {
+ fn shortest_route(&self, include_depth: bool) -> usize {
+ iter::successors(
+ Some((
+ rbt_set![(self.entrance.clone(), 0)],
+ rbt_set![(self.entrance.clone(), 0)],
+ )),
+ |(explored, locations)| {
+ Some(Maze::next_depth_states(
+ explored.clone(),
+ self.next_locations(locations, explored, include_depth),
+ ))
+ },
+ )
+ // .inspect(|(explored, states)| eprintln!("{:?}", states))
+ .take_while(|(_explored, states)| states.size() > 0)
+ .enumerate()
+ .find(|(_i, (_explored, states))| {
+ states
+ .iter()
+ .any(|(p_state, depth)| *p_state == self.exit && (!include_depth || *depth == 0))
+ })
+ .unwrap()
+ .0
+ }
+
+ fn next_depth_states(
+ explored: RedBlackTreeSet<(Point, isize)>,
+ locations: RedBlackTreeSet<(Point, isize)>,
+ ) -> (
+ RedBlackTreeSet<(Point, isize)>,
+ RedBlackTreeSet<(Point, isize)>,
+ ) {
+ (
+ locations
+ .iter()
+ .fold(explored, |acc, next| acc.insert(next.clone())),
+ locations,
+ )
+ }
+
+ fn next_locations(
+ &self,
+ locations: &RedBlackTreeSet<(Point, isize)>,
+ explored: &RedBlackTreeSet<(Point, isize)>,
+ include_depth: bool,
+ ) -> RedBlackTreeSet<(Point, isize)> {
+ locations
+ .iter()
+ .flat_map(|(p, depth)| {
+ [(-1, 0), (1, 0), (0, -1), (0, 1)]
+ .iter()
+ .map(move |(dx, dy)| (p.add(*dx, *dy), *depth))
+ .chain(
+ self.portals
+ .iter()
+ .filter(move |(from, _to)| p == from)
+ .map(move |(_from, to)| (to.clone(), depth + 1)),
+ )
+ .chain(
+ self.portals
+ .iter()
+ .filter(move |(_to, from)| p == from)
+ .map(move |(to, _from)| (to.clone(), depth - 1)),
+ )
+ })
+ .filter(|(p_next, depth)| {
+ !self.walls[p_next.y][p_next.x] && (!include_depth || *depth >= 0)
+ })
+ .filter(|state| !explored.contains(state))
+ .collect()
+ }
+}
+
+#[test]
+fn portal_maze_example_1() {
+ let maze: Maze = r" A
+ A
+ #######.#########
+ #######.........#
+ #######.#######.#
+ #######.#######.#
+ #######.#######.#
+ ##### B ###.#
+BC...## C ###.#
+ ##.## ###.#
+ ##...DE F ###.#
+ ##### G ###.#
+ #########.#####.#
+DE..#######...###.#
+ #.#########.###.#
+FG..#########.....#
+ ###########.#####
+ Z
+ Z "
+ .split('\n')
+ .map(|s| s.to_string())
+ .collect::<MazeBuilder>()
+ .build();
+
+ assert_eq!(maze.shortest_route(false), 23);
+ assert_eq!(maze.shortest_route(true), 26);
+}
diff --git a/2019/src/bin/day_21.rs b/2019/src/bin/day_21.rs
new file mode 100644
index 0000000..7fa781c
--- /dev/null
+++ b/2019/src/bin/day_21.rs
@@ -0,0 +1,109 @@
+use aoc2019::*;
+use std::io;
+use std::io::prelude::*;
+use std::process;
+use structopt::StructOpt;
+
+#[derive(Debug, StructOpt)]
+#[structopt(name = "Day 21: Springdroid Adventure")]
+/// Pilots a springdroid around!
+///
+/// See https://adventofcode.com/2019/day/21 for details.
+struct Opt {}
+
+fn main() {
+ let stdin = io::stdin();
+ let _opt = Opt::from_args();
+
+ let program: IntcodeProgram = stdin
+ .lock()
+ .split(b',')
+ .map(|x| exit_on_failed_assertion(x, "Error reading input"))
+ .map(|x| exit_on_failed_assertion(String::from_utf8(x), "Input was not valid UTF-8"))
+ .map(|x| exit_on_failed_assertion(x.trim().parse::<Intcode>(), "Invalid number"))
+ .collect::<IntcodeProgram>();
+
+ let walk_result = exit_on_failed_assertion(
+ {
+ let input = vec![
+ "NOT T T\n",
+ "AND A T\n",
+ "AND B T\n",
+ "AND C T\n",
+ "NOT T J\n",
+ "AND D J\n",
+ "WALK\n",
+ ];
+ program
+ .with_input(
+ input
+ .iter()
+ .flat_map(|line| line.chars().map(|c| Intcode::from(c as u8)))
+ .collect(),
+ )
+ .execute()
+ },
+ "Program failed",
+ );
+
+ println!(
+ "{}",
+ walk_result
+ .drop_last()
+ .unwrap()
+ .iter()
+ .flat_map(|c| c.to_signed_bytes_be())
+ .map(|c| c as char)
+ .collect::<String>()
+ );
+ println!("{}", walk_result.last().unwrap());
+
+ let run_result = exit_on_failed_assertion(
+ {
+ // (!A || !B || !C) && D && (E || H)
+ let input = vec![
+ "OR E J\n",
+ "OR H J\n",
+ "AND D J\n",
+ "NOT T T\n",
+ "AND A T\n",
+ "AND B T\n",
+ "AND C T\n",
+ "NOT T T\n",
+ "AND T J\n",
+ "RUN\n",
+ ];
+ program
+ .with_input(
+ input
+ .iter()
+ .flat_map(|line| line.chars().map(|c| Intcode::from(c as u8)))
+ .collect(),
+ )
+ .execute()
+ },
+ "Program failed",
+ );
+
+ println!(
+ "{}",
+ run_result
+ .drop_last()
+ .unwrap()
+ .iter()
+ .flat_map(|c| c.to_signed_bytes_be())
+ .map(|c| c as char)
+ .collect::<String>()
+ );
+ println!("{}", run_result.last().unwrap());
+}
+
+fn exit_on_failed_assertion<A, E: std::error::Error>(data: Result<A, E>, message: &str) -> A {
+ match data {
+ Ok(data) => data,
+ Err(e) => {
+ eprintln!("{}: {}", message, e);
+ process::exit(1);
+ }
+ }
+}
diff --git a/2019/src/bin/day_22.rs b/2019/src/bin/day_22.rs
new file mode 100644
index 0000000..5b999a6
--- /dev/null
+++ b/2019/src/bin/day_22.rs
@@ -0,0 +1,325 @@
+use derive_more::Display;
+use num::bigint::BigInt;
+use num::traits::identities::Zero;
+use num::traits::sign::abs;
+use num::traits::Signed;
+use std::fmt;
+use std::io;
+use std::io::prelude::*;
+use std::process;
+use std::str::FromStr;
+use structopt::StructOpt;
+
+#[derive(Debug, StructOpt)]
+#[structopt(name = "Day 22: Slam Shuffle")]
+/// Shuffles some cards.
+///
+/// See https://adventofcode.com/2019/day/22 for details.
+struct Opt {
+ /// The size of the deck
+ deck_size: BigInt,
+ /// At the end, query the position of card
+ card: BigInt,
+ /// Number of repetitions
+ repetitions: BigInt,
+
+ /// Prints the card in position n, rather than the position of card n
+ #[structopt(short = "p")]
+ position_mode: bool,
+}
+
+fn main() {
+ let stdin = io::stdin();
+ let opt = Opt::from_args();
+
+ let instructions = stdin
+ .lock()
+ .lines()
+ .map(|x| exit_on_failed_assertion(x, "Error reading input"))
+ .map(|x| exit_on_failed_assertion(x.parse::<Instruction>(), "Parse error"))
+ .collect::<Vec<Instruction>>();
+
+ //eprintln!("{:?}", instructions);
+
+ if opt.position_mode {
+ println!(
+ "{}",
+ instructions
+ .iter()
+ .rev()
+ .fold(
+ StandardisedInstruction::identity(opt.deck_size.clone()),
+ |acc, next| acc.then(&(next.clone(), opt.deck_size.clone(), false).into())
+ )
+ .repeat(opt.repetitions)
+ .apply(opt.card.clone())
+ );
+ } else {
+ println!(
+ "{}",
+ instructions
+ .iter()
+ .fold(
+ StandardisedInstruction::identity(opt.deck_size.clone()),
+ |acc, next| {
+ eprintln!("{}", acc);
+ acc.then(&(next.clone(), opt.deck_size.clone(), true).into())
+ }
+ )
+ .repeat(opt.repetitions)
+ .apply(opt.card.clone())
+ );
+ }
+}
+
+fn exit_on_failed_assertion<A, E: std::error::Error>(data: Result<A, E>, message: &str) -> A {
+ match data {
+ Ok(data) => data,
+ Err(e) => {
+ eprintln!("{}: {}", message, e);
+ process::exit(1);
+ }
+ }
+}
+
+fn mod_plus(a: BigInt, b: BigInt, modulus: BigInt) -> BigInt {
+ mod_normalize(a + b, modulus)
+}
+
+fn mod_sub(a: BigInt, b: BigInt, modulus: BigInt) -> BigInt {
+ mod_normalize(a - b, modulus)
+}
+
+fn mod_times(a: BigInt, b: BigInt, modulus: BigInt) -> BigInt {
+ mod_normalize(a * b, modulus)
+}
+
+fn mod_divide(a: BigInt, b: BigInt, modulus: BigInt) -> BigInt {
+ mod_times(a, mod_inverse(b, modulus.clone()), modulus)
+}
+
+fn mod_pow(a: BigInt, b: BigInt, modulus: BigInt) -> BigInt {
+ a.modpow(&b, &modulus)
+}
+
+fn mod_normalize(a: BigInt, modulus: BigInt) -> BigInt {
+ if a.is_negative() {
+ a.clone() + modulus.clone() * (1 + abs(a) / modulus)
+ } else {
+ a % modulus
+ }
+}
+
+// NB: This may give nonsense if modulus isn't coprime with a
+fn mod_inverse(a: BigInt, modulus: BigInt) -> BigInt {
+ mod_normalize(euclid_gcd_coefficients(a, modulus.clone()).0, modulus)
+}
+
+fn euclid_gcd_coefficients(a: BigInt, b: BigInt) -> (BigInt, BigInt) {
+ fn euclid_gcd_coefficients_inner(
+ r: BigInt,
+ old_r: BigInt,
+ s: BigInt,
+ old_s: BigInt,
+ t: BigInt,
+ old_t: BigInt,
+ ) -> (BigInt, BigInt) {
+ if r.is_zero() {
+ (old_s, old_t)
+ } else {
+ euclid_gcd_coefficients_inner(
+ old_r.clone() - (old_r.clone() / r.clone()) * r.clone(),
+ r.clone(),
+ old_s - (old_r.clone() / r.clone()) * s.clone(),
+ s,
+ old_t - (old_r.clone() / r) * t.clone(),
+ t,
+ )
+ }
+ }
+
+ assert!(a < b);
+
+ euclid_gcd_coefficients_inner(b, a, 0.into(), 1.into(), 1.into(), 0.into())
+}
+
+#[derive(Debug, Clone)]
+enum Instruction {
+ DealIntoNewStack,
+ Cut(BigInt),
+ ReverseCut(BigInt),
+ DealWithIncrement(BigInt),
+}
+
+impl FromStr for Instruction {
+ type Err = ParseErr;
+ fn from_str(s: &str) -> Result<Self, Self::Err> {
+ if s.starts_with("deal into new stack") {
+ Ok(Instruction::DealIntoNewStack)
+ } else if s.starts_with("cut -") {
+ s.split(' ')
+ .nth(1)
+ .map(|val| {
+ val.parse::<BigInt>()
+ .map_err(|_| ParseErr)
+ .map(|parsed| Instruction::ReverseCut(abs(parsed)))
+ })
+ .unwrap_or(Err(ParseErr))
+ } else if s.starts_with("cut") {
+ s.split(' ')
+ .nth(1)
+ .map(|val| {
+ val.parse::<BigInt>()
+ .map_err(|_| ParseErr)
+ .map(|parsed| Instruction::Cut(parsed))
+ })
+ .unwrap_or(Err(ParseErr))
+ } else if s.starts_with("deal with increment") {
+ s.split(' ')
+ .nth(3)
+ .map(|val| {
+ val.parse::<BigInt>()
+ .map_err(|_| ParseErr)
+ .map(|parsed| Instruction::DealWithIncrement(parsed))
+ })
+ .unwrap_or(Err(ParseErr))
+ } else {
+ Err(ParseErr)
+ }
+ }
+}
+
+// f(x) = ax + b mod c
+#[derive(Display, Clone)]
+#[display(fmt = "f(x) = {} x + {} % {}", a, b, modulus)]
+struct StandardisedInstruction {
+ a: BigInt,
+ b: BigInt,
+ modulus: BigInt,
+}
+
+impl From<(Instruction, BigInt, bool)> for StandardisedInstruction {
+ fn from((instruction, modulus, forward): (Instruction, BigInt, bool)) -> Self {
+ match (instruction, forward) {
+ (Instruction::DealIntoNewStack, _) => StandardisedInstruction {
+ a: BigInt::from(-1),
+ b: BigInt::from(-1),
+ modulus: modulus,
+ },
+ (Instruction::Cut(n), true) => StandardisedInstruction {
+ a: BigInt::from(1),
+ b: BigInt::from(-n),
+ modulus: modulus,
+ },
+ (Instruction::Cut(n), false) => StandardisedInstruction {
+ a: BigInt::from(1),
+ b: BigInt::from(n),
+ modulus: modulus,
+ },
+ (Instruction::ReverseCut(n), true) => StandardisedInstruction {
+ a: BigInt::from(1),
+ b: BigInt::from(n),
+ modulus: modulus,
+ },
+ (Instruction::ReverseCut(n), false) => StandardisedInstruction {
+ a: BigInt::from(1),
+ b: BigInt::from(-n),
+ modulus: modulus,
+ },
+ (Instruction::DealWithIncrement(n), true) => StandardisedInstruction {
+ a: BigInt::from(n),
+ b: BigInt::from(0),
+ modulus: modulus,
+ },
+ (Instruction::DealWithIncrement(n), false) => StandardisedInstruction {
+ a: BigInt::from(mod_inverse(n, modulus.clone())),
+ b: BigInt::from(0),
+ modulus: modulus,
+ },
+ }
+ .normalise()
+ }
+}
+
+impl StandardisedInstruction {
+ fn identity(modulus: BigInt) -> StandardisedInstruction {
+ StandardisedInstruction {
+ a: BigInt::from(1),
+ b: BigInt::from(0),
+ modulus,
+ }
+ }
+ fn normalise(&self) -> StandardisedInstruction {
+ StandardisedInstruction {
+ a: mod_normalize(self.a.clone(), self.modulus.clone()),
+ b: mod_normalize(self.b.clone(), self.modulus.clone()),
+ modulus: self.modulus.clone(),
+ }
+ }
+ fn then(&self, other: &StandardisedInstruction) -> StandardisedInstruction {
+ // g(f(x)) = ga (fa x + fb) + gb =
+ StandardisedInstruction {
+ a: mod_times(self.a.clone(), other.a.clone(), self.modulus.clone()),
+ b: mod_plus(
+ mod_times(self.b.clone(), other.a.clone(), self.modulus.clone()),
+ other.b.clone(),
+ self.modulus.clone(),
+ ),
+ modulus: self.modulus.clone(),
+ }
+ }
+ fn repeat(&self, repetitions: BigInt) -> StandardisedInstruction {
+ StandardisedInstruction {
+ a: mod_pow(self.a.clone(), repetitions.clone(), self.modulus.clone()),
+ b: mod_divide(
+ mod_times(
+ self.b.clone(),
+ mod_sub(
+ BigInt::from(1),
+ mod_pow(self.a.clone(), repetitions.clone(), self.modulus.clone()),
+ self.modulus.clone(),
+ ),
+ self.modulus.clone(),
+ ),
+ mod_sub(BigInt::from(1), self.a.clone(), self.modulus.clone()),
+ self.modulus.clone(),
+ ),
+ modulus: self.modulus.clone(),
+ }
+ }
+
+ fn apply(&self, x: BigInt) -> BigInt {
+ mod_plus(
+ mod_times(self.a.clone(), x, self.modulus.clone()),
+ self.b.clone(),
+ self.modulus.clone(),
+ )
+ }
+}
+
+#[derive(Debug, Clone, Copy)]
+struct ParseErr;
+
+impl fmt::Display for ParseErr {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f, "Error parsing input")
+ }
+}
+
+impl std::error::Error for ParseErr {}
+
+#[test]
+fn mod_inverse_of_13() {
+ assert_eq!(mod_inverse(1.into(), 13.into()), 1.into());
+ assert_eq!(mod_inverse(2.into(), 13.into()), 7.into());
+ assert_eq!(mod_inverse(3.into(), 13.into()), 9.into());
+ assert_eq!(mod_inverse(4.into(), 13.into()), 10.into());
+ assert_eq!(mod_inverse(5.into(), 13.into()), 8.into());
+ assert_eq!(mod_inverse(6.into(), 13.into()), 11.into());
+ assert_eq!(mod_inverse(7.into(), 13.into()), 2.into());
+ assert_eq!(mod_inverse(8.into(), 13.into()), 5.into());
+ assert_eq!(mod_inverse(9.into(), 13.into()), 3.into());
+ assert_eq!(mod_inverse(10.into(), 13.into()), 4.into());
+ assert_eq!(mod_inverse(11.into(), 13.into()), 6.into());
+ assert_eq!(mod_inverse(12.into(), 13.into()), 12.into());
+}
diff --git a/2019/src/bin/day_23.rs b/2019/src/bin/day_23.rs
new file mode 100644
index 0000000..e074cf4
--- /dev/null
+++ b/2019/src/bin/day_23.rs
@@ -0,0 +1,211 @@
+use aoc2019::*;
+use rpds::list;
+use rpds::list::List;
+use rpds::vector::Vector;
+use std::io;
+use std::io::prelude::*;
+use std::iter;
+use std::process;
+use structopt::StructOpt;
+
+#[derive(Debug, StructOpt)]
+#[structopt(name = "Day 23: Category Six")]
+/// Executes an Intcode program on a network of computers
+///
+/// See https://adventofcode.com/2019/day/23 for details.
+struct Opt {
+ #[structopt(short = "n", long = "network-size")]
+ network_size: usize,
+ #[structopt(long = "nat")]
+ send_nat: bool,
+}
+
+fn main() {
+ let stdin = io::stdin();
+ let opt = Opt::from_args();
+
+ let program: IntcodeProgram = stdin
+ .lock()
+ .split(b',')
+ .map(|x| exit_on_failed_assertion(x, "Error reading input"))
+ .map(|x| exit_on_failed_assertion(String::from_utf8(x), "Input was not valid UTF-8"))
+ .map(|x| exit_on_failed_assertion(x.trim().parse::<Intcode>(), "Invalid number"))
+ .collect::<IntcodeProgram>();
+
+ let network = Network::new(program, opt.network_size);
+
+ if opt.send_nat {
+ println!("{}", network.first_repeated_nat_packet().y);
+ } else {
+ println!("{}", network.first_nat_packet().y);
+ }
+}
+
+fn exit_on_failed_assertion<A, E: std::error::Error>(data: Result<A, E>, message: &str) -> A {
+ match data {
+ Ok(data) => data,
+ Err(e) => {
+ eprintln!("{}: {}", message, e);
+ process::exit(1);
+ }
+ }
+}
+
+#[derive(Debug, Clone)]
+struct Network {
+ computers: Vector<IntcodeProgram>,
+ nat: Option<Packet>,
+ is_potentially_idle: bool,
+ is_idle: bool,
+}
+
+impl Network {
+ fn new(program: IntcodeProgram, network_size: usize) -> Network {
+ Network {
+ computers: (0..network_size)
+ .map(|ip| program.with_input(list![ip.into(), Intcode::from(-1)]))
+ .collect(),
+ nat: None,
+ is_potentially_idle: false,
+ is_idle: false,
+ }
+ }
+
+ fn first_nat_packet(&self) -> Packet {
+ iter::successors(Some(self.clone()), |network| Some(network.next()))
+ .filter_map(|network| network.nat)
+ .next()
+ .unwrap()
+ }
+
+ fn first_repeated_nat_packet(&self) -> Packet {
+ self.sent_nat_packets()
+ .zip(self.sent_nat_packets().skip(1))
+ // .inspect(|(nat, _p2)| eprintln!("{}", nat.y))
+ .find(|(p1, p2)| p1.y == p2.y)
+ .unwrap()
+ .0
+ }
+
+ fn sent_nat_packets<'a>(&'a self) -> impl Iterator<Item = Packet> + 'a {
+ iter::successors(Some(self.clone()), |network| {
+ Some(network.with_nat_packet_sent().run_to_network_idle())
+ })
+ .filter_map(|network| network.nat)
+ }
+
+ fn run_to_network_idle(&self) -> Network {
+ iter::successors(Some(self.clone()), |network| Some(network.next()))
+ .find(|network| network.is_idle)
+ .unwrap()
+ }
+
+ fn with_nat_packet_sent(&self) -> Network {
+ if self.nat.is_some() {
+ Network {
+ computers: self
+ .computers
+ .iter()
+ .enumerate()
+ .map(|(ip, computer)| {
+ computer
+ .with_additional_input(
+ self.nat
+ .iter()
+ .filter(|packet| packet.dest == Intcode::from(ip))
+ .flat_map(|packet| vec![packet.x.clone(), packet.y.clone()])
+ .collect(),
+ )
+ .run_to_termination_or_input()
+ })
+ .collect(),
+ nat: self.nat.clone(),
+ is_potentially_idle: false,
+ is_idle: false,
+ }
+ } else {
+ self.clone()
+ }
+ }
+
+ fn next(&self) -> Network {
+ Network {
+ computers: self
+ .computers
+ .iter()
+ .enumerate()
+ .map(|(ip, computer)| {
+ computer
+ .with_cleared_output()
+ .with_additional_input(if self.empty_queues() {
+ list![Intcode::from(-1)]
+ } else {
+ list![]
+ })
+ .with_additional_input(
+ self.pending_packets()
+ .filter(|packet| packet.dest == Intcode::from(ip))
+ .flat_map(|packet| vec![packet.x, packet.y])
+ .collect(),
+ )
+ .run_to_termination_or_input()
+ })
+ .collect(),
+ nat: self
+ .pending_packets()
+ .filter(|packet| packet.is_nat())
+ .map(|packet| packet.with_dest(0.into()))
+ .last()
+ .or_else(|| self.nat.clone()),
+ is_potentially_idle: self.empty_queues(),
+ is_idle: self.is_potentially_idle && self.empty_queues(),
+ }
+ }
+
+ fn pending_packets<'a>(&'a self) -> impl Iterator<Item = Packet> + 'a {
+ self.computers.iter().flat_map(|computer| {
+ computer
+ .output
+ .iter()
+ .cloned()
+ .collect::<Vec<Intcode>>()
+ .chunks_exact(3)
+ .map(|packet| Packet {
+ dest: packet[0].clone(),
+ x: packet[1].clone(),
+ y: packet[2].clone(),
+ })
+ .collect::<Vec<Packet>>()
+ })
+ }
+
+ fn pending_input<'a>(&'a self) -> impl Iterator<Item = Intcode> + 'a {
+ self.computers
+ .iter()
+ .flat_map(|computer| computer.input.iter().cloned().collect::<Vec<Intcode>>())
+ }
+
+ fn empty_queues(&self) -> bool {
+ self.pending_packets().count() == 0 && self.pending_input().count() == 0
+ }
+}
+
+#[derive(Debug, Clone)]
+struct Packet {
+ dest: Intcode,
+ x: Intcode,
+ y: Intcode,
+}
+
+impl Packet {
+ fn is_nat(&self) -> bool {
+ self.dest == 255.into()
+ }
+
+ fn with_dest(&self, dest: Intcode) -> Packet {
+ Packet {
+ dest,
+ ..self.clone()
+ }
+ }
+}
diff --git a/2019/src/bin/day_24.rs b/2019/src/bin/day_24.rs
new file mode 100644
index 0000000..ebc6a1b
--- /dev/null
+++ b/2019/src/bin/day_24.rs
@@ -0,0 +1,239 @@
+use rpds::RedBlackTreeSet;
+use std::io;
+use std::io::prelude::*;
+use std::iter;
+use std::iter::FromIterator;
+use std::process;
+use structopt::StructOpt;
+
+#[derive(Debug, StructOpt)]
+#[structopt(name = "Day 24: Planet of Discord")]
+/// Simulates the life and death of Eris bugs
+///
+/// See https://adventofcode.com/2019/day/24 for details.
+struct Opt {
+ /// How many iterations of the game of life should be run
+ /// If not provided, runs until a state appears twice.
+ #[structopt(short = "n")]
+ depth: Option<usize>,
+ /// Interprets the map as being one part of an infinite fractal map
+ #[structopt(short = "f")]
+ fractal: bool,
+}
+
+fn main() {
+ let stdin = io::stdin();
+ let opt = Opt::from_args();
+
+ let initial_state: State = stdin
+ .lock()
+ .lines()
+ .map(|x| exit_on_failed_assertion(x, "Error reading input"))
+ .collect::<State>()
+ .with_fractal_mode(opt.fractal);
+
+ let final_state = match opt.depth {
+ Some(depth) => initial_state.n_steps_forward(depth),
+ None => initial_state.first_repeated_state(),
+ };
+
+ println!("Bugs: {}", final_state.alive.size());
+ println!("Biodiversity: {}", final_state.biodiversity_rating());
+}
+
+fn exit_on_failed_assertion<A, E: std::error::Error>(data: Result<A, E>, message: &str) -> A {
+ match data {
+ Ok(data) => data,
+ Err(e) => {
+ eprintln!("{}: {}", message, e);
+ process::exit(1);
+ }
+ }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
+struct State {
+ alive: RedBlackTreeSet<Coordinate>,
+ fractal_mode: bool,
+}
+
+impl FromIterator<String> for State {
+ fn from_iter<T: IntoIterator<Item = String>>(iter: T) -> Self {
+ State {
+ alive: iter
+ .into_iter()
+ .enumerate()
+ .flat_map(move |(y, line)| {
+ line.chars()
+ .enumerate()
+ .filter(move |(_x, c)| *c == '#')
+ .map(move |(x, _c)| Coordinate {
+ x: x as isize,
+ y: y as isize,
+ depth: 0,
+ })
+ .collect::<Vec<Coordinate>>()
+ })
+ .collect(),
+ fractal_mode: false,
+ }
+ }
+}
+
+impl State {
+ fn with_fractal_mode(&self, fractal_mode: bool) -> State {
+ State {
+ fractal_mode,
+ ..self.clone()
+ }
+ }
+
+ fn n_steps_forward(&self, n: usize) -> Self {
+ iter::successors(Some(self.clone()), |state| Some(state.next()))
+ .nth(n)
+ .unwrap()
+ }
+
+ fn first_repeated_state(&self) -> State {
+ iter::successors(
+ Some((RedBlackTreeSet::new(), self.clone())),
+ |(seen, state)| Some((seen.insert(state.clone()), state.next())),
+ )
+ .find(|(seen, state)| seen.contains(state))
+ .unwrap()
+ .1
+ }
+
+ fn next(&self) -> State {
+ State {
+ alive: self
+ .still_alive_next_round()
+ .chain(self.comes_alive_next_round())
+ .collect(),
+ ..self.clone()
+ }
+ }
+
+ fn biodiversity_rating(&self) -> usize {
+ self.alive
+ .iter()
+ .map(|coord| 2_usize.pow((coord.y * 5 + coord.x) as u32))
+ .sum()
+ }
+
+ fn still_alive_next_round<'a>(&'a self) -> impl Iterator<Item = Coordinate> + 'a {
+ self.alive
+ .iter()
+ .filter(move |coord| self.count_alive_neighbours(**coord) == 1)
+ .cloned()
+ }
+
+ fn comes_alive_next_round<'a>(&'a self) -> impl Iterator<Item = Coordinate> + 'a {
+ self.alive
+ .iter()
+ .flat_map(move |coord| self.neighbours(*coord))
+ .filter(move |coord| !self.alive.contains(coord))
+ .filter(move |coord| {
+ self.count_alive_neighbours(*coord) == 1 || self.count_alive_neighbours(*coord) == 2
+ })
+ }
+
+ fn count_alive_neighbours(&self, coordinate: Coordinate) -> usize {
+ self.neighbours(coordinate)
+ .into_iter()
+ .filter(|coord| self.alive.contains(coord))
+ .count()
+ }
+
+ fn neighbours(&self, coordinate: Coordinate) -> Vec<Coordinate> {
+ if self.fractal_mode {
+ [(-1, 0), (1, 0), (0, -1), (0, 1)]
+ .into_iter()
+ .map(|(dx, dy)| Coordinate {
+ x: coordinate.x + dx,
+ y: coordinate.y + dy,
+ depth: coordinate.depth,
+ })
+ .flat_map(move |coord| match (coord.x, coord.y) {
+ (x, _y) if x < 0 => vec![Coordinate {
+ x: 1,
+ y: 2,
+ depth: coord.depth - 1,
+ }]
+ .into_iter(),
+ (_x, y) if y < 0 => vec![Coordinate {
+ x: 2,
+ y: 1,
+ depth: coord.depth - 1,
+ }]
+ .into_iter(),
+ (x, _y) if x >= 5 => vec![Coordinate {
+ x: 3,
+ y: 2,
+ depth: coord.depth - 1,
+ }]
+ .into_iter(),
+ (_x, y) if y >= 5 => vec![Coordinate {
+ x: 2,
+ y: 3,
+ depth: coord.depth - 1,
+ }]
+ .into_iter(),
+ (2, 2) => match (coordinate.x, coordinate.y) {
+ (1, 2) => (0..5)
+ .map(|y| Coordinate {
+ x: 0,
+ y,
+ depth: coord.depth + 1,
+ })
+ .collect::<Vec<_>>()
+ .into_iter(),
+ (2, 1) => (0..5)
+ .map(|x| Coordinate {
+ x,
+ y: 0,
+ depth: coord.depth + 1,
+ })
+ .collect::<Vec<_>>()
+ .into_iter(),
+ (3, 2) => (0..5)
+ .map(|y| Coordinate {
+ x: 4,
+ y,
+ depth: coord.depth + 1,
+ })
+ .collect::<Vec<_>>()
+ .into_iter(),
+ (2, 3) => (0..5)
+ .map(|x| Coordinate {
+ x,
+ y: 4,
+ depth: coord.depth + 1,
+ })
+ .collect::<Vec<_>>()
+ .into_iter(),
+ (_, _) => vec![].into_iter(),
+ },
+ _ => vec![coord.clone()].into_iter(),
+ })
+ .collect()
+ } else {
+ [(-1, 0), (1, 0), (0, -1), (0, 1)]
+ .into_iter()
+ .map(|(dx, dy)| Coordinate {
+ x: coordinate.x + dx,
+ y: coordinate.y + dy,
+ depth: coordinate.depth,
+ })
+ .filter(|coord| coord.x >= 0 && coord.x < 5 && coord.y >= 0 && coord.y < 5)
+ .collect()
+ }
+ }
+}
+
+#[derive(Debug, Clone, Copy, PartialOrd, Ord, PartialEq, Eq)]
+struct Coordinate {
+ x: isize,
+ y: isize,
+ depth: isize,
+}
diff --git a/2019/src/bin/day_25.dot b/2019/src/bin/day_25.dot
new file mode 100644
index 0000000..58dc131
--- /dev/null
+++ b/2019/src/bin/day_25.dot
@@ -0,0 +1,43 @@
+digraph {
+ Breach [label="Hull Breach"]
+ Crew [label="Crew Quarters (antenna)"]
+ Hallway [label="Hallway (weather machine)"]
+ Storage [label="Storage (klein bottle)"]
+ Stables [label="Stables (spool of cat6)"]
+ Warp [label="Warp Drive Maintenance"]
+ Security [label="Security Checkpoint"]
+ Pressure [label="Pressure-Sensitive Floor"]
+ Gift [label="Gift Wrapping Center"]
+ Sick [label="Sick Bay (infinite loop X)"]
+ Chocolate [label="Hot Chocolate Fountain (giant electromagnet X)"]
+ Observatory [label="Observatory (cake)"]
+ Navigation [label="Navigation (escape pod XX)"]
+ Corridor [label="Corridor"]
+ Holodeck [label="Holodeck (molten lava X)"]
+ Science [label="Science Lab (tambourine)"]
+ Passages [label="Passages (shell)"]
+ Engineering [label="Engineering"]
+ Arcade [label="Arcade (photons X)"]
+ Kitchen [label="Kitchen (mug)"]
+
+
+ Breach -> Crew [label=East]
+ Breach -> Hallway [label=North]
+ Hallway -> Storage [label=North]
+ Storage -> Stables [label=East]
+ Stables -> Warp [label=South]
+ Warp -> Security [label=South]
+ Security -> Pressure [label=East]
+ Stables -> Gift [label=East]
+ Gift -> Sick [label=North]
+ Sick -> Chocolate [label=West]
+ Chocolate -> Observatory [label=North]
+ Chocolate -> Navigation [label=West]
+ Corridor -> Holodeck [label=North]
+ Holodeck -> Science [label=North]
+ Sick -> Corridor [label=East]
+ Corridor -> Passages [label=South]
+ Passages -> Engineering [label=East]
+ Engineering -> Arcade [label=South]
+ Gift -> Kitchen [label=South]
+}
diff --git a/2019/src/bin/day_25.rs b/2019/src/bin/day_25.rs
new file mode 100644
index 0000000..522789e
--- /dev/null
+++ b/2019/src/bin/day_25.rs
@@ -0,0 +1,110 @@
+use aoc2019::*;
+use std::io;
+use std::io::prelude::*;
+use std::process;
+use structopt::StructOpt;
+
+#[derive(Debug, StructOpt)]
+#[structopt(name = "Day 25: Cryostasis")]
+/// Pilots a robot to save Santa!
+///
+/// See https://adventofcode.com/2019/day/25 for details.
+struct Opt {}
+
+fn main() {
+ let stdin = io::stdin();
+ let _opt = Opt::from_args();
+
+ let program: IntcodeProgram = stdin
+ .lock()
+ .split(b',')
+ .map(|x| exit_on_failed_assertion(x, "Error reading input"))
+ .map(|x| exit_on_failed_assertion(String::from_utf8(x), "Input was not valid UTF-8"))
+ .map(|x| exit_on_failed_assertion(x.trim().parse::<Intcode>(), "Invalid number"))
+ .collect::<IntcodeProgram>();
+
+ let input = vec![
+ "east",
+ "take antenna",
+ "west",
+ "north",
+ "take weather machine",
+ "north",
+ "take klein bottle",
+ "east",
+ "take spool of cat6",
+ "east",
+ "south",
+ "take mug",
+ "north",
+ "north",
+ "west",
+ "north",
+ "take cake",
+ "south",
+ "east",
+ "east",
+ "north",
+ "north",
+ "take tambourine",
+ "south",
+ "south",
+ "south",
+ "take shell",
+ "north",
+ "west",
+ "south",
+ "west",
+ "south",
+ "south",
+ "inv",
+ //"drop mug",
+ //"drop weather machine",
+ "drop cake",
+ "drop shell",
+ "drop klein bottle",
+ "drop tambourine",
+ //"drop antenna",
+ //"drop spool of cat6",
+ "east",
+ ];
+
+ let result = exit_on_failed_assertion(
+ program
+ .with_input(
+ input
+ .iter()
+ .flat_map(|line| {
+ line.chars()
+ .map(|c| Intcode::from(c as u8))
+ .chain(vec![Intcode::from(10)].into_iter())
+ })
+ .collect(),
+ )
+ .run_to_termination_or_input()
+ .output_into_result(),
+ "Program failed",
+ );
+
+ println!(
+ "{}",
+ result
+ .drop_last()
+ .unwrap()
+ .iter()
+ .flat_map(|c| c.to_signed_bytes_be())
+ .map(|c| c as char)
+ .collect::<String>()
+ );
+ println!("{}", result.last().unwrap());
+}
+
+fn exit_on_failed_assertion<A, E: std::error::Error>(data: Result<A, E>, message: &str) -> A {
+ match data {
+ Ok(data) => data,
+ Err(e) => {
+ eprintln!("{}: {}", message, e);
+ process::exit(1);
+ }
+ }
+}
diff --git a/2019/src/bin/day_3.rs b/2019/src/bin/day_3.rs
new file mode 100644
index 0000000..f4163bd
--- /dev/null
+++ b/2019/src/bin/day_3.rs
@@ -0,0 +1,333 @@
+use rpds::vector::Vector;
+use std::fmt;
+use std::io;
+use std::io::prelude::*;
+use std::process;
+use std::str::FromStr;
+use structopt::StructOpt;
+
+#[derive(Debug, StructOpt)]
+#[structopt(name = "Day 3: Crossed Wires")]
+/// Finds the closest intersection between two wires. By default,
+/// 'closest' is defined as closest in terms of Manhattan distance. If
+/// --signal-distance is set, distance is defined in terms of the
+/// total distance along the wire.
+///
+/// See https://adventofcode.com/2019/day/3 for details.
+struct Opt {
+ #[structopt(short = "s", long = "signal-distance")]
+ /// returns the closest intersection by signal distance.
+ signal_distance: bool,
+}
+
+fn main() {
+ let stdin = io::stdin();
+ let opt = Opt::from_args();
+
+ let mut input = stdin
+ .lock()
+ .lines()
+ .map(|x| exit_on_failed_assertion(x, "Error reading input"))
+ .map(|x| exit_on_failed_assertion(x.parse::<Wire>(), "Input was not a valid wire"));
+
+ let (wire1, wire2) = match (input.next(), input.next()) {
+ (Some(w1), Some(w2)) => (w1, w2),
+ _ => {
+ eprintln!("Input must have two wires");
+ process::exit(1);
+ }
+ };
+
+ match wire1.closest_collision(&wire2, opt.signal_distance) {
+ Some(c) => println!(
+ "{}",
+ if opt.signal_distance {
+ c.signal_distance
+ } else {
+ c.manhattan_distance()
+ }
+ ),
+ None => {
+ eprintln!("No collisions");
+ process::exit(1);
+ }
+ }
+}
+
+fn exit_on_failed_assertion<A, E: std::error::Error>(data: Result<A, E>, message: &str) -> A {
+ match data {
+ Ok(data) => data,
+ Err(e) => {
+ eprintln!("{}: {}", message, e);
+ process::exit(1);
+ }
+ }
+}
+
+#[derive(Debug, Clone)]
+struct Wire {
+ segments: Vector<WireSegment>,
+}
+
+impl FromStr for Wire {
+ type Err = UnknownError;
+
+ fn from_str(s: &str) -> Result<Self, UnknownError> {
+ s.split(',')
+ .fold(
+ Ok(Vector::new()),
+ |acc: Result<Vector<WireSegment>, UnknownError>, next_str| {
+ acc.and_then(|previous_segments| {
+ WireSegment::from_str(
+ previous_segments.last().map(|l| l.end()).unwrap_or((0, 0)),
+ previous_segments
+ .last()
+ .map(|l| l.end_signal_distance())
+ .unwrap_or(0),
+ next_str,
+ )
+ .map(|seg| previous_segments.push_back(seg))
+ })
+ },
+ )
+ .map(|segments| Wire { segments })
+ }
+}
+
+impl Wire {
+ fn closest_collision(&self, other: &Wire, use_signal_distance: bool) -> Option<Collision> {
+ self.collisions(other).min_by_key(|c| {
+ if use_signal_distance {
+ c.signal_distance
+ } else {
+ c.manhattan_distance()
+ }
+ })
+ }
+
+ fn collisions<'a>(&'a self, other: &'a Wire) -> impl Iterator<Item = Collision> + 'a {
+ self.segments
+ .iter()
+ .flat_map(move |seg1| other.segments.iter().map(move |seg2| (seg1, seg2)))
+ .flat_map(|(seg1, seg2)| seg1.collisions(seg2))
+ .filter(|c| !(c.x == 0 && c.y == 0))
+ }
+}
+
+#[derive(Debug, Clone)]
+struct WireSegment {
+ start: (i32, i32),
+ start_signal_distance: i32,
+ direction: Direction,
+ length: i32,
+}
+
+impl WireSegment {
+ fn from_str(
+ start: (i32, i32),
+ start_signal_distance: i32,
+ s: &str,
+ ) -> Result<Self, UnknownError> {
+ s.parse::<Direction>().and_then(|direction| {
+ WireSegment::length_from_str(s).map(|length| WireSegment {
+ start,
+ start_signal_distance,
+ direction,
+ length,
+ })
+ })
+ }
+
+ fn length_from_str(s: &str) -> Result<i32, UnknownError> {
+ s.chars()
+ .skip(1)
+ .collect::<String>()
+ .parse()
+ .map_err(|_| UnknownError)
+ }
+
+ fn end(&self) -> (i32, i32) {
+ (
+ self.start.0 + self.direction.as_vec().0 * self.length,
+ self.start.1 + self.direction.as_vec().1 * self.length,
+ )
+ }
+
+ fn end_signal_distance(&self) -> i32 {
+ self.start_signal_distance + self.length
+ }
+
+ fn collisions(&self, other: &WireSegment) -> Option<Collision> {
+ use Direction::*;
+
+ match (self.direction, other.direction) {
+ (Left, Left) | (Right, Right) | (Up, Up) | (Down, Down) => None,
+ (Left, Right) | (Right, Left) | (Up, Down) | (Down, Up) => None,
+ (Left, Up) => collisions(
+ self.end(),
+ self.end_signal_distance(),
+ self.length,
+ -1,
+ other.start,
+ other.start_signal_distance,
+ other.length,
+ 1,
+ ),
+ (Left, Down) => collisions(
+ self.end(),
+ self.end_signal_distance(),
+ self.length,
+ -1,
+ other.end(),
+ other.end_signal_distance(),
+ other.length,
+ -1,
+ ),
+ (Right, Up) => collisions(
+ self.start,
+ self.start_signal_distance,
+ self.length,
+ 1,
+ other.start,
+ other.start_signal_distance,
+ other.length,
+ 1,
+ ),
+ (Right, Down) => collisions(
+ self.start,
+ self.start_signal_distance,
+ self.length,
+ 1,
+ other.end(),
+ other.end_signal_distance(),
+ other.length,
+ -1,
+ ),
+ (Down, Right) => collisions(
+ other.start,
+ other.start_signal_distance,
+ other.length,
+ 1,
+ self.end(),
+ self.end_signal_distance(),
+ self.length,
+ -1,
+ ),
+ (Down, Left) => collisions(
+ other.end(),
+ other.end_signal_distance(),
+ other.length,
+ -1,
+ self.end(),
+ self.end_signal_distance(),
+ self.length,
+ -1,
+ ),
+ (Up, Right) => collisions(
+ other.start,
+ other.start_signal_distance,
+ other.length,
+ 1,
+ self.start,
+ self.start_signal_distance,
+ self.length,
+ 1,
+ ),
+ (Up, Left) => collisions(
+ other.end(),
+ other.end_signal_distance(),
+ other.length,
+ -1,
+ self.start,
+ self.start_signal_distance,
+ self.length,
+ 1,
+ ),
+ }
+ }
+}
+
+fn collisions(
+ horizontal_start: (i32, i32),
+ horizontal_start_signal_distance: i32,
+ horizontal_length: i32,
+ horizontal_signal_distance_multiplier: i32,
+ vertical_start: (i32, i32),
+ vertical_start_signal_distance: i32,
+ vertical_length: i32,
+ vertical_signal_distance_multiplier: i32,
+) -> Option<Collision> {
+ if horizontal_start.1 >= vertical_start.1
+ && horizontal_start.1 <= vertical_start.1 + vertical_length
+ && vertical_start.0 >= horizontal_start.0
+ && vertical_start.0 <= horizontal_start.0 + horizontal_length
+ {
+ Some(Collision {
+ x: vertical_start.0,
+ y: horizontal_start.1,
+ signal_distance: horizontal_start_signal_distance
+ + (vertical_start.0 - horizontal_start.0) * horizontal_signal_distance_multiplier
+ + vertical_start_signal_distance
+ + (horizontal_start.1 - vertical_start.1) * vertical_signal_distance_multiplier,
+ })
+ } else {
+ None
+ }
+}
+
+#[derive(Debug, Clone, Copy)]
+enum Direction {
+ Up,
+ Down,
+ Left,
+ Right,
+}
+
+impl FromStr for Direction {
+ type Err = UnknownError;
+
+ fn from_str(s: &str) -> Result<Self, UnknownError> {
+ use Direction::*;
+ match s.chars().next() {
+ Some('L') => Ok(Left),
+ Some('R') => Ok(Right),
+ Some('U') => Ok(Up),
+ Some('D') => Ok(Down),
+ Some(_) => Err(UnknownError),
+ None => Err(UnknownError),
+ }
+ }
+}
+impl Direction {
+ fn as_vec(&self) -> (i32, i32) {
+ use Direction::*;
+ match self {
+ Up => (0, 1),
+ Down => (0, -1),
+ Left => (-1, 0),
+ Right => (1, 0),
+ }
+ }
+}
+
+struct Collision {
+ x: i32,
+ y: i32,
+ signal_distance: i32,
+}
+
+impl Collision {
+ fn manhattan_distance(&self) -> i32 {
+ self.x.abs() + self.y.abs()
+ }
+}
+
+#[derive(Debug, PartialEq)]
+struct UnknownError;
+
+impl fmt::Display for UnknownError {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f, "Unknown error")
+ }
+}
+impl std::error::Error for UnknownError {}
diff --git a/2019/src/bin/day_4.rs b/2019/src/bin/day_4.rs
new file mode 100644
index 0000000..d7d6b69
--- /dev/null
+++ b/2019/src/bin/day_4.rs
@@ -0,0 +1,55 @@
+use structopt::StructOpt;
+
+#[derive(Debug, StructOpt)]
+#[structopt(name = "Day 4: Secure Container")]
+/// Calculates how many possible lock values there are
+///
+/// See https://adventofcode.com/2019/day/4 for details.
+struct Opt {
+ /// Repeated digits must be exactly 2 long
+ #[structopt(long = "larger-range-rule")]
+ larger_range_rule: bool,
+ min: u32,
+ max: u32,
+}
+
+fn main() {
+ let opt = Opt::from_args();
+
+ println!(
+ "{}",
+ valid_combinations(opt.min, opt.max, opt.larger_range_rule)
+ )
+}
+
+fn valid_combinations(min: u32, max: u32, larger_range_rule: bool) -> u32 {
+ (min..max)
+ .filter(|x| {
+ two_adjacent_identical_digits(*x, larger_range_rule) && digits_never_decrease(*x)
+ })
+ .count() as u32
+}
+
+fn two_adjacent_identical_digits(x: u32, larger_range_rule: bool) -> bool {
+ if larger_range_rule {
+ (0..5).any(|d| {
+ digit(x, d) == digit(x, d + 1)
+ && digit(x, d) != digit(x, d + 2)
+ && digit(x, d) != digit(x, d - 1)
+ })
+ } else {
+ (0..5).any(|d| digit(x, d) == digit(x, d + 1))
+ }
+}
+
+fn digits_never_decrease(x: u32) -> bool {
+ (0..5).all(|d| digit(x, d) >= digit(x, d + 1))
+}
+
+fn digit(x: u32, digit: i32) -> u32 {
+ if digit < 0 {
+ 0
+ } else {
+ (x / 10u32.pow(digit as u32)) % 10
+ }
+}
diff --git a/2019/src/bin/day_5.rs b/2019/src/bin/day_5.rs
new file mode 100644
index 0000000..07f7af8
--- /dev/null
+++ b/2019/src/bin/day_5.rs
@@ -0,0 +1,45 @@
+use aoc2019::*;
+use std::io;
+use std::io::prelude::*;
+use std::process;
+use structopt::StructOpt;
+
+#[derive(Debug, StructOpt)]
+#[structopt(name = "Day 5: Sunny with a Chance of Asteroids")]
+/// Executes an Intcode program
+///
+/// The program is read from stdin as a series of comma-separated
+/// values. Newlines are ignored.
+///
+/// See https://adventofcode.com/2019/day/5 for details.
+struct Opt {
+ #[structopt(short = "i", long = "input")]
+ input: Vec<Intcode>,
+}
+
+fn main() {
+ let stdin = io::stdin();
+ let opt = Opt::from_args();
+
+ let program: IntcodeProgram = stdin
+ .lock()
+ .split(b',')
+ .map(|x| exit_on_failed_assertion(x, "Error reading input"))
+ .map(|x| exit_on_failed_assertion(String::from_utf8(x), "Input was not valid UTF-8"))
+ .map(|x| exit_on_failed_assertion(x.trim().parse::<Intcode>(), "Invalid number"))
+ .collect::<IntcodeProgram>()
+ .with_input(opt.input.into_iter().collect());
+
+ let result = exit_on_failed_assertion(program.execute(), "Program errored");
+ println!("{}", result);
+}
+
+fn exit_on_failed_assertion<A, E: std::error::Error>(data: Result<A, E>, message: &str) -> A {
+ match data {
+ Ok(data) => data,
+ Err(e) => {
+ eprintln!("{}: {}", message, e);
+ process::exit(1);
+ }
+ }
+}
diff --git a/2019/src/bin/day_6.rs b/2019/src/bin/day_6.rs
new file mode 100644
index 0000000..2af272c
--- /dev/null
+++ b/2019/src/bin/day_6.rs
@@ -0,0 +1,251 @@
+use rpds::vector::Vector;
+use std::fmt;
+use std::io;
+use std::io::prelude::*;
+use std::iter::FromIterator;
+use std::process;
+use std::str::FromStr;
+use structopt::StructOpt;
+
+#[derive(Debug, StructOpt)]
+#[structopt(name = "Day 6: Universal Orbit Map")]
+/// Finds the minumum number of orbital transfers between two points.
+///
+/// Input is read from stdin, one direct orbit per line, in the format
+/// `A)B` (B is orbiting A).
+///
+/// See https://adventofcode.com/2019/day/6 for details.
+struct Opt {
+ /// Debug checksum: Counts the total orbits
+ #[structopt(short = "d", long = "debug")]
+ debug: bool,
+}
+
+fn main() {
+ let stdin = io::stdin();
+ let opt = Opt::from_args();
+
+ let orbits: OrbitalMap = stdin
+ .lock()
+ .lines()
+ .map(|x| exit_on_failed_assertion(x, "Error reading input"))
+ .map(|x| exit_on_failed_assertion(x.parse::<Orbit>(), "Input was not a valid orbit"))
+ .collect();
+
+ // eprintln!("{:#?}", orbits);
+
+ if opt.debug {
+ println!("{}", orbits.total_orbits());
+ } else {
+ println!("{}", orbits.orbital_transfers("YOU", "SAN"));
+ }
+}
+
+fn exit_on_failed_assertion<A, E: std::error::Error>(data: Result<A, E>, message: &str) -> A {
+ match data {
+ Ok(data) => data,
+ Err(e) => {
+ eprintln!("{}: {}", message, e);
+ process::exit(1);
+ }
+ }
+}
+
+#[derive(Debug)]
+struct StrError {
+ str: String,
+}
+
+impl fmt::Display for StrError {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f, "{}", self.str)
+ }
+}
+impl std::error::Error for StrError {}
+
+#[derive(Debug, Clone)]
+struct Orbit {
+ a: String,
+ b: String,
+}
+
+impl FromStr for Orbit {
+ type Err = StrError;
+
+ fn from_str(s: &str) -> Result<Self, StrError> {
+ match s.split(')').collect::<Vec<_>>()[..] {
+ [a, b] => Ok(Orbit {
+ a: a.to_string(),
+ b: b.to_string(),
+ }),
+ _ => Err(StrError {
+ str: format!("{} is not a valid orbit description", s),
+ }),
+ }
+ }
+}
+
+#[derive(Clone, Debug)]
+struct OrbitalMap {
+ id: String,
+ depth: usize,
+ orbiters: Vector<OrbitalMap>,
+}
+
+struct OrbitalMapBuilder {
+ orbiters: Vector<OrbitalMap>,
+ inserted_orbits: Vector<String>,
+ pending_orbits: Vector<Orbit>,
+}
+
+impl FromIterator<Orbit> for OrbitalMap {
+ fn from_iter<T: IntoIterator<Item = Orbit>>(iter: T) -> Self {
+ iter.into_iter().collect::<OrbitalMapBuilder>().build()
+ }
+}
+
+impl FromIterator<Orbit> for OrbitalMapBuilder {
+ fn from_iter<T: IntoIterator<Item = Orbit>>(iter: T) -> Self {
+ OrbitalMapBuilder {
+ orbiters: Vector::new(),
+ inserted_orbits: Vector::new(),
+ pending_orbits: iter.into_iter().collect(),
+ }
+ }
+}
+
+impl OrbitalMapBuilder {
+ fn build(self) -> OrbitalMap {
+ if self.pending_orbits.is_empty() {
+ OrbitalMap {
+ id: ROOT.into(),
+ depth: 0,
+ orbiters: self.orbiters,
+ }
+ } else {
+ self.pending_orbits
+ .into_iter()
+ .fold(
+ OrbitalMapBuilder {
+ pending_orbits: Vector::new(),
+ ..self
+ },
+ |acc, next| acc.insert(&next),
+ )
+ .build()
+ }
+ }
+
+ fn insert(self, orbit: &Orbit) -> OrbitalMapBuilder {
+ if orbit.a == ROOT {
+ OrbitalMapBuilder {
+ orbiters: self.orbiters.push_back(OrbitalMap::new(orbit.b.clone(), 1)),
+ inserted_orbits: self.inserted_orbits.push_back(orbit.b.clone()),
+ ..self
+ }
+ } else if self.inserted_orbits.iter().any(|o| *o == orbit.a) {
+ OrbitalMapBuilder {
+ orbiters: self
+ .orbiters
+ .into_iter()
+ .map(|map| OrbitalMap::insert(map.clone(), orbit))
+ .collect(),
+ inserted_orbits: self.inserted_orbits.push_back(orbit.b.clone()),
+ ..self
+ }
+ } else {
+ OrbitalMapBuilder {
+ pending_orbits: self.pending_orbits.push_back(orbit.clone()),
+ ..self
+ }
+ }
+ }
+}
+
+const ROOT: &str = "COM";
+
+impl OrbitalMap {
+ fn new(id: String, depth: usize) -> OrbitalMap {
+ OrbitalMap {
+ id,
+ depth,
+ orbiters: Vector::new(),
+ }
+ }
+
+ fn insert(self, orbit: &Orbit) -> OrbitalMap {
+ if orbit.a == self.id {
+ if self.orbiters.iter().any(|o| o.id == orbit.b) {
+ self
+ } else {
+ OrbitalMap {
+ orbiters: self
+ .orbiters
+ .push_back(OrbitalMap::new(orbit.b.clone(), self.depth + 1)),
+ ..self
+ }
+ }
+ } else {
+ OrbitalMap {
+ orbiters: self
+ .orbiters
+ .into_iter()
+ .map(|map| OrbitalMap::insert(map.clone(), orbit))
+ .collect(),
+ ..self
+ }
+ }
+ }
+
+ fn count_orbits(&self) -> usize {
+ self.orbiters.len()
+ + self
+ .orbiters
+ .iter()
+ .map(|o| o.count_orbits())
+ .sum::<usize>()
+ }
+
+ fn total_orbits(&self) -> usize {
+ self.count_orbits()
+ + self
+ .orbiters
+ .iter()
+ .map(|o| o.total_orbits())
+ .sum::<usize>()
+ }
+
+ fn find_depth(&self, id: &str) -> usize {
+ if self.id == id {
+ self.depth
+ } else {
+ // only the actual one will return non-zero from this
+ self.orbiters.iter().map(|o| o.find_depth(id)).sum()
+ }
+ }
+
+ fn contains(&self, id: &str) -> bool {
+ self.id == id || self.orbiters.iter().any(|o| o.contains(id))
+ }
+
+ fn find_common_ancestor(&self, a: &str, b: &str) -> Option<OrbitalMap> {
+ if !self.contains(a) || !self.contains(b) {
+ None
+ } else {
+ self.orbiters
+ .iter()
+ .flat_map(|o| o.find_common_ancestor(a, b))
+ .next()
+ .or(Some(self.clone()))
+ }
+ }
+
+ fn orbital_transfers(&self, from: &str, to: &str) -> usize {
+ self.find_depth(from) + self.find_depth(to)
+ - 2 * self
+ .find_common_ancestor(from, to)
+ .map(|o| o.depth)
+ .unwrap_or(0)
+ - 2
+ }
+}
diff --git a/2019/src/bin/day_7.rs b/2019/src/bin/day_7.rs
new file mode 100644
index 0000000..9b9177a
--- /dev/null
+++ b/2019/src/bin/day_7.rs
@@ -0,0 +1,175 @@
+use aoc2019::*;
+use rpds::list;
+use rpds::list::List;
+use rpds::vector::Vector;
+use std::io;
+use std::io::prelude::*;
+use std::iter;
+use std::process;
+use structopt::StructOpt;
+
+#[derive(Debug, StructOpt)]
+#[structopt(name = "Day 7: Amplification Circuit")]
+/// Executes an Intcode program on 5 amplifiers, and finds the input that gives the max output
+///
+/// See https://adventofcode.com/2019/day/7 for details.
+struct Opt {
+ #[structopt(short = "f", long = "feedback-loop")]
+ feedback_loop_mode: bool,
+}
+
+fn main() {
+ let stdin = io::stdin();
+ let opt = Opt::from_args();
+
+ let program: IntcodeProgram = stdin
+ .lock()
+ .split(b',')
+ .map(|x| exit_on_failed_assertion(x, "Error reading input"))
+ .map(|x| exit_on_failed_assertion(String::from_utf8(x), "Input was not valid UTF-8"))
+ .map(|x| exit_on_failed_assertion(x.trim().parse::<Intcode>(), "Invalid number"))
+ .collect::<IntcodeProgram>();
+
+ let result = exit_on_failed_assertion(
+ find_max_power(&program, opt.feedback_loop_mode),
+ "Program errored",
+ );
+ println!("{}", result);
+}
+
+fn exit_on_failed_assertion<A, E: std::error::Error>(data: Result<A, E>, message: &str) -> A {
+ match data {
+ Ok(data) => data,
+ Err(e) => {
+ eprintln!("{}: {}", message, e);
+ process::exit(1);
+ }
+ }
+}
+
+fn find_max_power(
+ program: &IntcodeProgram,
+ feedback_loop_mode: bool,
+) -> Result<Intcode, IntcodeProgramError> {
+ PhaseSetting::all(feedback_loop_mode)
+ .map(|phase| AmplifierArray::new(program, &phase).execute())
+ .collect::<Result<Vec<Intcode>, _>>()
+ .map(|powers| powers.into_iter().max().unwrap_or(Intcode::from(0)))
+}
+
+#[derive(Debug, Clone)]
+struct PhaseSetting([Intcode; 5]);
+
+impl PhaseSetting {
+ fn all(feedback_loop_mode: bool) -> impl Iterator<Item = PhaseSetting> {
+ if feedback_loop_mode {
+ PhaseSetting::permute(5, 10)
+ } else {
+ PhaseSetting::permute(0, 5)
+ }
+ }
+
+ fn permute(min: i32, max: i32) -> impl Iterator<Item = PhaseSetting> {
+ // This is an absolutely atrocious way to do the permutation,
+ // but luckily it's only 5 elements long.
+ (min..max)
+ .flat_map(move |a| {
+ (min..max).flat_map(move |b| {
+ (min..max).flat_map(move |c| {
+ (min..max).flat_map(move |d| {
+ (min..max).map(move |e| {
+ PhaseSetting([a.into(), b.into(), c.into(), d.into(), e.into()])
+ })
+ })
+ })
+ })
+ })
+ .filter(move |phase| (min..max).all(|x| phase.0.contains(&x.into())))
+ }
+}
+
+#[derive(Debug, Clone)]
+struct AmplifierArray {
+ amplifiers: Vector<IntcodeProgram>,
+}
+
+impl AmplifierArray {
+ fn new(program: &IntcodeProgram, phase: &PhaseSetting) -> AmplifierArray {
+ AmplifierArray {
+ amplifiers: (0..5)
+ .map(|n| AmplifierArray::new_amp(program, phase, n))
+ .collect(),
+ }
+ }
+
+ fn new_amp(program: &IntcodeProgram, phase: &PhaseSetting, n: usize) -> IntcodeProgram {
+ if n == 0 {
+ program.with_input(list![phase.0[n].clone(), Intcode::from(0)])
+ } else {
+ program.with_input(list![phase.0[n].clone()])
+ }
+ }
+
+ fn execute(&self) -> Result<Intcode, IntcodeProgramError> {
+ self.run_to_termination().output_into_result()
+ }
+
+ fn run_to_termination(&self) -> AmplifierArray {
+ iter::successors(Some(self.clone()), |p| Some(p.next()))
+ .find(|p| p.is_terminated())
+ .unwrap() // successors doesn't terminate, so this will never be none.
+ }
+
+ fn output_into_result(&self) -> Result<Intcode, IntcodeProgramError> {
+ self.amplifiers
+ .first()
+ .and_then(|amp| amp.input.first().cloned())
+ .ok_or(IntcodeProgramError::Unknown)
+ }
+
+ fn is_terminated(&self) -> bool {
+ self.amplifiers.last().map(|amp| amp.halted).unwrap_or(true)
+ }
+
+ fn next(&self) -> AmplifierArray {
+ self.run_amplifiers().update_inputs()
+ }
+
+ fn run_amplifiers(&self) -> AmplifierArray {
+ AmplifierArray {
+ amplifiers: self
+ .amplifiers
+ .iter()
+ .map(|amp| amp.run_to_termination_or_input())
+ .collect(),
+ }
+ }
+
+ fn update_inputs(&self) -> AmplifierArray {
+ AmplifierArray {
+ amplifiers: self
+ .amplifiers
+ .iter()
+ .fold(
+ (
+ Vector::new(),
+ self.amplifiers
+ .last()
+ .map(|a| a.output.iter().cloned().collect::<List<Intcode>>())
+ .unwrap_or(List::new()),
+ ),
+ |(amps, piped_input), next_amp| {
+ (
+ amps.push_back(
+ next_amp
+ .with_additional_input(piped_input)
+ .with_cleared_output(),
+ ),
+ next_amp.output.iter().cloned().collect::<List<Intcode>>(),
+ )
+ },
+ )
+ .0,
+ }
+ }
+}
diff --git a/2019/src/bin/day_8.rs b/2019/src/bin/day_8.rs
new file mode 100644
index 0000000..0508e7c
--- /dev/null
+++ b/2019/src/bin/day_8.rs
@@ -0,0 +1,135 @@
+use std::fmt;
+use std::io;
+use std::io::prelude::*;
+use std::process;
+use structopt::StructOpt;
+
+#[derive(Debug, StructOpt)]
+#[structopt(name = "Day 8: Space Image Format")]
+/// Executes an Intcode program on 5 amplifiers, and finds the input that gives the max output
+///
+/// See https://adventofcode.com/2019/day/8 for details.
+struct Opt {
+ /// Rather than rendering the image, calculate and print its checksum
+ #[structopt(short = "c", long = "checksum")]
+ checksum_mode: bool,
+ #[structopt(short = "w", long = "width")]
+ width: u32,
+ #[structopt(short = "h", long = "height")]
+ height: u32,
+}
+
+fn main() {
+ let opt = Opt::from_args();
+
+ let image: Image = {
+ let mut buffer = String::new();
+ exit_on_failed_assertion(
+ io::stdin().read_to_string(&mut buffer),
+ "Error reading input",
+ );
+
+ Image::from_str(&buffer.trim(), opt.width, opt.height)
+ };
+
+ if opt.checksum_mode {
+ println!("{}", image.checksum());
+ } else {
+ println!("{}", image);
+ }
+}
+
+fn exit_on_failed_assertion<A, E: std::error::Error>(data: Result<A, E>, message: &str) -> A {
+ match data {
+ Ok(data) => data,
+ Err(e) => {
+ eprintln!("{}: {}", message, e);
+ process::exit(1);
+ }
+ }
+}
+
+#[derive(Debug)]
+struct Image {
+ width: u32,
+ height: u32,
+ layers: Vec<ImageLayer>,
+}
+
+impl fmt::Display for Image {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ self.flatten()
+ .pixels
+ .chunks(self.width as usize)
+ .map(|line| {
+ line.iter()
+ .map(|c| write!(f, "{}", if *c == 0 { ' ' } else { '1' }))
+ .collect::<fmt::Result>()
+ .and_then(|_| writeln!(f))
+ })
+ .collect()
+ }
+}
+
+impl Image {
+ fn from_str(s: &str, width: u32, height: u32) -> Image {
+ Image {
+ width,
+ height,
+ layers: s
+ .as_bytes()
+ .chunks((width * height) as usize)
+ .map(|chunk| ImageLayer::new(chunk))
+ .collect(),
+ }
+ }
+
+ fn checksum(&self) -> usize {
+ self.layers
+ .iter()
+ .min_by_key(|layer| layer.pixel_count(0))
+ .map(|layer| layer.pixel_count(1) * layer.pixel_count(2))
+ .unwrap_or(0)
+ }
+
+ fn flatten(&self) -> ImageLayer {
+ self.layers
+ .iter()
+ .fold(ImageLayer::empty(self.width, self.height), |acc, next| {
+ ImageLayer {
+ pixels: acc
+ .pixels
+ .iter()
+ .zip(next.pixels.iter())
+ .map(|(a, b)| if *a == 2 { *b } else { *a })
+ .collect(),
+ }
+ })
+ }
+}
+
+#[derive(Debug)]
+struct ImageLayer {
+ pixels: Vec<u8>,
+}
+
+impl ImageLayer {
+ fn new(char_pixels: &[u8]) -> ImageLayer {
+ ImageLayer {
+ pixels: char_pixels
+ .iter()
+ .map(|c| c.overflowing_sub(b'0').0)
+ .collect(),
+ }
+ }
+
+ fn empty(width: u32, height: u32) -> ImageLayer {
+ ImageLayer {
+ pixels: vec![2; (width * height) as usize],
+ }
+ }
+
+ fn pixel_count(&self, value: u8) -> usize {
+ self.pixels.iter().filter(|p| **p == value).count()
+ }
+}
diff --git a/2019/src/bin/day_9.rs b/2019/src/bin/day_9.rs
new file mode 100644
index 0000000..7f9b4aa
--- /dev/null
+++ b/2019/src/bin/day_9.rs
@@ -0,0 +1 @@
+// Run the day 5 binary for this
diff --git a/2019/src/lib.rs b/2019/src/lib.rs
new file mode 100644
index 0000000..a7dfc02
--- /dev/null
+++ b/2019/src/lib.rs
@@ -0,0 +1,438 @@
+use derivative::Derivative;
+use num::bigint::BigInt;
+use num::traits::identities::Zero;
+use rpds::RedBlackTreeMap;
+use rpds::{list::List, vector::Vector};
+use std::fmt;
+use std::iter;
+use std::iter::FromIterator;
+use std::iter::IntoIterator;
+use std::iter::Iterator;
+
+pub type Intcode = BigInt;
+
+#[derive(Clone, Derivative)]
+#[derivative(Debug)]
+pub struct IntcodeProgram {
+ #[derivative(Debug(format_with = "std::fmt::Display::fmt"))]
+ instruction_pointer: Intcode,
+ #[derivative(Debug(format_with = "std::fmt::Display::fmt"))]
+ relative_base: Intcode,
+ pub error: Option<IntcodeProgramError>,
+ pub halted: bool,
+ pub awaiting_input: bool,
+ #[derivative(Debug(format_with = "std::fmt::Display::fmt"))]
+ memory: RedBlackTreeMap<Intcode, Intcode>,
+ #[derivative(Debug(format_with = "std::fmt::Display::fmt"))]
+ pub input: List<Intcode>,
+ #[derivative(Debug(format_with = "std::fmt::Display::fmt"))]
+ pub output: Vector<Intcode>,
+}
+
+impl FromIterator<Intcode> for IntcodeProgram {
+ fn from_iter<I: IntoIterator<Item = Intcode>>(iter: I) -> Self {
+ IntcodeProgram {
+ instruction_pointer: Intcode::from(0),
+ relative_base: Intcode::from(0),
+ error: None,
+ halted: false,
+ awaiting_input: false,
+ memory: iter
+ .into_iter()
+ .enumerate()
+ .map(|(addr, val)| (Intcode::from(addr), val))
+ .collect(),
+ input: List::new(),
+ output: Vector::new(),
+ }
+ }
+}
+
+pub fn intcode_to_bool(i: &Intcode) -> bool {
+ *i != Intcode::from(0)
+}
+
+pub fn bool_to_intcode(i: bool) -> Intcode {
+ if i {
+ Intcode::from(1)
+ } else {
+ Intcode::from(0)
+ }
+}
+
+impl IntcodeProgram {
+ pub fn with_mem_0(&self, val: Intcode) -> IntcodeProgram {
+ self.with_memory_set(0.into(), val)
+ }
+
+ pub fn with_noun_verb_input(&self, noun: Intcode, verb: Intcode) -> IntcodeProgram {
+ self.with_memory_set(1.into(), noun)
+ .with_memory_set(2.into(), verb)
+ }
+
+ pub fn with_input(&self, input: List<Intcode>) -> IntcodeProgram {
+ IntcodeProgram {
+ input,
+ ..self.clone()
+ }
+ }
+
+ pub fn with_additional_input(&self, input: List<Intcode>) -> IntcodeProgram {
+ IntcodeProgram {
+ input: self.input.iter().chain(input.iter()).cloned().collect(),
+ ..self.clone()
+ }
+ }
+
+ pub fn with_cleared_output(&self) -> IntcodeProgram {
+ IntcodeProgram {
+ output: Vector::new(),
+ ..self.clone()
+ }
+ }
+
+ pub fn execute(&self) -> Result<Vector<Intcode>, IntcodeProgramError> {
+ self.run_to_termination().output_into_result()
+ }
+
+ pub fn execute_returning_memory_0(&self) -> Result<Intcode, IntcodeProgramError> {
+ self.run_to_termination().memory_0_into_result()
+ }
+
+ pub fn run_to_termination(&self) -> IntcodeProgram {
+ iter::successors(Some(self.clear_await_input()), |p| {
+ Some(IntcodeProgram::next(&p))
+ })
+ .find(|p| p.halted)
+ .unwrap() // successors doesn't terminate, so this will never be none.
+ }
+
+ pub fn run_to_termination_or_input(&self) -> IntcodeProgram {
+ iter::successors(Some(self.clear_await_input()), |p| {
+ Some(IntcodeProgram::next(&p))
+ })
+ .find(|p| p.halted || p.awaiting_input)
+ .unwrap()
+ }
+
+ pub fn output_into_result(&self) -> Result<Vector<Intcode>, IntcodeProgramError> {
+ match self.error {
+ Some(ref error) => Err(error.clone()),
+ None => Ok(self.output.clone()),
+ }
+ }
+
+ fn with_instruction_pointer(&self, instruction_pointer: Intcode) -> IntcodeProgram {
+ IntcodeProgram {
+ instruction_pointer,
+ ..self.clone()
+ }
+ }
+
+ fn with_instruction_pointer_offset(&self, offset: usize) -> IntcodeProgram {
+ IntcodeProgram {
+ instruction_pointer: self.instruction_pointer.clone() + offset,
+ ..self.clone()
+ }
+ }
+
+ fn with_relative_base(&self, relative_base: Intcode) -> IntcodeProgram {
+ IntcodeProgram {
+ relative_base,
+ ..self.clone()
+ }
+ }
+
+ fn with_memory_set(&self, address: Intcode, value: Intcode) -> IntcodeProgram {
+ IntcodeProgram {
+ memory: self.memory.insert(address, value),
+ ..self.clone()
+ }
+ }
+
+ fn with_input_consumed(&self) -> IntcodeProgram {
+ self.input
+ .drop_first()
+ .map(|input| IntcodeProgram {
+ input,
+ ..self.clone()
+ })
+ .unwrap_or(self.error(IntcodeProgramError::Unknown))
+ }
+
+ fn with_output(&self, print: Intcode) -> IntcodeProgram {
+ IntcodeProgram {
+ output: self.output.push_back(print),
+ ..self.clone()
+ }
+ }
+
+ fn memory_0_into_result(&self) -> Result<Intcode, IntcodeProgramError> {
+ match self.error {
+ Some(ref error) => Err(error.clone()),
+ None => Ok(self
+ .memory
+ .get(&Intcode::from(0))
+ .cloned()
+ .unwrap_or(Intcode::from(0))),
+ }
+ }
+ fn next(&self) -> IntcodeProgram {
+ //dbg!(self);
+ self.memory
+ .get(&self.instruction_pointer)
+ .map(|opcode| match opcode.to_radix_le(100).1[0] {
+ 1 => self.add(opcode),
+ 2 => self.multiply(opcode),
+ 3 => self.input(opcode),
+ 4 => self.output(opcode),
+ 5 => self.jump_if_true(opcode),
+ 6 => self.jump_if_false(opcode),
+ 7 => self.less_than(opcode),
+ 8 => self.equals(opcode),
+ 9 => self.set_relative_base(opcode),
+ 99 => self.halt(),
+ unknown => self.error(IntcodeProgramError::InvalidOpcode(unknown.clone())),
+ })
+ .unwrap_or(self.error(IntcodeProgramError::Unknown))
+ }
+
+ fn add(&self, mode: &Intcode) -> IntcodeProgram {
+ self.with_instruction_pointer_offset(4).with_memory_set(
+ self.get_literal(3, mode),
+ self.get(1, mode) + self.get(2, mode),
+ )
+ }
+
+ fn multiply(&self, mode: &Intcode) -> IntcodeProgram {
+ self.with_instruction_pointer_offset(4).with_memory_set(
+ self.get_literal(3, mode),
+ self.get(1, mode) * self.get(2, mode),
+ )
+ }
+
+ fn input(&self, mode: &Intcode) -> IntcodeProgram {
+ match self.input.first().cloned() {
+ Some(input) => self
+ .with_instruction_pointer_offset(2)
+ .with_memory_set(self.get_literal(1, mode), input)
+ .with_input_consumed(),
+ None => self.await_input(),
+ }
+ }
+
+ fn output(&self, mode: &Intcode) -> IntcodeProgram {
+ self.with_instruction_pointer_offset(2)
+ .with_output(self.get(1, mode))
+ }
+
+ fn jump_if_true(&self, mode: &Intcode) -> IntcodeProgram {
+ if !self.get(1, mode).is_zero() {
+ self.with_instruction_pointer(self.get(2, mode))
+ } else {
+ self.with_instruction_pointer_offset(3)
+ }
+ }
+ fn jump_if_false(&self, mode: &Intcode) -> IntcodeProgram {
+ if self.get(1, mode).is_zero() {
+ self.with_instruction_pointer(self.get(2, mode))
+ } else {
+ self.with_instruction_pointer_offset(3)
+ }
+ }
+
+ fn less_than(&self, mode: &Intcode) -> IntcodeProgram {
+ self.with_instruction_pointer_offset(4).with_memory_set(
+ self.get_literal(3, mode),
+ if self.get(1, mode) < self.get(2, mode) {
+ Intcode::from(1)
+ } else {
+ Intcode::from(0)
+ },
+ )
+ }
+
+ fn equals(&self, mode: &Intcode) -> IntcodeProgram {
+ self.with_instruction_pointer_offset(4).with_memory_set(
+ self.get_literal(3, mode),
+ if self.get(1, mode) == self.get(2, mode) {
+ Intcode::from(1)
+ } else {
+ Intcode::from(0)
+ },
+ )
+ }
+
+ fn set_relative_base(&self, mode: &Intcode) -> IntcodeProgram {
+ self.with_instruction_pointer_offset(2)
+ .with_relative_base(self.relative_base.clone() + self.get(1, mode))
+ }
+
+ fn halt(&self) -> IntcodeProgram {
+ IntcodeProgram {
+ halted: true,
+ ..self.clone()
+ }
+ }
+
+ fn await_input(&self) -> IntcodeProgram {
+ IntcodeProgram {
+ awaiting_input: true,
+ ..self.clone()
+ }
+ }
+
+ fn clear_await_input(&self) -> IntcodeProgram {
+ IntcodeProgram {
+ awaiting_input: false,
+ ..self.clone()
+ }
+ }
+
+ fn error(&self, error: IntcodeProgramError) -> IntcodeProgram {
+ IntcodeProgram {
+ halted: true,
+ error: Some(error),
+ ..self.clone()
+ }
+ }
+
+ fn get(&self, pointer_offset: usize, mode: &Intcode) -> Intcode {
+ match mode
+ .to_radix_le(10)
+ .1
+ .get(pointer_offset + 1)
+ .cloned()
+ .unwrap_or(0)
+ {
+ 0 => self.get_position(pointer_offset),
+ 1 => self.get_immediate(pointer_offset),
+ 2 => self.get_relative(pointer_offset),
+ _ => Intcode::from(0),
+ }
+ }
+
+ fn get_literal(&self, pointer_offset: usize, mode: &Intcode) -> Intcode {
+ match mode
+ .to_radix_le(10)
+ .1
+ .get(pointer_offset + 1)
+ .cloned()
+ .unwrap_or(0)
+ {
+ 0 => self.get_immediate(pointer_offset),
+ 1 => self.get_immediate(pointer_offset),
+ 2 => self.get_immediate_relative(pointer_offset),
+ _ => Intcode::from(0),
+ }
+ }
+
+ fn get_immediate(&self, pointer_offset: usize) -> Intcode {
+ self.memory
+ .get(&(self.instruction_pointer.clone() + pointer_offset))
+ .cloned()
+ .unwrap_or(Intcode::from(0))
+ }
+
+ fn get_position(&self, pointer_offset: usize) -> Intcode {
+ self.memory
+ .get(&self.get_immediate(pointer_offset))
+ .cloned()
+ .unwrap_or(Intcode::from(0))
+ }
+
+ fn get_relative(&self, pointer_offset: usize) -> Intcode {
+ self.memory
+ .get(&(self.get_immediate(pointer_offset) + self.relative_base.clone()))
+ .cloned()
+ .unwrap_or(Intcode::from(0))
+ }
+
+ fn get_immediate_relative(&self, pointer_offset: usize) -> Intcode {
+ self.get_immediate(pointer_offset) + self.relative_base.clone()
+ }
+}
+
+#[derive(Debug, PartialEq, Clone)]
+pub enum IntcodeProgramError {
+ InvalidOpcode(u8),
+ Unknown,
+}
+
+impl fmt::Display for IntcodeProgramError {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ use IntcodeProgramError::*;
+
+ match self {
+ InvalidOpcode(i) => write!(f, "{} is not a valid opcode", i),
+ Unknown => write!(f, "Unknown error"),
+ }
+ }
+}
+impl std::error::Error for IntcodeProgramError {}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ fn i32_vec_to_intcode_program(input: Vec<i32>) -> IntcodeProgram {
+ input.into_iter().map(Intcode::from).collect()
+ }
+
+ fn i32_vec_to_intcode_memory(input: Vec<i32>) -> RedBlackTreeMap<Intcode, Intcode> {
+ input
+ .into_iter()
+ .enumerate()
+ .map(|(i, val)| (Intcode::from(i), Intcode::from(val)))
+ .collect()
+ }
+
+ fn i32_vec_to_intcode_vec(input: Vec<i32>) -> Vector<Intcode> {
+ input.into_iter().map(Intcode::from).collect()
+ }
+
+ fn test_example_program(
+ before_execution: Vec<i32>,
+ after_execution: Vec<i32>,
+ ) -> IntcodeProgram {
+ let program = i32_vec_to_intcode_program(before_execution).run_to_termination();
+
+ assert_eq!(program.error, None);
+ assert_eq!(program.memory, i32_vec_to_intcode_memory(after_execution));
+ program
+ }
+
+ #[test]
+ fn day_2_example_1() {
+ test_example_program(vec![1, 0, 0, 0, 99], vec![2, 0, 0, 0, 99]);
+ }
+
+ #[test]
+ fn day_2_example_2() {
+ test_example_program(vec![2, 3, 0, 3, 99], vec![2, 3, 0, 6, 99]);
+ }
+
+ #[test]
+ fn day_5_example_1() {
+ test_example_program(vec![1002, 4, 3, 4, 33], vec![1002, 4, 3, 4, 99]);
+ }
+
+ #[test]
+ fn day_9_example_1() {
+ let quine = vec![
+ 109, 1, 204, -1, 1001, 100, 1, 100, 1008, 100, 16, 101, 1006, 101, 0, 99,
+ ];
+ let program = i32_vec_to_intcode_program(quine.clone()).run_to_termination();
+ assert_eq!(program.error, None);
+ assert_eq!(program.output, i32_vec_to_intcode_vec(quine));
+ }
+}
+
+pub fn sort_by_key<T, K: Ord>(
+ iter: impl IntoIterator<Item = T>,
+ f: impl FnMut(&T) -> K,
+) -> impl Iterator<Item = T> {
+ let mut tmp: Vec<T> = iter.into_iter().collect();
+ tmp.sort_by_key(f);
+ tmp.into_iter()
+}
diff --git a/2019/src/main.rs b/2019/src/main.rs
new file mode 100644
index 0000000..0c24a73
--- /dev/null
+++ b/2019/src/main.rs
@@ -0,0 +1,12 @@
+use std::io;
+use std::io::prelude::*;
+
+fn main() {
+ let stdin = io::stdin();
+ let answer = string_length_sum(stdin.lock().lines().map(|l| l.unwrap()));
+ dbg!(answer);
+}
+
+fn string_length_sum(it: impl Iterator<Item = String>) -> usize {
+ it.map(|l| l.len()).sum()
+}