diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
deleted file mode 100644
index 9bba3d9..0000000
--- a/.github/workflows/test.yml
+++ /dev/null
@@ -1,23 +0,0 @@
-name: test
-
-on:
- push:
- branches:
- - master
- - main
- pull_request:
-
-jobs:
- test:
- runs-on: ubuntu-latest
- steps:
- - uses: actions/checkout@v4
- - uses: erlef/setup-beam@v1
- with:
- otp-version: "27.0.1"
- gleam-version: "1.6.3"
- rebar3-version: "3"
- # elixir-version: "1.15.4"
- - run: gleam deps download
- - run: gleam test
- - run: gleam format --check src test
diff --git a/.gitignore b/.gitignore
index a263f17..ea8c4bf 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,5 +1 @@
-*.beam
-*.ez
-/build
-erl_crash.dump
-data/*.txt
+/target
diff --git a/Cargo.lock b/Cargo.lock
new file mode 100644
index 0000000..e2eebe0
--- /dev/null
+++ b/Cargo.lock
@@ -0,0 +1,711 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 3
+
+[[package]]
+name = "addr2line"
+version = "0.21.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb"
+dependencies = [
+ "gimli",
+]
+
+[[package]]
+name = "adler"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
+
+[[package]]
+name = "aho-corasick"
+version = "1.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
+name = "android-tzdata"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0"
+
+[[package]]
+name = "android_system_properties"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "anyhow"
+version = "1.0.75"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6"
+
+[[package]]
+name = "aoc"
+version = "0.1.0"
+dependencies = [
+ "anyhow",
+ "chrono",
+ "itertools",
+ "nom",
+ "rayon",
+ "regex",
+ "serde",
+ "serde_json",
+ "tap",
+ "tokio",
+]
+
+[[package]]
+name = "autocfg"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
+
+[[package]]
+name = "backtrace"
+version = "0.3.69"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837"
+dependencies = [
+ "addr2line",
+ "cc",
+ "cfg-if",
+ "libc",
+ "miniz_oxide",
+ "object",
+ "rustc-demangle",
+]
+
+[[package]]
+name = "bitflags"
+version = "1.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
+
+[[package]]
+name = "bumpalo"
+version = "3.14.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec"
+
+[[package]]
+name = "bytes"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223"
+
+[[package]]
+name = "cc"
+version = "1.0.83"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "cfg-if"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
+
+[[package]]
+name = "chrono"
+version = "0.4.31"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7f2c685bad3eb3d45a01354cedb7d5faa66194d1d58ba6e267a8de788f79db38"
+dependencies = [
+ "android-tzdata",
+ "iana-time-zone",
+ "js-sys",
+ "num-traits",
+ "serde",
+ "wasm-bindgen",
+ "windows-targets",
+]
+
+[[package]]
+name = "core-foundation-sys"
+version = "0.8.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f"
+
+[[package]]
+name = "crossbeam-deque"
+version = "0.8.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef"
+dependencies = [
+ "cfg-if",
+ "crossbeam-epoch",
+ "crossbeam-utils",
+]
+
+[[package]]
+name = "crossbeam-epoch"
+version = "0.9.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ae211234986c545741a7dc064309f67ee1e5ad243d0e48335adc0484d960bcc7"
+dependencies = [
+ "autocfg",
+ "cfg-if",
+ "crossbeam-utils",
+ "memoffset",
+ "scopeguard",
+]
+
+[[package]]
+name = "crossbeam-utils"
+version = "0.8.16"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294"
+dependencies = [
+ "cfg-if",
+]
+
+[[package]]
+name = "either"
+version = "1.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07"
+
+[[package]]
+name = "gimli"
+version = "0.28.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253"
+
+[[package]]
+name = "hermit-abi"
+version = "0.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7"
+
+[[package]]
+name = "iana-time-zone"
+version = "0.1.58"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8326b86b6cff230b97d0d312a6c40a60726df3332e721f72a1b035f451663b20"
+dependencies = [
+ "android_system_properties",
+ "core-foundation-sys",
+ "iana-time-zone-haiku",
+ "js-sys",
+ "wasm-bindgen",
+ "windows-core",
+]
+
+[[package]]
+name = "iana-time-zone-haiku"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f"
+dependencies = [
+ "cc",
+]
+
+[[package]]
+name = "itertools"
+version = "0.12.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "25db6b064527c5d482d0423354fcd07a89a2dfe07b67892e62411946db7f07b0"
+dependencies = [
+ "either",
+]
+
+[[package]]
+name = "itoa"
+version = "1.0.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38"
+
+[[package]]
+name = "js-sys"
+version = "0.3.66"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cee9c64da59eae3b50095c18d3e74f8b73c0b86d2792824ff01bbce68ba229ca"
+dependencies = [
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "libc"
+version = "0.2.150"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c"
+
+[[package]]
+name = "lock_api"
+version = "0.4.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45"
+dependencies = [
+ "autocfg",
+ "scopeguard",
+]
+
+[[package]]
+name = "log"
+version = "0.4.20"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f"
+
+[[package]]
+name = "memchr"
+version = "2.6.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167"
+
+[[package]]
+name = "memoffset"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c"
+dependencies = [
+ "autocfg",
+]
+
+[[package]]
+name = "minimal-lexical"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
+
+[[package]]
+name = "miniz_oxide"
+version = "0.7.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7"
+dependencies = [
+ "adler",
+]
+
+[[package]]
+name = "mio"
+version = "0.8.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3dce281c5e46beae905d4de1870d8b1509a9142b62eedf18b443b011ca8343d0"
+dependencies = [
+ "libc",
+ "wasi",
+ "windows-sys",
+]
+
+[[package]]
+name = "nom"
+version = "7.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a"
+dependencies = [
+ "memchr",
+ "minimal-lexical",
+]
+
+[[package]]
+name = "num-traits"
+version = "0.2.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c"
+dependencies = [
+ "autocfg",
+]
+
+[[package]]
+name = "num_cpus"
+version = "1.16.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43"
+dependencies = [
+ "hermit-abi",
+ "libc",
+]
+
+[[package]]
+name = "object"
+version = "0.32.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9cf5f9dd3933bd50a9e1f149ec995f39ae2c496d31fd772c1fd45ebc27e902b0"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
+name = "once_cell"
+version = "1.18.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d"
+
+[[package]]
+name = "parking_lot"
+version = "0.12.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f"
+dependencies = [
+ "lock_api",
+ "parking_lot_core",
+]
+
+[[package]]
+name = "parking_lot_core"
+version = "0.9.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "redox_syscall",
+ "smallvec",
+ "windows-targets",
+]
+
+[[package]]
+name = "pin-project-lite"
+version = "0.2.13"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58"
+
+[[package]]
+name = "proc-macro2"
+version = "1.0.70"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "39278fbbf5fb4f646ce651690877f89d1c5811a3d4acb27700c1cb3cdb78fd3b"
+dependencies = [
+ "unicode-ident",
+]
+
+[[package]]
+name = "quote"
+version = "1.0.33"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae"
+dependencies = [
+ "proc-macro2",
+]
+
+[[package]]
+name = "rayon"
+version = "1.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9c27db03db7734835b3f53954b534c91069375ce6ccaa2e065441e07d9b6cdb1"
+dependencies = [
+ "either",
+ "rayon-core",
+]
+
+[[package]]
+name = "rayon-core"
+version = "1.12.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5ce3fb6ad83f861aac485e76e1985cd109d9a3713802152be56c3b1f0e0658ed"
+dependencies = [
+ "crossbeam-deque",
+ "crossbeam-utils",
+]
+
+[[package]]
+name = "redox_syscall"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa"
+dependencies = [
+ "bitflags",
+]
+
+[[package]]
+name = "regex"
+version = "1.10.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343"
+dependencies = [
+ "aho-corasick",
+ "memchr",
+ "regex-automata",
+ "regex-syntax",
+]
+
+[[package]]
+name = "regex-automata"
+version = "0.4.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f"
+dependencies = [
+ "aho-corasick",
+ "memchr",
+ "regex-syntax",
+]
+
+[[package]]
+name = "regex-syntax"
+version = "0.8.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f"
+
+[[package]]
+name = "rustc-demangle"
+version = "0.1.23"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76"
+
+[[package]]
+name = "ryu"
+version = "1.0.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741"
+
+[[package]]
+name = "scopeguard"
+version = "1.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
+
+[[package]]
+name = "serde"
+version = "1.0.193"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "25dd9975e68d0cb5aa1120c288333fc98731bd1dd12f561e468ea4728c042b89"
+dependencies = [
+ "serde_derive",
+]
+
+[[package]]
+name = "serde_derive"
+version = "1.0.193"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "serde_json"
+version = "1.0.108"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3d1c7e3eac408d115102c4c24ad393e0821bb3a5df4d506a80f85f7a742a526b"
+dependencies = [
+ "itoa",
+ "ryu",
+ "serde",
+]
+
+[[package]]
+name = "signal-hook-registry"
+version = "1.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "smallvec"
+version = "1.11.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4dccd0940a2dcdf68d092b8cbab7dc0ad8fa938bf95787e1b916b0e3d0e8e970"
+
+[[package]]
+name = "socket2"
+version = "0.5.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7b5fac59a5cb5dd637972e5fca70daf0523c9067fcdc4842f053dae04a18f8e9"
+dependencies = [
+ "libc",
+ "windows-sys",
+]
+
+[[package]]
+name = "syn"
+version = "2.0.39"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "23e78b90f2fcf45d3e842032ce32e3f2d1545ba6636271dcbf24fa306d87be7a"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
+]
+
+[[package]]
+name = "tap"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369"
+
+[[package]]
+name = "tokio"
+version = "1.34.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d0c014766411e834f7af5b8f4cf46257aab4036ca95e9d2c144a10f59ad6f5b9"
+dependencies = [
+ "backtrace",
+ "bytes",
+ "libc",
+ "mio",
+ "num_cpus",
+ "parking_lot",
+ "pin-project-lite",
+ "signal-hook-registry",
+ "socket2",
+ "tokio-macros",
+ "windows-sys",
+]
+
+[[package]]
+name = "tokio-macros"
+version = "2.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "unicode-ident"
+version = "1.0.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
+
+[[package]]
+name = "wasi"
+version = "0.11.0+wasi-snapshot-preview1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
+
+[[package]]
+name = "wasm-bindgen"
+version = "0.2.89"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0ed0d4f68a3015cc185aff4db9506a015f4b96f95303897bfa23f846db54064e"
+dependencies = [
+ "cfg-if",
+ "wasm-bindgen-macro",
+]
+
+[[package]]
+name = "wasm-bindgen-backend"
+version = "0.2.89"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1b56f625e64f3a1084ded111c4d5f477df9f8c92df113852fa5a374dbda78826"
+dependencies = [
+ "bumpalo",
+ "log",
+ "once_cell",
+ "proc-macro2",
+ "quote",
+ "syn",
+ "wasm-bindgen-shared",
+]
+
+[[package]]
+name = "wasm-bindgen-macro"
+version = "0.2.89"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0162dbf37223cd2afce98f3d0785506dcb8d266223983e4b5b525859e6e182b2"
+dependencies = [
+ "quote",
+ "wasm-bindgen-macro-support",
+]
+
+[[package]]
+name = "wasm-bindgen-macro-support"
+version = "0.2.89"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f0eb82fcb7930ae6219a7ecfd55b217f5f0893484b7a13022ebb2b2bf20b5283"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+ "wasm-bindgen-backend",
+ "wasm-bindgen-shared",
+]
+
+[[package]]
+name = "wasm-bindgen-shared"
+version = "0.2.89"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7ab9b36309365056cd639da3134bf87fa8f3d86008abf99e612384a6eecd459f"
+
+[[package]]
+name = "windows-core"
+version = "0.51.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f1f8cf84f35d2db49a46868f947758c7a1138116f7fac3bc844f43ade1292e64"
+dependencies = [
+ "windows-targets",
+]
+
+[[package]]
+name = "windows-sys"
+version = "0.48.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
+dependencies = [
+ "windows-targets",
+]
+
+[[package]]
+name = "windows-targets"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
+dependencies = [
+ "windows_aarch64_gnullvm",
+ "windows_aarch64_msvc",
+ "windows_i686_gnu",
+ "windows_i686_msvc",
+ "windows_x86_64_gnu",
+ "windows_x86_64_gnullvm",
+ "windows_x86_64_msvc",
+]
+
+[[package]]
+name = "windows_aarch64_gnullvm"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
+
+[[package]]
+name = "windows_aarch64_msvc"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
+
+[[package]]
+name = "windows_i686_gnu"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
+
+[[package]]
+name = "windows_i686_msvc"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
+
+[[package]]
+name = "windows_x86_64_gnu"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
+
+[[package]]
+name = "windows_x86_64_gnullvm"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
+
+[[package]]
+name = "windows_x86_64_msvc"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
diff --git a/Cargo.toml b/Cargo.toml
new file mode 100644
index 0000000..d49bc76
--- /dev/null
+++ b/Cargo.toml
@@ -0,0 +1,18 @@
+[package]
+name = "aoc"
+version = "0.1.0"
+edition = "2021"
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
+anyhow = "1.0.75"
+chrono = { version = "0.4.31", features = ["serde"] }
+itertools = "0.12.0"
+nom = "7.1.3"
+rayon = "1.8.0"
+regex = "1.10.2"
+serde = { version = "1.0.193", features = ["derive"] }
+serde_json = "1.0.108"
+tap = "1.0.1"
+tokio = { version = "1.34.0", features = ["full"] }
diff --git a/LICENSE b/LICENSE
deleted file mode 100644
index 6133265..0000000
--- a/LICENSE
+++ /dev/null
@@ -1,674 +0,0 @@
- GNU GENERAL PUBLIC LICENSE
- Version 3, 29 June 2007
-
- Copyright (C) 2007 Free Software Foundation, Inc.
- Everyone is permitted to copy and distribute verbatim copies
- of this license document, but changing it is not allowed.
-
- Preamble
-
- The GNU General Public License is a free, copyleft license for
-software and other kinds of works.
-
- The licenses for most software and other practical works are designed
-to take away your freedom to share and change the works. By contrast,
-the GNU General Public License is intended to guarantee your freedom to
-share and change all versions of a program--to make sure it remains free
-software for all its users. We, the Free Software Foundation, use the
-GNU General Public License for most of our software; it applies also to
-any other work released this way by its authors. You can apply it to
-your programs, too.
-
- When we speak of free software, we are referring to freedom, not
-price. Our General Public Licenses are designed to make sure that you
-have the freedom to distribute copies of free software (and charge for
-them if you wish), that you receive source code or can get it if you
-want it, that you can change the software or use pieces of it in new
-free programs, and that you know you can do these things.
-
- To protect your rights, we need to prevent others from denying you
-these rights or asking you to surrender the rights. Therefore, you have
-certain responsibilities if you distribute copies of the software, or if
-you modify it: responsibilities to respect the freedom of others.
-
- For example, if you distribute copies of such a program, whether
-gratis or for a fee, you must pass on to the recipients the same
-freedoms that you received. You must make sure that they, too, receive
-or can get the source code. And you must show them these terms so they
-know their rights.
-
- Developers that use the GNU GPL protect your rights with two steps:
-(1) assert copyright on the software, and (2) offer you this License
-giving you legal permission to copy, distribute and/or modify it.
-
- For the developers' and authors' protection, the GPL clearly explains
-that there is no warranty for this free software. For both users' and
-authors' sake, the GPL requires that modified versions be marked as
-changed, so that their problems will not be attributed erroneously to
-authors of previous versions.
-
- Some devices are designed to deny users access to install or run
-modified versions of the software inside them, although the manufacturer
-can do so. This is fundamentally incompatible with the aim of
-protecting users' freedom to change the software. The systematic
-pattern of such abuse occurs in the area of products for individuals to
-use, which is precisely where it is most unacceptable. Therefore, we
-have designed this version of the GPL to prohibit the practice for those
-products. If such problems arise substantially in other domains, we
-stand ready to extend this provision to those domains in future versions
-of the GPL, as needed to protect the freedom of users.
-
- Finally, every program is threatened constantly by software patents.
-States should not allow patents to restrict development and use of
-software on general-purpose computers, but in those that do, we wish to
-avoid the special danger that patents applied to a free program could
-make it effectively proprietary. To prevent this, the GPL assures that
-patents cannot be used to render the program non-free.
-
- The precise terms and conditions for copying, distribution and
-modification follow.
-
- TERMS AND CONDITIONS
-
- 0. Definitions.
-
- "This License" refers to version 3 of the GNU General Public License.
-
- "Copyright" also means copyright-like laws that apply to other kinds of
-works, such as semiconductor masks.
-
- "The Program" refers to any copyrightable work licensed under this
-License. Each licensee is addressed as "you". "Licensees" and
-"recipients" may be individuals or organizations.
-
- To "modify" a work means to copy from or adapt all or part of the work
-in a fashion requiring copyright permission, other than the making of an
-exact copy. The resulting work is called a "modified version" of the
-earlier work or a work "based on" the earlier work.
-
- A "covered work" means either the unmodified Program or a work based
-on the Program.
-
- To "propagate" a work means to do anything with it that, without
-permission, would make you directly or secondarily liable for
-infringement under applicable copyright law, except executing it on a
-computer or modifying a private copy. Propagation includes copying,
-distribution (with or without modification), making available to the
-public, and in some countries other activities as well.
-
- To "convey" a work means any kind of propagation that enables other
-parties to make or receive copies. Mere interaction with a user through
-a computer network, with no transfer of a copy, is not conveying.
-
- An interactive user interface displays "Appropriate Legal Notices"
-to the extent that it includes a convenient and prominently visible
-feature that (1) displays an appropriate copyright notice, and (2)
-tells the user that there is no warranty for the work (except to the
-extent that warranties are provided), that licensees may convey the
-work under this License, and how to view a copy of this License. If
-the interface presents a list of user commands or options, such as a
-menu, a prominent item in the list meets this criterion.
-
- 1. Source Code.
-
- The "source code" for a work means the preferred form of the work
-for making modifications to it. "Object code" means any non-source
-form of a work.
-
- A "Standard Interface" means an interface that either is an official
-standard defined by a recognized standards body, or, in the case of
-interfaces specified for a particular programming language, one that
-is widely used among developers working in that language.
-
- The "System Libraries" of an executable work include anything, other
-than the work as a whole, that (a) is included in the normal form of
-packaging a Major Component, but which is not part of that Major
-Component, and (b) serves only to enable use of the work with that
-Major Component, or to implement a Standard Interface for which an
-implementation is available to the public in source code form. A
-"Major Component", in this context, means a major essential component
-(kernel, window system, and so on) of the specific operating system
-(if any) on which the executable work runs, or a compiler used to
-produce the work, or an object code interpreter used to run it.
-
- The "Corresponding Source" for a work in object code form means all
-the source code needed to generate, install, and (for an executable
-work) run the object code and to modify the work, including scripts to
-control those activities. However, it does not include the work's
-System Libraries, or general-purpose tools or generally available free
-programs which are used unmodified in performing those activities but
-which are not part of the work. For example, Corresponding Source
-includes interface definition files associated with source files for
-the work, and the source code for shared libraries and dynamically
-linked subprograms that the work is specifically designed to require,
-such as by intimate data communication or control flow between those
-subprograms and other parts of the work.
-
- The Corresponding Source need not include anything that users
-can regenerate automatically from other parts of the Corresponding
-Source.
-
- The Corresponding Source for a work in source code form is that
-same work.
-
- 2. Basic Permissions.
-
- All rights granted under this License are granted for the term of
-copyright on the Program, and are irrevocable provided the stated
-conditions are met. This License explicitly affirms your unlimited
-permission to run the unmodified Program. The output from running a
-covered work is covered by this License only if the output, given its
-content, constitutes a covered work. This License acknowledges your
-rights of fair use or other equivalent, as provided by copyright law.
-
- You may make, run and propagate covered works that you do not
-convey, without conditions so long as your license otherwise remains
-in force. You may convey covered works to others for the sole purpose
-of having them make modifications exclusively for you, or provide you
-with facilities for running those works, provided that you comply with
-the terms of this License in conveying all material for which you do
-not control copyright. Those thus making or running the covered works
-for you must do so exclusively on your behalf, under your direction
-and control, on terms that prohibit them from making any copies of
-your copyrighted material outside their relationship with you.
-
- Conveying under any other circumstances is permitted solely under
-the conditions stated below. Sublicensing is not allowed; section 10
-makes it unnecessary.
-
- 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
-
- No covered work shall be deemed part of an effective technological
-measure under any applicable law fulfilling obligations under article
-11 of the WIPO copyright treaty adopted on 20 December 1996, or
-similar laws prohibiting or restricting circumvention of such
-measures.
-
- When you convey a covered work, you waive any legal power to forbid
-circumvention of technological measures to the extent such circumvention
-is effected by exercising rights under this License with respect to
-the covered work, and you disclaim any intention to limit operation or
-modification of the work as a means of enforcing, against the work's
-users, your or third parties' legal rights to forbid circumvention of
-technological measures.
-
- 4. Conveying Verbatim Copies.
-
- You may convey verbatim copies of the Program's source code as you
-receive it, in any medium, provided that you conspicuously and
-appropriately publish on each copy an appropriate copyright notice;
-keep intact all notices stating that this License and any
-non-permissive terms added in accord with section 7 apply to the code;
-keep intact all notices of the absence of any warranty; and give all
-recipients a copy of this License along with the Program.
-
- You may charge any price or no price for each copy that you convey,
-and you may offer support or warranty protection for a fee.
-
- 5. Conveying Modified Source Versions.
-
- You may convey a work based on the Program, or the modifications to
-produce it from the Program, in the form of source code under the
-terms of section 4, provided that you also meet all of these conditions:
-
- a) The work must carry prominent notices stating that you modified
- it, and giving a relevant date.
-
- b) The work must carry prominent notices stating that it is
- released under this License and any conditions added under section
- 7. This requirement modifies the requirement in section 4 to
- "keep intact all notices".
-
- c) You must license the entire work, as a whole, under this
- License to anyone who comes into possession of a copy. This
- License will therefore apply, along with any applicable section 7
- additional terms, to the whole of the work, and all its parts,
- regardless of how they are packaged. This License gives no
- permission to license the work in any other way, but it does not
- invalidate such permission if you have separately received it.
-
- d) If the work has interactive user interfaces, each must display
- Appropriate Legal Notices; however, if the Program has interactive
- interfaces that do not display Appropriate Legal Notices, your
- work need not make them do so.
-
- A compilation of a covered work with other separate and independent
-works, which are not by their nature extensions of the covered work,
-and which are not combined with it such as to form a larger program,
-in or on a volume of a storage or distribution medium, is called an
-"aggregate" if the compilation and its resulting copyright are not
-used to limit the access or legal rights of the compilation's users
-beyond what the individual works permit. Inclusion of a covered work
-in an aggregate does not cause this License to apply to the other
-parts of the aggregate.
-
- 6. Conveying Non-Source Forms.
-
- You may convey a covered work in object code form under the terms
-of sections 4 and 5, provided that you also convey the
-machine-readable Corresponding Source under the terms of this License,
-in one of these ways:
-
- a) Convey the object code in, or embodied in, a physical product
- (including a physical distribution medium), accompanied by the
- Corresponding Source fixed on a durable physical medium
- customarily used for software interchange.
-
- b) Convey the object code in, or embodied in, a physical product
- (including a physical distribution medium), accompanied by a
- written offer, valid for at least three years and valid for as
- long as you offer spare parts or customer support for that product
- model, to give anyone who possesses the object code either (1) a
- copy of the Corresponding Source for all the software in the
- product that is covered by this License, on a durable physical
- medium customarily used for software interchange, for a price no
- more than your reasonable cost of physically performing this
- conveying of source, or (2) access to copy the
- Corresponding Source from a network server at no charge.
-
- c) Convey individual copies of the object code with a copy of the
- written offer to provide the Corresponding Source. This
- alternative is allowed only occasionally and noncommercially, and
- only if you received the object code with such an offer, in accord
- with subsection 6b.
-
- d) Convey the object code by offering access from a designated
- place (gratis or for a charge), and offer equivalent access to the
- Corresponding Source in the same way through the same place at no
- further charge. You need not require recipients to copy the
- Corresponding Source along with the object code. If the place to
- copy the object code is a network server, the Corresponding Source
- may be on a different server (operated by you or a third party)
- that supports equivalent copying facilities, provided you maintain
- clear directions next to the object code saying where to find the
- Corresponding Source. Regardless of what server hosts the
- Corresponding Source, you remain obligated to ensure that it is
- available for as long as needed to satisfy these requirements.
-
- e) Convey the object code using peer-to-peer transmission, provided
- you inform other peers where the object code and Corresponding
- Source of the work are being offered to the general public at no
- charge under subsection 6d.
-
- A separable portion of the object code, whose source code is excluded
-from the Corresponding Source as a System Library, need not be
-included in conveying the object code work.
-
- A "User Product" is either (1) a "consumer product", which means any
-tangible personal property which is normally used for personal, family,
-or household purposes, or (2) anything designed or sold for incorporation
-into a dwelling. In determining whether a product is a consumer product,
-doubtful cases shall be resolved in favor of coverage. For a particular
-product received by a particular user, "normally used" refers to a
-typical or common use of that class of product, regardless of the status
-of the particular user or of the way in which the particular user
-actually uses, or expects or is expected to use, the product. A product
-is a consumer product regardless of whether the product has substantial
-commercial, industrial or non-consumer uses, unless such uses represent
-the only significant mode of use of the product.
-
- "Installation Information" for a User Product means any methods,
-procedures, authorization keys, or other information required to install
-and execute modified versions of a covered work in that User Product from
-a modified version of its Corresponding Source. The information must
-suffice to ensure that the continued functioning of the modified object
-code is in no case prevented or interfered with solely because
-modification has been made.
-
- If you convey an object code work under this section in, or with, or
-specifically for use in, a User Product, and the conveying occurs as
-part of a transaction in which the right of possession and use of the
-User Product is transferred to the recipient in perpetuity or for a
-fixed term (regardless of how the transaction is characterized), the
-Corresponding Source conveyed under this section must be accompanied
-by the Installation Information. But this requirement does not apply
-if neither you nor any third party retains the ability to install
-modified object code on the User Product (for example, the work has
-been installed in ROM).
-
- The requirement to provide Installation Information does not include a
-requirement to continue to provide support service, warranty, or updates
-for a work that has been modified or installed by the recipient, or for
-the User Product in which it has been modified or installed. Access to a
-network may be denied when the modification itself materially and
-adversely affects the operation of the network or violates the rules and
-protocols for communication across the network.
-
- Corresponding Source conveyed, and Installation Information provided,
-in accord with this section must be in a format that is publicly
-documented (and with an implementation available to the public in
-source code form), and must require no special password or key for
-unpacking, reading or copying.
-
- 7. Additional Terms.
-
- "Additional permissions" are terms that supplement the terms of this
-License by making exceptions from one or more of its conditions.
-Additional permissions that are applicable to the entire Program shall
-be treated as though they were included in this License, to the extent
-that they are valid under applicable law. If additional permissions
-apply only to part of the Program, that part may be used separately
-under those permissions, but the entire Program remains governed by
-this License without regard to the additional permissions.
-
- When you convey a copy of a covered work, you may at your option
-remove any additional permissions from that copy, or from any part of
-it. (Additional permissions may be written to require their own
-removal in certain cases when you modify the work.) You may place
-additional permissions on material, added by you to a covered work,
-for which you have or can give appropriate copyright permission.
-
- Notwithstanding any other provision of this License, for material you
-add to a covered work, you may (if authorized by the copyright holders of
-that material) supplement the terms of this License with terms:
-
- a) Disclaiming warranty or limiting liability differently from the
- terms of sections 15 and 16 of this License; or
-
- b) Requiring preservation of specified reasonable legal notices or
- author attributions in that material or in the Appropriate Legal
- Notices displayed by works containing it; or
-
- c) Prohibiting misrepresentation of the origin of that material, or
- requiring that modified versions of such material be marked in
- reasonable ways as different from the original version; or
-
- d) Limiting the use for publicity purposes of names of licensors or
- authors of the material; or
-
- e) Declining to grant rights under trademark law for use of some
- trade names, trademarks, or service marks; or
-
- f) Requiring indemnification of licensors and authors of that
- material by anyone who conveys the material (or modified versions of
- it) with contractual assumptions of liability to the recipient, for
- any liability that these contractual assumptions directly impose on
- those licensors and authors.
-
- All other non-permissive additional terms are considered "further
-restrictions" within the meaning of section 10. If the Program as you
-received it, or any part of it, contains a notice stating that it is
-governed by this License along with a term that is a further
-restriction, you may remove that term. If a license document contains
-a further restriction but permits relicensing or conveying under this
-License, you may add to a covered work material governed by the terms
-of that license document, provided that the further restriction does
-not survive such relicensing or conveying.
-
- If you add terms to a covered work in accord with this section, you
-must place, in the relevant source files, a statement of the
-additional terms that apply to those files, or a notice indicating
-where to find the applicable terms.
-
- Additional terms, permissive or non-permissive, may be stated in the
-form of a separately written license, or stated as exceptions;
-the above requirements apply either way.
-
- 8. Termination.
-
- You may not propagate or modify a covered work except as expressly
-provided under this License. Any attempt otherwise to propagate or
-modify it is void, and will automatically terminate your rights under
-this License (including any patent licenses granted under the third
-paragraph of section 11).
-
- However, if you cease all violation of this License, then your
-license from a particular copyright holder is reinstated (a)
-provisionally, unless and until the copyright holder explicitly and
-finally terminates your license, and (b) permanently, if the copyright
-holder fails to notify you of the violation by some reasonable means
-prior to 60 days after the cessation.
-
- Moreover, your license from a particular copyright holder is
-reinstated permanently if the copyright holder notifies you of the
-violation by some reasonable means, this is the first time you have
-received notice of violation of this License (for any work) from that
-copyright holder, and you cure the violation prior to 30 days after
-your receipt of the notice.
-
- Termination of your rights under this section does not terminate the
-licenses of parties who have received copies or rights from you under
-this License. If your rights have been terminated and not permanently
-reinstated, you do not qualify to receive new licenses for the same
-material under section 10.
-
- 9. Acceptance Not Required for Having Copies.
-
- You are not required to accept this License in order to receive or
-run a copy of the Program. Ancillary propagation of a covered work
-occurring solely as a consequence of using peer-to-peer transmission
-to receive a copy likewise does not require acceptance. However,
-nothing other than this License grants you permission to propagate or
-modify any covered work. These actions infringe copyright if you do
-not accept this License. Therefore, by modifying or propagating a
-covered work, you indicate your acceptance of this License to do so.
-
- 10. Automatic Licensing of Downstream Recipients.
-
- Each time you convey a covered work, the recipient automatically
-receives a license from the original licensors, to run, modify and
-propagate that work, subject to this License. You are not responsible
-for enforcing compliance by third parties with this License.
-
- An "entity transaction" is a transaction transferring control of an
-organization, or substantially all assets of one, or subdividing an
-organization, or merging organizations. If propagation of a covered
-work results from an entity transaction, each party to that
-transaction who receives a copy of the work also receives whatever
-licenses to the work the party's predecessor in interest had or could
-give under the previous paragraph, plus a right to possession of the
-Corresponding Source of the work from the predecessor in interest, if
-the predecessor has it or can get it with reasonable efforts.
-
- You may not impose any further restrictions on the exercise of the
-rights granted or affirmed under this License. For example, you may
-not impose a license fee, royalty, or other charge for exercise of
-rights granted under this License, and you may not initiate litigation
-(including a cross-claim or counterclaim in a lawsuit) alleging that
-any patent claim is infringed by making, using, selling, offering for
-sale, or importing the Program or any portion of it.
-
- 11. Patents.
-
- A "contributor" is a copyright holder who authorizes use under this
-License of the Program or a work on which the Program is based. The
-work thus licensed is called the contributor's "contributor version".
-
- A contributor's "essential patent claims" are all patent claims
-owned or controlled by the contributor, whether already acquired or
-hereafter acquired, that would be infringed by some manner, permitted
-by this License, of making, using, or selling its contributor version,
-but do not include claims that would be infringed only as a
-consequence of further modification of the contributor version. For
-purposes of this definition, "control" includes the right to grant
-patent sublicenses in a manner consistent with the requirements of
-this License.
-
- Each contributor grants you a non-exclusive, worldwide, royalty-free
-patent license under the contributor's essential patent claims, to
-make, use, sell, offer for sale, import and otherwise run, modify and
-propagate the contents of its contributor version.
-
- In the following three paragraphs, a "patent license" is any express
-agreement or commitment, however denominated, not to enforce a patent
-(such as an express permission to practice a patent or covenant not to
-sue for patent infringement). To "grant" such a patent license to a
-party means to make such an agreement or commitment not to enforce a
-patent against the party.
-
- If you convey a covered work, knowingly relying on a patent license,
-and the Corresponding Source of the work is not available for anyone
-to copy, free of charge and under the terms of this License, through a
-publicly available network server or other readily accessible means,
-then you must either (1) cause the Corresponding Source to be so
-available, or (2) arrange to deprive yourself of the benefit of the
-patent license for this particular work, or (3) arrange, in a manner
-consistent with the requirements of this License, to extend the patent
-license to downstream recipients. "Knowingly relying" means you have
-actual knowledge that, but for the patent license, your conveying the
-covered work in a country, or your recipient's use of the covered work
-in a country, would infringe one or more identifiable patents in that
-country that you have reason to believe are valid.
-
- If, pursuant to or in connection with a single transaction or
-arrangement, you convey, or propagate by procuring conveyance of, a
-covered work, and grant a patent license to some of the parties
-receiving the covered work authorizing them to use, propagate, modify
-or convey a specific copy of the covered work, then the patent license
-you grant is automatically extended to all recipients of the covered
-work and works based on it.
-
- A patent license is "discriminatory" if it does not include within
-the scope of its coverage, prohibits the exercise of, or is
-conditioned on the non-exercise of one or more of the rights that are
-specifically granted under this License. You may not convey a covered
-work if you are a party to an arrangement with a third party that is
-in the business of distributing software, under which you make payment
-to the third party based on the extent of your activity of conveying
-the work, and under which the third party grants, to any of the
-parties who would receive the covered work from you, a discriminatory
-patent license (a) in connection with copies of the covered work
-conveyed by you (or copies made from those copies), or (b) primarily
-for and in connection with specific products or compilations that
-contain the covered work, unless you entered into that arrangement,
-or that patent license was granted, prior to 28 March 2007.
-
- Nothing in this License shall be construed as excluding or limiting
-any implied license or other defenses to infringement that may
-otherwise be available to you under applicable patent law.
-
- 12. No Surrender of Others' Freedom.
-
- If conditions are imposed on you (whether by court order, agreement or
-otherwise) that contradict the conditions of this License, they do not
-excuse you from the conditions of this License. If you cannot convey a
-covered work so as to satisfy simultaneously your obligations under this
-License and any other pertinent obligations, then as a consequence you may
-not convey it at all. For example, if you agree to terms that obligate you
-to collect a royalty for further conveying from those to whom you convey
-the Program, the only way you could satisfy both those terms and this
-License would be to refrain entirely from conveying the Program.
-
- 13. Use with the GNU Affero General Public License.
-
- Notwithstanding any other provision of this License, you have
-permission to link or combine any covered work with a work licensed
-under version 3 of the GNU Affero General Public License into a single
-combined work, and to convey the resulting work. The terms of this
-License will continue to apply to the part which is the covered work,
-but the special requirements of the GNU Affero General Public License,
-section 13, concerning interaction through a network will apply to the
-combination as such.
-
- 14. Revised Versions of this License.
-
- The Free Software Foundation may publish revised and/or new versions of
-the GNU General Public License from time to time. Such new versions will
-be similar in spirit to the present version, but may differ in detail to
-address new problems or concerns.
-
- Each version is given a distinguishing version number. If the
-Program specifies that a certain numbered version of the GNU General
-Public License "or any later version" applies to it, you have the
-option of following the terms and conditions either of that numbered
-version or of any later version published by the Free Software
-Foundation. If the Program does not specify a version number of the
-GNU General Public License, you may choose any version ever published
-by the Free Software Foundation.
-
- If the Program specifies that a proxy can decide which future
-versions of the GNU General Public License can be used, that proxy's
-public statement of acceptance of a version permanently authorizes you
-to choose that version for the Program.
-
- Later license versions may give you additional or different
-permissions. However, no additional obligations are imposed on any
-author or copyright holder as a result of your choosing to follow a
-later version.
-
- 15. Disclaimer of Warranty.
-
- THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
-APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
-HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
-OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
-THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
-IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
-ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
-
- 16. Limitation of Liability.
-
- IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
-WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
-THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
-GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
-USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
-DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
-PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
-EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
-SUCH DAMAGES.
-
- 17. Interpretation of Sections 15 and 16.
-
- If the disclaimer of warranty and limitation of liability provided
-above cannot be given local legal effect according to their terms,
-reviewing courts shall apply local law that most closely approximates
-an absolute waiver of all civil liability in connection with the
-Program, unless a warranty or assumption of liability accompanies a
-copy of the Program in return for a fee.
-
- END OF TERMS AND CONDITIONS
-
- How to Apply These Terms to Your New Programs
-
- If you develop a new program, and you want it to be of the greatest
-possible use to the public, the best way to achieve this is to make it
-free software which everyone can redistribute and change under these terms.
-
- To do so, attach the following notices to the program. It is safest
-to attach them to the start of each source file to most effectively
-state the exclusion of warranty; and each file should have at least
-the "copyright" line and a pointer to where the full notice is found.
-
- advent_of_code
- Copyright (C) 2024 sreedevk
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program. If not, see .
-
-Also add information on how to contact you by electronic and paper mail.
-
- If the program does terminal interaction, make it output a short
-notice like this when it starts in an interactive mode:
-
- advent_of_code Copyright (C) 2024 sreedevk
- This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
- This is free software, and you are welcome to redistribute it
- under certain conditions; type `show c' for details.
-
-The hypothetical commands `show w' and `show c' should show the appropriate
-parts of the General Public License. Of course, your program's commands
-might be different; for a GUI interface, you would use an "about box".
-
- You should also get your employer (if you work as a programmer) or school,
-if any, to sign a "copyright disclaimer" for the program, if necessary.
-For more information on this, and how to apply and follow the GNU GPL, see
-.
-
- The GNU General Public License does not permit incorporating your program
-into proprietary programs. If your program is a subroutine library, you
-may consider it more useful to permit linking proprietary applications with
-the library. If this is what you want to do, use the GNU Lesser General
-Public License instead of this License. But first, please read
-.
diff --git a/README.md b/README.md
index 1836783..a4ba895 100644
--- a/README.md
+++ b/README.md
@@ -1,22 +1,9 @@
-# Advent Of Code 2024
+# Advent of Code 2023
-```sh
-# Run Tests Against all solutions (example inputs used)
-gleam test
+## Usage
-# Run the solution against actual input for a particular day
-gleam run
+```bash
+git clone https://github.com/sreedevk/advent-of-code
+cd advent-of-code
+cargo run -r
```
-
-## Solution Status
-
-1. [x] [Day 01 Historian Hysteria](https://github.com/sreedevk/advent-of-code/blob/main/src/historian_hysteria.gleam)
-2. [x] [Day 02 Red Nosed Reports](https://github.com/sreedevk/advent-of-code/blob/main/src/red_nosed_reports.gleam)
-3. [x] [Day 03 Mull It Over](https://github.com/sreedevk/advent-of-code/blob/main/src/mull_it_over.gleam)
-4. [x] [Day 04 Ceres Search](https://github.com/sreedevk/advent-of-code/blob/main/src/ceres_search.gleam)
-5. [x] [Day 05 Print Queue](https://github.com/sreedevk/advent-of-code/blob/main/src/print_queue.gleam)
-6. [x] [Day 06 Guard Gallivant](https://github.com/sreedevk/advent-of-code/blob/main/src/guard_gallivant.gleam)
-7. [x] [Day 07 Bridge Repair](https://github.com/sreedevk/advent-of-code/blob/main/src/bridge_repair.gleam)
-8. [x] [Day 08 Resonant Collinearity](https://github.com/sreedevk/advent-of-code/blob/main/src/resonant_collinearity.gleam)
-9. [ ] [Day 09 Disk Fragmenter](https://github.com/sreedevk/advent-of-code/blob/main/src/disk_fragmenter.gleam)
-10. [ ] [Day 10 Hoof It](https://github.com/sreedevk/advent-of-code/blob/main/src/hoof_it.gleam)
diff --git a/data/day01.txt b/data/day01.txt
new file mode 100644
index 0000000..813c4a3
--- /dev/null
+++ b/data/day01.txt
@@ -0,0 +1,1000 @@
+ninefourone1
+53sevenvvqm
+kscpjfdxp895foureightckjjl1
+72fivebt9ndgq
+28gtbkszmrtmnineoneightmx
+four66jqrbtqcsxjtqjvfjhl1
+four8pzznjbhxlhtz6bhtzdxjlg1
+rgxjrsldrfmzq25szhbldzqhrhbjpkbjlsevenseven
+slkjvk4threesevenznjqmmfive
+61ppgrkmkfhteightone
+1threesix67px
+sxbjdbtlnjrmlzgxneightthreepmqxdxhfk8jfrheightwovp
+twofour2sevenk
+sevenonezknqnkfqbzffjvfivetwo94two
+45xj
+mp7one6eightvhfnmfive6
+fhtctftxm3threefour2b
+2dq7bdmhhs92
+pdnbqlbvtcxgpnfhmsfhzstgm173
+8fourvxkddsrlcvseveneight
+15zqpmsix77hlljgfive
+jzjv6seven
+eight1vbfive
+721sixsdzbqtskbpkqbcmgmlpk5psrhr
+pqxdxcx5
+twozsf2five
+7twosixthree775
+7xtxrch7six
+729twofourlqrxtwo
+qtvbgtclhnk4ninefourseven5one
+jvhngkcdjhnmqghdbqdzqssf5onegzjbbcchboneightn
+five8two14five2nine1
+one3twomddthree
+8nine9two
+7fiveeight9ninesix6fivethree
+254kcd61dc4two
+7sixonetxvthntlngtwobzkbz23
+8sixnine6
+threedqtgmv2skmvcd
+7ptdhpvr1
+lsvmzvzvd9mqxszjmbddkmxzdxsninedmglzlzphtwo
+kgdt12seven4xxtttr5
+nrdtgdftjmfour6fxjninenineblqlthvpcx
+ninezmstcdfchc11onebmmfdfhvdncrhc
+1fiveseven
+oneone26twoeight
+threefivenine98one9twotbbcq
+9cm7ninestc
+jcrbmcjtrlzvz7
+nine8nine22
+3nineoneseveneight
+58four2three
+stwonefourthree9twonine4six5bvxgkxf
+ninechzcz4seven
+2tgzgmtzzpjdqqz
+brsptjppb28qxcxxjbzpeighteight
+eightthree3ninejrft4
+sixqsgkzdjmgpfive4threemxltqdxsfive
+vxfd2q8
+khqhgqlxslkmbrvljcnineeight1gjgcqmnbdczqb8four
+mvbltrgpfourcclxftbb7gcbqcptvgfsevenrdm
+61eight
+six8fourthree6fourseven6three
+jqdfxvhjg3sflkn2sixptxxsqrfml
+6jtxs
+seven99threeone
+five6sevensmbbrjqvdbmkbsqtwonelg
+fdvfsndt32fourgllgfrninebhnzzczfive
+9hxp9srhjhjjvqljhzprcjpqreightzs1
+djldhkkcn55threethreefourflnxnbzhkzmx
+fourfive43chfvjnvjrkpxlgjrfnqbl
+fxjgtj4
+1sevenfour2fiveeight
+seven43rxxeightb1
+9sevensnxkp3lpzxfxnntkxzkrhk7jzhmtvn6
+25one
+threeone7
+1pkfvsxxthreeoneseven
+ztbvfqnpz2xdhgdjmgvfourtworqbxqsh47
+8four7sixninesix
+threedgl88cczqhqxjnc
+nineeightthree4sixfive3sixdqlmscqjk
+16crjsdl
+tgq2sixhc7three
+tzgsqspndt5xnqlthghzfvkkhone
+4fxdqrs64ninex34gd
+seven22
+kghfkrpvnppfncbhhqpt55bjf
+hjhb71bqdrrgsrkqdtsgrxgsscqjmtfzjkzsbp
+lgdnt9threeeighteight97
+pvjhnk83sixncvgmsjltwotdmmpxknhvntfndxr
+7449
+qdfzv9hkprplzkfh
+66three5five4zdsfrcnljqmsxf2
+veightwo27bdbsvseveneightrcqcjxsixeight
+1thvkkk
+8bnxqfsdhzppblzlzbkfsksfscmb
+zseventbdzlmhnnrfive1one
+sixxnmntrmp6srcsqbrqnjfiveeightfive
+4trnzlshnjtwo5twocxrvfssbj
+6two3twonetqt
+55qsnx43
+3three23tpctbkrnqv
+sixqk4cnfdmtltmlhqxtwo41glkhdhgnt
+35fivesevenpfournxzsbbgzthjvlvzrnine
+tworkzgkcvcone53nrvgdvgtc
+two9llkjbkz8pklrsgqqzr2four
+ninecgpbgcnine4tldjqsone4six
+2tfjhtfourfour
+onebhlhdvvqx1sevenmsixsix9
+pjgjt6jkrgshxltfnine8four45
+4vsqfljrfiveqeightnvbdb
+11nfslqvhm
+7crrhqxsfive8ctkzbhqnine
+vrvtglvthreettrkq5bdlrtpx718
+1btbxlthreedtrzgeightnineqczhqm3
+193
+fcbzxqxxjtmn47ffschdrbeight
+twoh1gqkrnm1
+7ninesixpzpsn7
+5kkvzpgqd
+three6nine
+32fdn
+22twoxgvktxpxmbjqtgtbckx
+1hdtftwosix
+2jfc
+six5nvzcgmrscjn5eight4
+nineqhtczsninetwosix4five
+9three6sj
+hntktlbqmldrphqzxkhfour193
+twotwo5259
+v7six1vtlxnpm
+rhsm2
+gprmtxbhlsv8onefournine
+2fsrbtdvft15six1kxpqbnqsxh9
+one5onemxthree8
+nineqbxdbznzktxsmstsntzffour3one
+9blhkhjsgsfgsblzdtqqfour8
+stz4889563cb
+vjrbs6threeptbbmncz7hqhqgfgldtseven5
+vbfs1
+zjqgczjsjpvzvjseven4
+sixfjzbrrhcfqvglxhnsxninedrvtvjbfqjdbrzblkq6three
+one3threegcdldjsrsssixonefiveonechngsl
+7srxv4hsgjqsqfvv1tdngkpjrczkl4
+5scgdglnjbnsix8fivesixtjccvmkfxfnzvhctgpncjc
+4eightfivefive1lgscbj7kpcr1
+eightknfssevenfive6jnpklczrpfeightwol
+37qccxllhzshninebvpc8
+1eightmmcthkhf
+seven8fourqn7tbgqnmzcc1
+sixsevenone4
+clhdvjnqnine9threesix
+onetwoeight9
+81z3threenjsdhnqxvtwonezv
+9hqtsb
+onekgnlbthreeg3
+eightspnrpjb65fivevzfpvjntbg7drbgjccneight
+ninerdlsix7285
+fournineninefive3vbnhmhdvjgdqcm
+njzspqxpxrone7four55
+nfdhlqcpvzrrtsmzhgq3
+fourmfdtnpsfbxkjtgtgx5sixrppsqplqdjvnsixdtqvtdm
+21onesix6sixnine2
+fffsmvtt8fivenineglrqrmktzzseven
+fivefoursevencjxmskrqclz2
+lgk27threefourfsqrbkntbkfourvflgrzhh9
+617hj9
+ninegcxninetwohpfdxrb3tjjjtxtnvtwo
+one1gnftc8onehtsxsmg
+foneight3fsbhdqzr5twojbsdnntwohd9seven
+zkzpfvcxqnbvrg1
+nine36cddqfvrf
+rdjlpfk2pschfsdrpz
+nine994three8six
+three3nvflpftf2eight4
+3nine2
+rxxjdk5354
+hf4eight8qjtcfldnkvtwofivetwothree
+7six3twodhnvmxj1nine
+57seven3six6
+qklbvzfhclfnllhhgeight8xtvld
+5fgzqhkssmkcfour1
+hhvjkdnlffnineeighttwo18twonecs
+sevenbfzrgfm1six1
+nine71cskklxvcbnxtskdbqnpgklrxklcgccxjnssksrlkx
+hmklhhjdthree77
+3vpxclbgkpone3ninesrclfive
+djfqkgjvqpfvdsix5sixtwoeightsix
+eightlt7csvgxpnslk
+sevenfoureightnld2mxtgpbzpthree1
+11sevenglfmsb6
+onetjjnxvssg1four4drxbxpnpv24
+2zdxs9mfnbgfmjln1threefive
+one186ltsbck
+6fsbpb9sixhc
+nine818
+xzqcpcdprsqjbgknkvztwo419q
+39qfdlcnkhg31
+9djnlcrxqxhrcb8mczrxrm
+nmb887525seven
+jhmv3
+zhvdbn1fivem8seven4sixoneighttsn
+6zmmjqmnftclqbcthree
+6cpzeight92
+onepqfhtsevencvlfvnczhb91mmtdprqxmcnine1
+tvqdfxn8eight
+five6fivercgrpbtjgv87jmcndclbk2six
+jgtmrbvl68lpqkpxddqqxvsixfivesix
+nine2nlffgkvmp
+1frdnhssftg4eightgclxsgqtn
+2sixblr94six
+94mlfv
+6vlqtcsmdd47hpfmlc7fiveeight2
+tklxghxv5bzc4hhcdcpmnine8
+four6one1zzgqghvs412
+xghjpblsfpg19ntpfmcfd
+471rbdblzs
+69fourhjxkvd7fourfour
+jmrscfqdfppfdjskpk61
+five5eightnqpd9ninezknztwo
+onelknchr7nrfprgmqzp
+svxlxrx9892five2
+3ntkbzzpxhdmrsix8ttgp
+ndh7zlnrzpvmnine
+one7xlnbmjjmfv62qvqjpfprbvjkpcnine
+99three5
+threetwotwo7dhtgtbchc7sixtwo
+tmfxxph3eightgdccscdsrkmnhbb75
+joneight4one5
+nine3six
+81tqzsqpkv99
+sixvjlq7
+five7bkc
+five3811threelfpzztxzk
+1fourkkpclqc3
+xgrpbmktcthree46g
+bgcp4two8
+jtgeightwo7nine
+bkmcrcq3eightrdtvrbglmxmmztqm
+7tscmg5one2jhhbfb1
+zt5khcrgqjg5nxxzxzd
+five85
+twothree1
+eightsixthreetwo6b3tnjmcqdjfive
+onefrlg7
+fivescbjxbdnvslqqsone5bdbvskpmksqmmfsncsmd
+two83fourthreefourseventhree
+dglrmbtkfltwofive8ninelzmrxvxoneeight
+8nine6sixsixtwo7
+sevennine4lbsevenkdnrhpltn
+h3fiveeight4cplrnd
+vhsgjbqm3ninedfhfsb
+93nine7jvjmlzgcztrqlxtwo
+zhhhdddbbgcssvfzdhmpone5fivefournine
+l9fourvjfbqpdslkmvxsdrnsgcvzpjxm
+kxlseven5two
+rbtwonegsdgvsjtpnnkone7mdz
+phffknvthree2threeqgvfqxgnine7
+2lgglnmthreeseven27three81
+lrgkrxx2
+seventwokxvzkvq6eightthree
+5fiveseven
+fstwonersngdlngx28nine
+49oneninesix8four2q
+hfvhzvmjgbfcbsevenrmhjhzkc3
+six84
+8eight2gzblldzvkjfive
+6fz3eightzmsqb4qsbbsnthm
+fcglpc2one51
+sevendqghclrpxt7pzone48two
+three5one
+5sevenfivebbzkjlcnxseven8fourmzqlxxgjvc
+xgg8one6782
+gggtljnnsix3lkhdqzzpdtdkmjtgjddkpgx4five
+qrmsfc13onevnhlbgs
+nrtwonethreerbbqffzh62
+5eight81gcdbrx3rlk
+mtdtxcmm2bgmqhgqrtxsn8
+onercx2
+9sixoneqgr4
+xmoneightfour2
+six85foursixninetwo
+ninetwo8four8six
+qchclfzq47
+khrll3two21
+seveneightnine8868four
+3rmbmtbxjp12seven
+3tsxgvqxmzvxbdvxtgrvdbzqbh
+eight7fourjtxx
+fmb4one7threekbxeightwoj
+vcsevensixseven577
+2dkhlrrtrnbgzrmxm5fiveclhgn1eight
+1sevenlmrbnfour17seven
+three5jtbvkseightoneseven4df
+fourrgqxplbpbxtsgkm7
+fourqdfxchlc371sc2
+fqxlmeighttwo1seven
+zvvlftlhfthreesix6three46qkstxvdt
+m74pjgccfour1four
+plphq933eighteight
+cdbqlhbhj3eight
+4onevgdkxhz799five9fbljhpqmvk
+two6qzgphxl
+two1eight
+onekxxghlonerqqlrs83threehvvdhsxmfour
+npmsvvrdl2673
+fivejthseightsixtwo9vgrvjzbzsrxjv
+eight2gqfive7mzjzpxqcvheightjfx
+1bxckdpt
+dngoneightbtdptfn85
+fourtwovfzgmxjseven935
+8onesix2drgjnlrxbtdlmlznine5
+five4mmpmqlttsx56ljdzldntdvthree
+1nxxgtwothree22twothreenine
+38eightsevennxctjfstp
+8fourvhnps3onellstpnztn6kvjccmv
+1bseven93eightfour
+5nphkdbhxqb2pqxtkvhxq
+nvvx6fourjgkdsczjv
+fourxrmq78
+8tjmnvthree3ninetwo2five
+p7cvtwoneq
+7thbggjbznrsixonethreeninej
+xdgm1crqfnklk
+onehmqqgh4ninenthjonegfjmvtfgd
+sevenbsqtlk9
+8seven9two9hdz29
+fbcjhzdgzdg8jgjvcrmgbcrsixnine
+3bssqrj44onedqxvhkfive1
+tmmxtz5dtxbbcjlfivesix
+pvfqzksgrs4khmlvtwoeightlsx
+psbttsmnpninefour42fivegsixfive
+sevenfiveqscr7dfxpninesix5
+xmsjddzfxftsjfq6four6eight6three
+seven42
+eighteight1nineeight9
+8c
+pmqljjjzvx5znxqnsfour8
+78zlpxnvsqpgmgmk
+four7fsgttnrgnlslr
+fourtwo3jg2
+qlz18three5lpxfjvnfppqjxh
+4fiveonetthree4eight
+7lzffxkxnzjrtr
+three7nineone46ksnshqgdpt
+8dntxkkkgdxggvhxh2onefour5gqzsqkm
+tjsixonedbklrxxk2twonxdpjzb8
+mfglbrjrq93
+seven37xhsrxrvcgninexbmdrzxthreeonethree
+fivegznvfztszqlhtrsslsmqq43212
+tdthjjjbkeighteightsevenpcbmpfq2
+five1eightq
+three13three4vrsrrtp
+cgztjgqgdths2
+dhxztfvlonetwokszrv8prdpm2
+dfkcklchjj8twonine52ppvndfcnf6
+three7ninenkxfourfive
+93sixlqxctdhmvssixone
+oneqbvfrvteightnineninefivethree9
+jskrtmvsrqnpvcgsmxbonecmlrjpdpc4three
+crpcfour54xxgzz
+9fivefhdpcqsd
+fivenineclfctjninefbsh2
+fivexhrzbqpfxl8sixtwoeightllzplcpllk
+zxgl5qneightsevenone
+sixpdc17thxfive
+1twolftpzbmnzvdlkvlsevenhdvgfrjhmthreethreeddkdvht
+67twotwo71
+oneeightcgnhtdxpfnsevenoneeight13
+eightthreervd5tnj17
+ssrsmhxrsixeight3gbqggcvfqg29
+6fivecvcdxnxhxxtlzthree
+fournrrsix595
+p2qchlvplzdvchkbdzzbnsix7ninefour
+fourthreefourtzvlrnr9m94seven
+4jxzkrfourvtjpsnrllkjcczmmqnsj4q1two
+4627qlpscgpjcnine539
+two6nineeight
+63five66fivethree1
+skndgzsbsntwoone1
+threerzgdxgtthree2three
+953lsdgn59
+27bk
+sixmfmbslpjjsixsvnqrvtxznffive5
+2ninenlgpggxm42six234
+fdzfvkjnchsevenfivethreetscllgjvrtqckfnmz3cszmt4
+7ninetlzsxjsl2nine3
+shsvptqngsevencjjthvfm9six5four
+7lsrq36threevzfjc62
+two59threedxmfourjfschvqvnine
+khfqjmksxhbvs8sevenhzrmjtkgm
+nine2stgflmsm8fkthhhjzlszdnmkmqpnjxrfc4
+twofourthree244nine
+eightvt978
+fivefiveninesixnine6513
+2lbtz19fourtshqsvblhrkhxbpfour
+ptt7bntxhdvl
+mskflsslvdlmndmmqmfourtczqlssnineseven5xxxkfvzd
+l329eightsevenfourfivethree
+rmlksxsixspp9fourhlcg
+8five9q
+hqoneightsix19nine6xmjbtgjzgrhmlrxq
+six38
+9eight2
+3sixbzhgfcg57sixsixjtqmknd
+9fchn58
+vrpftbnvonefour6
+vqgdtrvhnnxxsevenseven9eight
+56vnine5rdpsnlqcbq7three
+vncrjds2cmrg7
+213sixfivesix
+tzclpzdsthree4sxgjvrzcrzcndnfour
+4sixseven1three7
+8fbrggzmtqn8
+four79p
+twonineqonemfour3dq
+5fdgpmrghtksn5onesixtwo
+xseightwongqqsxtwo8jslclldvnb
+nine1one
+9gxjrfourvhqzcxdhrtpxgtwonine
+eighthfhtnvchtc7fjkrxsmhtm7rbk
+thqxcfjbksix32xqrgqsqtx
+6qjqql
+jgcreight7eight
+6onesix4threeseven
+5vcv1twoeight7
+fivesthreebvjntwo9jdxghmxvl
+632msc9threenineqfone
+dqxfourkb4eight
+6stsp3nine
+566sevenpdmg
+xprjdn55
+9mjtcmhjb
+twoninelkjznqztbc3twolnhjhdbfxmhfr
+twotczpxn6qlcfdlpnq
+4ninefive
+1rs44three2gzczjdgq7ssmtgjbgbb
+ggmzqbkgsix4five23bftjlmbfbd
+threehfcscmmlqvcjtpthree98
+7sixsixone4
+2fivefvrr9four4three
+1zt1seven
+9hsbthqvhhsnineone23tslqccg
+sixbqvd3
+22148four3
+ninejlpbtnfive41rtzqjgfmcbncrrlnn
+9sixfour
+qnhfivetwofjtqtlxd7lmrlfctq864
+69dqrzhlqssgcsxtz54cpmjvrkcfiveseven
+fiveqpv85frkmpgxgc
+xxqsscldeightone9ngqtkf1nine
+5sixgxbnnjsvhf5dgxgone7
+sixsevensqghlvkfxnfour7
+8gmgvjbfivesevennine
+qj796fourone9
+rmpfsppvzdtwo4threetwotwo9
+dqvtrhm3nhtrxxccmfiveonedfzfvcghr
+4threejxkhnxcxjoneightp
+sevenhkpfgdgsgnvseven3m
+qhrvjcnfdbqchrsvchcxfourbkhhq9six1eight
+29pqnd
+1oneonethree627
+5977rcr2threeeight1
+fournthpqbztrhnine64
+fjnjpgqxr86five4sixxhrtvbp2two
+7sdnvlb5two
+58vffgzcgx4nineoneeight3
+h1sjgqbhndbz1oneqgncmhnleightwos
+gjms21
+onetwodphfznine51
+gxpl3fourzfz3
+five46
+mqsixccffmc9gqk1
+5kvxpqrrpeightthree
+threefoursevenfive2dhtbrxlzzl
+shhczssbltllsmntntlqfqgnnl98rm
+5oneeight3vkqtwo29
+bv69fouronefourone6
+eight6five966
+4xnrtztgfgcmnmnsevensix
+gmsvtnjd1sevennine4xxhqfbrjjqbglqjngttc
+mdnxhhteightfive5onenineninegqjbqmfd
+xonefourtwo4
+onesix61
+sjmnjhkj2892eightnine9
+nzseven39
+99nnjjzdrfsnjhthree1sevenfive
+6xmggtbnblnbxdpkzblnvcvjqmhvntwoeightseven
+76five6six
+chdfjrlfhdzeight778
+xrvrck9five1hrvpfvkdcb7eightnine
+foureighttq5sgdfourl2
+4rnbxrhhboneonefournine
+5four3
+1b97eight
+hlcjghlhsf32tgknm565knxqr
+onecqgbgdcmlb2sixsix6nine
+kxdkz3
+seven5xvhrxdm
+xblqbgkqgsixvgrthreezxnzhknklxhbmgl4
+fvnkc7threethreeseven
+bmbqxv24jhdg
+97rfphlxvtx
+4pgblonelone
+ptdpllrddeight3
+9knpjzskrfd4
+twomjqdtbbvmj4shvsqrone3
+9zzh3pjsf6mhxlhm9glglfztjm
+cfconeight47fivetdsmndgvsmbqjvszb
+21vbqjz374
+sixeightqgfdjbhfd4oneeightone
+tbccqdpz78srmcdx4six2
+643gqtvhkljxt
+klfjf4qms
+zrnhkhqzpczzfqsgsrtxklpbtp72
+1cnqfltrmhphg832three
+twoseven5
+mxkmxlcgsixklclrkfr8638fourlrqpzgjq
+nkbfkh452pthree
+zvcktvd2485four88
+rfxj4
+three6jnr7
+two45rldjnmxkjphtwo7v
+fivelncjffdnkzqrshvthreeh3p
+ninejgrbmhrbqldeightnine6nine8one
+96lvpt2djrkc5
+7seveneightthcxgthreeseven5hpfddktpj
+6bvn
+sixbjxtphstzgspnmkcvc952one
+gmmslrndvltlthree394sevenoneightl
+threenine7onefourtwojxhzvqlseveneight
+5eightsix4txcczzmg
+84seven
+skjpkhxggsvjbprhllgjhninetwo6
+72bdpzccvone4zbdzlllnnonernlfvdpq
+bvrtmzmtwonine29
+mrlvmdnlxb2814five5fjxzlhpn
+lmrpf82rksix611
+tvq18oneqnmmzvtclnthree
+jrbjc1zbbpqbrddt26seven1
+lxfivenmdtnhdmf98ptpxsgmgrxkmmznlk
+zbmvchmxsevenddddthree2dxlddjp4
+three3onejg2fqgtjmpcgeighteight
+three2two9seightfjqtwo
+ninefive8sevenvnssix
+3cnbxxtgmf5
+kpmjcsfrjfgzhmbpnqmlvrhbhqs8
+3vvcone64
+fvqksdsixthreexbfivetwo3
+sevenseven5
+63twoone8vhbcpmmlfive1
+4ctwo17eightsixkpvlgpj1
+rsgsnone1
+kbvxonemcqfive3eightone
+ninenineone45threepvsmrtonejxmbnd
+37fklnjkslqk9th9
+fiveoneq8rcgdxtwo8jfkxq6
+rgd7
+7rgkdpvp7qrb
+7crtxfmslxxtcxsv
+mqdnltb23fiveqcdqtonethree
+8seven7
+8cqhqlhndqjznqhdbld2nspnxbj99tqqhp
+onelqn7
+bvbjfour7
+ldqzhvhrbgsrrkh5j
+kjsjxdcqgjztldjvxxgr9twoxfknxrrrphkdzdl8
+rvscnztblp56ljqtwompclcf
+2dbtdgsevenhzctckvkvxvjljz
+tvmhhxbbxvvsnlnineqsltjd92one
+9twoqdmtvbxhpcthreeeight
+81dvnkd87xbct
+6mnxqnndcjfivefdckzmppfsevenmqvvvbnrgs
+lvl3qjk5
+3fivefive
+ktvsqzrf14eightmtnqbcktk5
+sevencdknznbxseventwo8rzggmvpbvlrs
+hkhhrdxlml1xzbshninejzqc
+eightseven23shkgzdgvvcxxfdv5
+14five1sevenxfmhtptwo3seven
+47one
+2three3
+f5dszzs2
+xmxffxkxpkninethree8x6seven
+glzoneighteightrnjqgjznjm9
+63fznqxdfqt8
+33nine
+4vrbmthreefbdzf
+fourninethreesixnine9fourlvbgqhjbqncnlbjbz
+two848dbvbninenine17
+pqzqgone1two
+eight7lmxbhcsix
+szr2fcvkljctlghhthree
+sk81pxqhhhhvnjvgzfiveseven
+cgqqkrz2vpdpzrthqssg7nineeight
+498eightfournine
+eight85onesvxnineone53
+ninevmchpkcg2
+six2shsvqfivefourtwo
+mdzckfvr72cv
+twotwo7onethreefourdjtgjg
+tworfclmm3
+5sfvnkrmrptsix7four6kzlmclm
+1onedkqgzbr89kphvc8
+5seventhree8eight9eight
+kvjpgjgrcmpdscbfthreethree4mjqjnnzceightwohh
+kjbmh1fdkdtznmsznvlconeznineseven
+1fmgpxhxpqznqscvbszhhcmglvtnzhbbjjbzg
+1mfqzkfnine5
+rrflkqslxztdlqxqkdnhqd7ps
+39123thhsmscbpxr
+8vnine4jgqrvqtshg3jhhdnbsrxneight4
+xkqgnfour87
+lsbnjqtzqz7ninenineone73lmkbnkhs
+9fiveqqgqblfivehttxk
+8twotwognd
+4xknbheightfour6358
+4cqtpfjpf72eight3
+ninemjpqpqg8foureightsevenfcvpnrnnpzhcgkm
+37twofivedsxrzbpchnkgxqx
+oneone57one2k92
+mckoneight9threefour1onefourhdrcrvhqcmngkjnsthree
+945
+tmmtwo7
+57
+6twoxzbfftnr27
+threenine4bqpztsixfour
+84eight
+3jpbnjrqhqfnxckqkqdvls
+9gzzjzz
+374nine
+ninembxeight4sevent
+threecq3
+cvn6cvqmpmfflkzphndjnggtktwosn
+pgz7four5nineeightsixqrnfkdkgh
+6one781vstwothreef
+one617fourthreefourxqxnpv
+8eightsqmkjkkf5xckcvd4lfnnfour
+seven23qhntfmg56onexkjxh
+f5s56rfltx282
+twosixninefive1tlzq
+threetdhghclfsksql5oneninetwoseven
+zbqzxmpb9pxlrthree
+r4gxdzjnvzfonejnpmfcpgvxjjvkh8
+five338threejkk67seven
+twolntxcnzvfr55sixtwofivesevennine
+xhlppbqfr71brvppsixthreefddlgpfslqmdv
+kxsklgonefjfpkd4threefive9six4
+6srphqmtdoneh3glthreefour8
+rjzdmj1cqvxnx1nvcvbfctft9
+3fqjdgbpggthreesix53
+9fivesndgmkvckblktzkshglqgdl4ztwoseven
+qqrxkqhnzb23two34nine9
+8hrmffgstqpsixeightx1six
+jngcsjnrhn2zsvcjmjg
+9zfdmhzxdnfour272dcrqgk
+lbjbrfhjxhxjphzxsjsix4
+fourthree2seven1two
+twosix87
+vrlqqkctddggcvcjcpk6hxbqvbxmtsix
+mrcgbpc6dthzqmmthreefour6two
+r2zntjxgpfqfmqh
+fourseven3
+6nfnsgchjdffttmgfnbvlxzoneseven8
+8sevenqqfiveseven5twojvgk
+4rmtkvml4
+bprnine85
+sevenmfpcvlblcnine485fourseven4
+sevenseventhree68fivelhqgjqvcdqkvds
+3fourxsgghqnvtssnvfs7nine7
+1fiveone5hpfdgvxb
+eight2eight42twotwoonenine
+lpdeightxcgpxkkeighthtjpsninemjlxrxtg31
+4smqpjzsixonethree
+mr6csbmgrdrjj3onelqd4four1
+5sixvbscchd3
+384sps
+4qzgsvmfx4ninevcclvcfrfp6tckcpvj5s
+8l5glclltgcjgbhcg6
+3ldtdmjc6threeone
+hsrtzl521nine5qqrtpdsp
+z4v8threejdsmbfjpbj
+9sixln26eightwovmh
+848
+kndxtqpfrqxdxtfnqrqznpgvp9ninerlzcdvdtwo84
+kmqs84775seven
+5threefourzkg
+43five8cq2kprvdqrmxr1
+three4ttjqdh
+48nine7sixfive
+22x
+sixrgtwo3rnbzkrztkdkg
+4t
+29bjpskmxneightppvthree
+zmlzxvtlkt4seveneightbxseven
+5two5eightnpszzmbkncnstx4
+9vk98sevenhznkxmlrlk7vdbqgvfjdk
+1sixb8sjkvdhfld
+one42eight4mrsdnpfjpvdtq
+76fourntsrfllxkdfqvm6seven
+skqndhr3nm4776
+4xpmfxmvj633eight
+83ninecmpt
+fourdthree9
+9eightjqnnmthcrseven
+7threekgtf1
+xscj7threenmhsixseven5s3
+cqlzjt41
+855threemlmmqkgtfk
+ninefzmvjjtvbmgf8nineninetwonegcn
+ccpkzcldfourkdtfkjxvfb9fourhbtwonsoneightnl
+pkeightwo5seven88rdnzzsdkbjeight9
+threen2fjsfivesix26nine
+nine4rz8nine7bglpcmkqfzpseven
+eight94six8dpgrv
+twodfctf278
+fltqtmdkgjsvf72three
+llrtzsixsix4fivetwosixone
+qjhtjqjhgkjkzlpxxclsrdnzk1gbqt
+sixeight1sixtwo
+one5413nkmqjtlbdkz22
+bhtwoneonemzpzkqeighttwooneqkmcmsbq4
+sevensix3three2sixprcqcvm
+25tjffdrtwohfqlkhzxlhb
+97gcgqgjnpsthfjfdv636jsxq
+zggjmjone1297six8drzs
+jbpvnineeightntkkshbjvr3nshnqzdlkjmkfive
+5four2gkkbxmpthreefour6
+5two15sixfivetzpg
+one4fouronemfpvnqseven
+9fnlbljdnzzfournine78
+djfljccrtvvqktzzvk61onesd
+7twohbkeight
+seven1eighttwothreet
+4mdcljknhpqgxffqpj5
+nine9jlsmfgdgntwothreeeight4
+136nh
+635ninejghg5
+cmone7fdlk9lfivemzvnhkcsp
+8eightnlndm
+6fourpb892
+fiveseventwosixfourthree7
+5fm
+ninegchdnrf63431
+24sgnflnsixninenine8
+snm9
+3fntd721dhhkrqqxsfpstsvzpgonetkhcr
+jlzfbml61vdmgb7one
+266517
+7fivetwo2vhchmg678nine
+cgrp3vzn5ninetwofour
+666ninefour
+9s
+svpcnlktpxtvk42jhsvvdpftxpsk
+2qznfzvbdr
+foneb7eightfivehlbjjknninethree
+kfp6
+l34pxxhxtd7d
+rsbcrtwo27twocqlmeight
+jkzgvqgpjfdqvmjfx2flnvjmgllxghhrbjjkfour2
+45sevengdnf59twofive
+6fivespvkblrxvkcgdxktl
+three9dvrssvl5eight4ftsix
+seven56gdmlbfbjsl894sevencmc
+814
+1one4
+onenine5fivekcrf1gvvfhlncsv
+2ctvq9djzddfxcrj
+ntdlcqgsixvmfvlc4fourvlhtvvqmnmkrm
+9nineseven1seven
+lcvzbnfourksvjqvmv47one5
+nine4blvlvlpkl6
+sixnqxrhnztzvpmbzmxjm19five
+18jtzhk
+rzrhv8four
+2npghxvjonebchsprfhsjznrxvxnine
+eightngsevencrjkxbhpgtxlzhgb46sevenqhqmlfx
+threesffl9fivelgmndjfvseven92
+seven85
+87six9vnshclz
+threetwo7915three
+one2vkbp6rhqbxvcl7
+bsbr1five91
+qd3mnine
+jjvhltxtdh5nineone6
+mbxlnj7bbhnxonejtmtqjfrzqgtrhkeightnine
+fourfourqrxdtfive2smnqp
+7tvjrszvrhdl5five
+four15tvmpvxpvdjnine
+sevenvv5tworpvdlseven3dlqvgblqtwo
+nkckggninegnlqlnv25threexlhlbzvzk
+3vngmhprjseventhreeeightnine
+nvqtpzsszrdvttfivenine56oneseven8
+146
+fxfbone59
+f32dhffctkxp6rcngvtfq
+sixthreefsixjhckmjqfive495
+42four
+65nine984
+5fthreeone9twoqqsfvzmp
+ttwonefive4
+one6gfxseightxqcq6
+3sixnrjtwormrncmhxeight
+jhdxnmsgsdsevensqsslbsndpdmznmldbgeight3tcvjjv4
+5sixtvpckxzcjzbmrzk9
+pmdmnfgkb3six8xsmstsmxgmm
+53onetvlgbglq4zbqpdgsskzdsksd6
+kzjcllvz6skphkfdxfiveqrbhmk
+75qqjdgxlmfthreevzbfjdlxkfqqq
+seveneightjntpjthzptwo2two
+2five4fvrfxxnine4qzkkfkmq
+2xlvcltn7
+fnmggtj2rqxzh7three
+rzpjkgtml1
+2oneseven4one7xps6
+rljfhfrhmzkjxktnszbkpfspxdkqneight2
+pzgnine49six2
+plxsqeight2
+eight2sevenseveneight8rfcrsdlxb
+sevenclpqqfxgjnmtwo9
+9sevenrqsixone8eightrxqgfsbjh
+kqtkstrxhtfzbllhl4lqvqkcbr
+hfplfpbltczflpp7nfive8
+ninenvqfrvtwo6onel
+threev65
+frhn18six9sixninefourrsqzgd
+mcxckfg5vpkbs89gbninexjzvlj
+fivesixdx28
+7ppbqv
+hs9twopcvpgtjnrsvksskpc8
+9mlpckzj2twothreefive
+rkrgdclkninetwo6eighttwodc25
+tfivefourtwohkhhgsqlj1dtdcxmxkf
+1four6five
+fgbvmvxvtsix2twonine2sixfour
+foureight66
+s6fourcv
+mxl358sixfive8six8
+ztbtwo73sixvxsix9four
+eight7qmdlcxfive5
+phgfivekrjxdmnzsqsix9
+1mfqsevenhz
+rjhcdgzngtc155bqlttbsxklpknvlmk
+qjkdqlrrs6two
+sxlmqzxdpxdnj9fivetwo9seven5
+2qtdblb2
+8qgdzrsixtwo598oneightp
+1shdb944
+vrlpronek2
+jm52
+8eightfourseven11mvtrmtkr2bmp
+mnvnjxrgmrxhztwo2ssrdpqk
+ztfive435three6threetwo
+tnrrdnbgnbhzljdxhxxfrqkcpeight8js3
+foursix6zcsrztvgjxmp
+five7fourgnnkspxcmczcbgsbdf77five
+fgbrzkmvgrdbqjqndpfive81onetwomtzlfb
+2qbsfd1two3ninetwo2
+8tdjxvfpvdvone33three
+lpchnmln56twofive8tfour
+cfkfbhppjf6fourdkfxsvdtbcjspzlseven8
+5fivestgkzsevenonedkhhrkthree
+37nine8six8onefhvvbkmgdfgtv
+26hzz
+5glvnsztmnfjmkjseventdm4five
+pvnnqrqvftrbcvnnthreenine5
+mgscxxlp3eight
+53eighteight
+two1oneqlcdkbddfour
+jbll3
+8threeseven5tmtrgdhqxd
+8twonine6s1
+91seven5pmqrjlhqrtzs
+jj3sevensix4482
+jeightwo7lk4three
+zchchxmsctzffivefournine9sqhqkgfour
+72xct1
+vnsxvsqkhpfvgdseven23gzcmltzgone
+xzjqhcvsix1fivecjtxnfivekmvjdc
+zdfourgjlhtwo24d5klkpdgqbz
+7sdzzdbrxbtonerjcmknnql4dfzqccvqt
+tncqzxjq9twofiveqkxdrxrpj894six
+dddmkctrzlpfmsszeight8zvbpmpkg
+three23ckjhgjc
+375jzdhnfcfr19mhsbnplqh
+vpbbjlzone5sevenseven33four
+onejzfsevenrbskjq1four
+seven13one
+vcnkfgv979one6zln
+rqlxzzbmjb4lmbthreektqsdcfzbmdsfivethreenrxdlkqt
+qkoneight8
+5rfourfivenine94fdprsix
+onexonelzdh2lcbqpzq6
+six6v
+7gtgxqnnine
+tsljzhntwo3fourpbjncgmvf3fflvjxp
+vfkdone9fivecftvmjdk
+xc5three6eight94
+18363one7
+8fiveksshdlfmzhljhcmjrn7kpv5j
+xbhmxfhbjnjzmninethree7
+2933mkmdqjcl
+6ncvzqxfvgfive
+lnine5fivetb4qmfktnqjxs
+93187
+5mqninedzkfhbk
+two7eightntdbsix298four
+sixone3bspxqxggkmkrbcqrhfrxrlgjrlvfl96
+fourfivehqls3nine
+threedfklszn2threeqzhh7one
+mqmftzglone6kjpgglznhrjz89
+146cvkftscqsevensixnine
+nndhdgpd484hxdgjtfsdxxg9
+6mbzckbjphg
+eight6jbjtnld2mdjtd
+zjtzcqxb736five
+jlkdmone8
+gvjnjvmlfvcmvnfb8xcgjcmjqvz1bzcctvsixfzqjlhfkfk6
+vr6onejnjmrrldnsixsix5six
+ninembtmtkgbctlfive45cjzzrmgcscfbcgeight
+2mdvneightjzgffivefive4
+hmdnbxghxjxt4czshmsfzc
+61six18threehrcj
+six3five6eightkdfzhxcjkdhq3
+jrhqrqkpd4hsixdsbjdpscclmnnhknqq16
+jflzcxr3three
+threefourghvgsktkc93cmjmsgh8one6
+96fivesevenslklhsfmpz
+jgkpgfnnbq2pmspdfhsqxfour
+g4fourthreerpkdhjhlxlzvnineseven
+xkxhkphnkvpdnlncn86srxthree
+7sixsevenrfour
+5zr72qltsrbdsv
+ninervqzdfzqmf6five
+8jslpvs73
+ztvlxndlm5twohdhmtrdnhbzdrxb
+seven6nine4dpdpvrtrmqvql
+jfz1
+5nineeight5onefivecxtqbsdtbthreefour
+fourgeight6threeszgseventwo9
+sixfour3
+npl8
+tzjkffsvbjseven5rhmlxonezlx
+5dhtpfour
+twothreebxtfndvdnine1sixbb9
+five9nineqlzrmtgs5
+9v764nineeight
+five4eightlsix6
+3nineeight21
+foureight8btsc
+3xgdgtb2
+7threetwonexqk
+kkqsix48onefourhlsh8
+onekgtdzgfh2fivenine2onerb
+six4zgcnlhmltrxp5xphvtwo9
+eight7cdqggpssix
+niner9pzmrbqldkljmgphrrgmdjseven6
+439
+twofoursixrthree5bxppnhqtx
+bmpnt3
+fivepkzkzpghrptpksevenseven83two1
+9fiveone8one
+fiveseven3lqxghdlskbltrzrstwo
+fournine3ninephlghonetwoeightbvmdcconeightq
+three2pvklmzqjfh4sixonedrctlsfdfour
+three91spjlscscjcxbbpdhrg37
+57qqjpdfppsix1qxrh5mlmncf
+4nfone5eight
+eightqsix7one
+4jtvxfd38hnrmqkbnvfxpp
+qmfsspkfour1plmslcrsseventhree
+fzckcbfvxbpsix7nine
+fzrj4
+4threeqntnineqstzjftnine
+tkrh6sixdqflrvtmzmfiveseven9ktmtvprkxhfour
+nine4983four
+mpllmjrfgv66five3kvhthplrtwo7nkklb
+9ngvdjddqbz
+5twosix8lbhmzrg
+eightsbmcfgm76two4hhc6
+seventwosevenrpm6threeeightwodxs
+xkbseventwotwogmkxhpmhm42hvvbfchreight
+gcqeightwosix8xdlhrnnbkmsevenqdbrjghz
+458ninextfjxvgsq5fltdsk6
+rlgsflhxqd5bdbhclmrthree
+twothreemqqbzjn88blvqxbseven
+rqrrdrmlfsixfive6
+eight959tzxkgqjd
+txdszrn5eight3cqeight1brqr
+45122
+jvvslnkdk6qnfzjzvseight55eight
+4twoeightgrhhkrvtkrzpfive7seven
+three8gsmkpzsmfvf2
+fiveeight5sevenone9twoseven
+4seightjjdkdglspz3vg
+sevenssrzkspld2
+qnzcvcthrsgjlnzxmxlppjdpnine8seven7
+eight7xhvkrcr
+two2tdjdfbqtqxrs119r
diff --git a/data/day02.txt b/data/day02.txt
new file mode 100644
index 0000000..8a9d45e
--- /dev/null
+++ b/data/day02.txt
@@ -0,0 +1,100 @@
+Game 1: 5 red, 1 green, 2 blue; 2 green, 8 blue, 6 red; 8 red, 3 blue, 2 green; 6 red, 1 green, 19 blue; 1 red, 17 blue
+Game 2: 4 red, 5 green, 2 blue; 7 red, 14 green, 3 blue; 2 green, 5 blue, 11 red; 10 blue, 3 green; 9 green, 6 blue, 13 red; 7 red, 5 green, 9 blue
+Game 3: 9 green, 18 blue, 1 red; 6 red, 10 blue, 5 green; 4 blue, 4 red, 15 green
+Game 4: 1 red, 13 green; 10 green, 2 red; 3 red, 4 green, 2 blue
+Game 5: 4 red, 2 green, 1 blue; 4 red, 9 blue; 4 green, 1 red, 6 blue; 3 blue, 2 green, 6 red; 5 red, 4 green, 1 blue
+Game 6: 6 red, 3 green, 6 blue; 3 green, 5 blue, 12 red; 3 green, 9 blue, 3 red; 13 red, 8 blue
+Game 7: 3 blue, 1 red; 3 blue, 10 green; 4 green, 5 blue
+Game 8: 11 green, 4 blue; 4 red, 4 blue, 11 green; 4 green, 3 blue; 1 blue, 6 red, 12 green
+Game 9: 1 blue, 4 green, 1 red; 5 green, 3 blue; 9 green, 4 blue; 3 blue, 1 red, 10 green; 6 green, 2 blue
+Game 10: 5 green, 6 red, 7 blue; 7 green, 5 blue, 5 red; 8 red, 6 blue, 8 green; 2 blue, 8 green, 6 red; 6 blue, 8 red, 4 green
+Game 11: 1 blue, 10 red, 10 green; 11 green, 2 blue, 16 red; 4 blue, 7 red, 14 green
+Game 12: 8 green, 9 red, 12 blue; 2 green, 4 blue, 7 red; 1 red, 9 blue, 7 green; 8 green, 2 red, 10 blue; 1 green, 5 red, 5 blue; 6 green, 5 red, 1 blue
+Game 13: 3 green, 1 blue, 6 red; 1 green, 10 red; 1 blue, 15 red, 2 green
+Game 14: 2 green, 6 blue; 1 green, 2 blue, 2 red; 5 blue, 1 green, 2 red; 4 green, 5 blue, 4 red; 4 red, 5 green, 4 blue; 1 red, 5 green, 6 blue
+Game 15: 12 green, 7 blue; 19 green; 11 blue, 16 green, 1 red; 1 red, 2 green, 3 blue; 8 blue, 1 red, 19 green; 14 blue, 3 green, 1 red
+Game 16: 2 green, 13 blue, 3 red; 5 red, 12 blue; 6 blue, 8 red; 4 red, 1 green, 4 blue; 1 green, 15 blue; 4 blue, 2 green, 1 red
+Game 17: 11 blue, 7 green, 2 red; 12 red, 8 green, 8 blue; 2 red, 6 blue, 6 green
+Game 18: 1 green, 2 blue; 2 green, 1 blue, 4 red; 3 green, 16 red; 2 red, 3 green
+Game 19: 11 blue, 3 green, 3 red; 11 blue, 5 green; 3 green, 3 red, 8 blue
+Game 20: 1 green, 6 blue; 4 blue, 6 green; 1 red, 10 green; 12 green; 5 blue, 1 red, 4 green; 1 green, 5 blue
+Game 21: 7 green, 3 blue; 1 red, 5 blue, 6 green; 1 red, 11 green; 8 blue, 1 red, 10 green; 1 red, 5 blue, 3 green
+Game 22: 3 red, 1 blue; 3 green, 1 red, 1 blue; 7 green, 2 blue
+Game 23: 12 green, 1 red, 2 blue; 10 blue, 1 green, 1 red; 9 blue, 8 green
+Game 24: 5 blue, 6 green, 6 red; 3 blue, 1 red; 8 blue, 2 green, 12 red; 1 green, 2 blue, 14 red; 2 blue, 5 green, 15 red
+Game 25: 6 red, 13 green; 1 blue, 1 red, 3 green; 1 blue, 12 red, 10 green
+Game 26: 16 red, 2 blue, 7 green; 1 blue, 7 green, 8 red; 1 blue, 3 red, 9 green
+Game 27: 4 blue, 15 green; 6 green, 2 blue, 1 red; 9 blue, 10 green, 4 red; 3 red, 3 green, 6 blue; 11 blue, 7 red, 11 green; 6 red, 5 green, 13 blue
+Game 28: 10 blue, 8 red, 10 green; 4 blue, 11 red, 6 green; 8 red, 9 green, 10 blue; 4 red, 9 green, 2 blue
+Game 29: 4 red, 9 green, 7 blue; 10 blue, 6 green, 4 red; 1 green, 2 red, 10 blue; 3 green, 9 blue
+Game 30: 6 blue, 9 green, 10 red; 6 blue, 4 red; 5 green, 2 blue; 5 green, 2 red, 2 blue; 6 blue, 8 green
+Game 31: 7 blue; 2 green, 6 blue; 1 red, 9 blue, 5 green
+Game 32: 8 blue, 2 red, 4 green; 6 red, 2 blue, 1 green; 14 blue, 8 green, 8 red
+Game 33: 1 green, 1 red, 1 blue; 2 blue, 1 green, 12 red; 1 green, 1 red; 1 blue, 2 red, 1 green; 7 red, 2 green, 2 blue
+Game 34: 3 blue; 2 blue; 10 red, 1 blue, 1 green; 5 red; 1 green, 1 red, 1 blue; 1 green, 2 red
+Game 35: 10 green, 1 red, 16 blue; 4 red, 10 blue, 9 green; 1 green, 7 blue, 5 red
+Game 36: 1 blue, 3 red, 16 green; 1 blue, 3 red, 1 green; 9 green, 3 red, 8 blue; 14 green, 6 blue, 3 red; 3 red, 12 green, 4 blue
+Game 37: 11 red, 3 blue; 15 red, 8 blue, 6 green; 6 green, 19 red, 11 blue; 1 green, 4 blue, 14 red; 12 blue, 5 red, 8 green; 4 blue, 9 red
+Game 38: 4 green, 10 blue, 3 red; 1 green, 1 red, 11 blue; 2 red, 12 blue
+Game 39: 3 green, 1 red, 4 blue; 9 green, 1 red, 18 blue; 4 red, 4 green, 17 blue; 4 red, 10 blue, 14 green
+Game 40: 5 red, 4 green, 8 blue; 1 green, 9 blue; 9 blue, 3 red, 6 green; 8 red, 9 blue, 9 green
+Game 41: 1 blue, 9 red, 3 green; 9 red, 10 green, 15 blue; 13 red, 8 green, 8 blue; 19 red, 6 blue, 2 green; 7 green, 5 blue, 12 red
+Game 42: 15 blue; 1 red, 1 green, 9 blue; 6 blue, 1 red; 1 green, 4 blue
+Game 43: 1 green, 8 blue, 2 red; 1 red, 1 green, 6 blue; 7 blue; 7 blue, 3 red, 1 green; 2 red, 5 blue
+Game 44: 7 green, 11 blue, 6 red; 9 green, 8 blue; 4 red, 15 green; 12 green, 14 blue, 8 red
+Game 45: 4 red, 4 green; 14 green; 4 green, 2 blue; 1 blue, 12 red, 5 green; 3 red, 6 green; 11 red, 1 green
+Game 46: 2 blue, 1 green, 1 red; 1 blue, 6 green, 1 red; 2 blue, 1 red, 1 green; 5 green
+Game 47: 1 blue, 1 red; 14 red; 3 green, 2 blue, 17 red; 4 green
+Game 48: 1 red, 11 green, 2 blue; 1 red, 11 green, 6 blue; 13 green, 1 blue, 3 red; 3 green, 4 red, 6 blue; 12 green, 5 blue, 1 red; 2 red, 4 green, 4 blue
+Game 49: 5 blue, 3 green; 2 green, 8 blue; 5 blue; 4 green, 5 blue, 1 red; 4 green, 7 blue; 1 green, 3 blue
+Game 50: 3 red, 5 green, 2 blue; 9 green, 7 red, 4 blue; 3 blue, 6 red, 13 green; 6 blue, 8 red, 9 green
+Game 51: 2 green, 11 red, 7 blue; 5 blue, 13 red; 1 green, 2 blue, 3 red; 6 blue, 8 red; 11 red, 2 green, 4 blue
+Game 52: 15 blue, 1 green, 4 red; 4 green, 10 blue, 2 red; 6 red, 18 blue, 1 green
+Game 53: 2 red, 10 green, 6 blue; 4 green, 3 blue, 3 red; 17 blue, 19 green, 5 red; 6 blue, 6 green, 9 red; 5 blue, 17 green, 7 red
+Game 54: 9 blue, 8 red, 6 green; 6 red, 8 green; 1 green, 6 blue, 1 red; 5 red, 4 green, 9 blue; 5 blue, 2 green, 5 red
+Game 55: 8 blue, 8 red, 10 green; 3 red, 4 green, 9 blue; 4 red, 3 green, 7 blue
+Game 56: 3 red, 6 green, 1 blue; 5 green, 1 blue, 1 red; 1 red, 2 green; 10 green
+Game 57: 1 green, 4 blue, 12 red; 17 red, 7 blue, 10 green; 17 red, 5 blue, 3 green
+Game 58: 1 red, 5 green, 14 blue; 5 green, 6 red, 7 blue; 4 blue, 8 green; 3 red, 9 green, 7 blue; 8 blue, 8 green, 6 red; 8 green, 7 blue, 5 red
+Game 59: 3 green, 5 red; 2 red, 13 green, 1 blue; 19 green, 1 red, 1 blue; 19 green, 1 blue; 18 green, 1 blue, 5 red; 6 red, 9 green
+Game 60: 5 red, 1 green, 6 blue; 8 red, 6 blue, 14 green; 8 green, 8 red, 3 blue; 2 blue, 5 green, 3 red; 4 blue, 1 red, 14 green
+Game 61: 7 red, 4 blue, 2 green; 2 green, 8 red, 9 blue; 5 blue, 2 green, 8 red; 8 red, 1 green, 8 blue
+Game 62: 6 red, 3 blue; 1 blue, 2 red, 2 green; 3 red, 1 blue
+Game 63: 2 red, 1 blue, 2 green; 1 blue, 1 green; 2 green, 4 red; 3 green, 2 red; 2 green
+Game 64: 5 green, 6 blue, 7 red; 2 red, 5 green, 8 blue; 7 green, 9 blue, 1 red; 4 green, 5 blue; 19 blue, 5 green, 13 red
+Game 65: 3 red, 1 blue, 4 green; 5 green, 3 blue; 9 green, 1 red, 10 blue
+Game 66: 6 red, 13 green, 2 blue; 2 blue, 5 red, 9 green; 18 red; 2 green, 1 blue, 1 red; 19 red, 10 green; 1 blue, 15 green, 13 red
+Game 67: 8 blue, 3 red; 1 red, 12 green, 7 blue; 4 red, 6 blue, 5 green; 11 green, 10 blue, 7 red; 5 red, 9 green, 14 blue
+Game 68: 1 red, 3 green; 10 blue, 1 red, 3 green; 1 green, 17 blue; 16 blue; 6 blue
+Game 69: 11 green, 5 blue, 8 red; 2 red, 5 green, 1 blue; 10 green, 2 blue; 11 green, 7 red, 4 blue
+Game 70: 2 green, 1 blue, 13 red; 16 green, 20 red, 4 blue; 10 red
+Game 71: 10 blue, 6 green, 7 red; 5 red, 5 green, 2 blue; 7 green, 4 red, 5 blue; 1 red, 8 blue; 5 red, 1 blue, 8 green; 5 blue, 1 red, 5 green
+Game 72: 2 red, 4 green; 2 green, 2 red, 1 blue; 3 blue, 3 green, 2 red; 2 green
+Game 73: 5 red, 19 blue; 12 blue, 4 green, 16 red; 14 red, 11 blue, 1 green
+Game 74: 2 red, 1 green, 9 blue; 5 blue, 1 green, 2 red; 2 green, 1 red, 13 blue; 2 green, 1 red, 3 blue
+Game 75: 7 blue, 1 red, 18 green; 17 green, 8 red, 13 blue; 15 blue, 4 red
+Game 76: 1 green, 12 red, 13 blue; 5 green, 11 blue, 12 red; 10 red, 1 green; 10 red, 2 blue; 5 red, 2 green; 2 green, 17 blue, 3 red
+Game 77: 2 blue, 1 red, 1 green; 7 red; 7 red, 3 blue, 2 green; 10 green, 1 red; 3 red, 7 blue, 6 green
+Game 78: 10 red, 2 blue, 2 green; 1 blue, 6 red, 4 green; 12 red, 8 green; 6 green, 8 red, 7 blue; 11 green, 5 blue, 6 red
+Game 79: 7 green, 5 red; 6 blue, 2 green, 15 red; 9 blue, 2 red, 12 green; 1 blue, 4 red, 10 green; 4 blue, 12 green, 11 red; 5 green, 3 red, 5 blue
+Game 80: 1 green, 13 blue, 2 red; 2 red, 1 green, 13 blue; 7 blue, 8 red
+Game 81: 1 green, 2 red, 11 blue; 5 red, 3 blue; 1 green, 1 red; 14 red, 1 green
+Game 82: 12 red, 3 blue, 8 green; 15 red, 9 blue, 8 green; 6 blue, 13 red, 8 green
+Game 83: 4 blue, 6 green, 3 red; 7 red, 2 blue, 9 green; 6 green, 3 red
+Game 84: 4 green; 3 red, 3 blue; 4 red, 1 blue, 2 green; 1 red, 5 green, 5 blue; 1 red, 5 blue, 3 green
+Game 85: 3 red, 4 blue, 15 green; 9 green; 2 red, 4 blue, 6 green; 1 red, 4 green, 7 blue; 3 red, 10 green, 9 blue; 1 red, 13 green, 3 blue
+Game 86: 8 red, 6 blue; 3 blue, 3 green, 15 red; 12 red, 6 green, 13 blue; 15 red, 6 green, 10 blue
+Game 87: 4 red, 4 blue; 6 red, 2 blue; 5 blue, 3 green; 4 blue, 2 red
+Game 88: 4 blue, 7 green; 2 blue, 7 green; 6 green, 4 blue; 1 red, 1 blue, 2 green; 11 green, 3 blue
+Game 89: 1 blue, 12 green, 11 red; 3 red, 7 blue, 1 green; 7 green, 8 red; 6 blue, 2 green, 3 red; 7 red, 8 green; 11 blue, 5 red, 12 green
+Game 90: 1 green, 12 red, 17 blue; 14 red, 17 blue, 9 green; 6 green, 9 red, 11 blue
+Game 91: 3 green, 14 blue; 2 blue, 2 green, 6 red; 1 red, 11 blue, 1 green; 3 green, 4 red, 20 blue; 6 red, 2 green, 3 blue; 10 blue, 12 red
+Game 92: 6 blue, 7 red; 2 blue, 4 red, 1 green; 4 red, 1 green, 3 blue; 2 red, 5 blue; 8 red, 6 blue; 1 green, 2 blue, 1 red
+Game 93: 4 blue, 1 green, 4 red; 8 red, 4 green, 4 blue; 2 blue, 9 red; 1 blue, 4 red; 4 blue, 2 green, 11 red
+Game 94: 5 blue, 1 green, 7 red; 1 green, 11 blue, 1 red; 1 green, 15 blue, 4 red
+Game 95: 1 red, 3 blue; 1 red, 1 green, 8 blue; 3 red, 1 green, 3 blue; 3 red, 6 blue; 6 blue
+Game 96: 4 green, 1 blue; 7 green, 3 red; 2 blue, 9 red, 16 green; 3 blue, 4 red, 11 green
+Game 97: 6 green, 8 blue; 1 blue, 1 green; 3 green, 4 blue; 8 blue, 5 green, 2 red
+Game 98: 18 blue, 6 green; 11 green, 3 blue, 7 red; 18 blue, 3 red, 7 green; 5 red, 5 green; 8 blue, 2 green, 11 red
+Game 99: 3 red, 2 green, 3 blue; 1 red, 4 green, 1 blue; 2 green, 18 red; 15 red, 1 blue; 2 blue, 9 red, 2 green; 17 red, 3 blue, 4 green
+Game 100: 9 blue, 8 red, 16 green; 3 red, 7 green, 8 blue; 1 green, 3 red, 12 blue; 3 green, 14 blue
diff --git a/data/.keep b/data/day03.txt
similarity index 100%
rename from data/.keep
rename to data/day03.txt
diff --git a/data/day04.txt b/data/day04.txt
new file mode 100644
index 0000000..4c0c0ea
--- /dev/null
+++ b/data/day04.txt
@@ -0,0 +1,223 @@
+Card 1: 5 37 16 3 56 11 23 72 7 8 | 3 79 35 45 72 69 15 14 48 88 96 37 11 75 83 56 23 7 16 50 21 91 32 97 17
+Card 2: 1 45 93 96 65 88 78 15 27 26 | 5 84 62 63 45 61 1 80 88 77 40 51 73 21 32 98 74 59 97 9 15 71 25 43 23
+Card 3: 9 99 34 44 37 16 67 43 41 83 | 43 41 5 69 90 50 34 94 86 59 98 16 99 28 44 37 47 57 7 14 83 67 76 9 77
+Card 4: 45 99 64 82 57 9 56 17 78 7 | 75 56 30 88 64 1 98 27 9 57 7 6 77 44 17 78 82 99 16 91 76 94 63 87 45
+Card 5: 76 80 42 88 26 56 79 63 6 37 | 16 4 40 34 46 76 67 69 1 54 5 55 59 24 78 29 26 9 51 44 92 41 63 88 65
+Card 6: 59 23 88 38 49 16 24 18 22 89 | 52 25 88 27 23 79 22 84 72 80 39 17 49 96 56 60 44 45 16 63 78 38 19 5 43
+Card 7: 81 1 37 6 20 76 3 31 93 83 | 74 32 25 76 43 87 52 93 47 85 83 31 17 72 6 99 1 36 20 81 3 69 78 44 37
+Card 8: 74 73 65 29 66 47 43 11 24 38 | 5 3 1 88 29 11 49 67 47 33 31 61 63 75 84 35 18 71 66 92 81 97 8 9 85
+Card 9: 67 68 8 74 17 11 28 47 96 2 | 85 7 37 33 15 18 91 96 4 67 16 47 28 26 80 52 17 97 68 8 11 79 2 46 74
+Card 10: 91 22 85 35 47 26 99 39 72 38 | 5 7 12 14 62 93 61 56 82 4 1 51 86 36 43 29 50 75 68 25 98 77 74 64 24
+Card 11: 4 53 44 83 23 84 40 55 69 82 | 24 48 11 37 60 76 41 29 58 39 45 88 95 67 49 28 36 35 86 33 18 63 51 19 93
+Card 12: 40 45 87 58 72 59 89 55 20 91 | 7 62 2 91 59 78 4 44 25 24 57 94 79 75 51 54 55 90 83 30 68 47 3 69 26
+Card 13: 92 58 35 96 84 62 31 65 95 5 | 22 52 84 98 62 31 75 7 12 78 51 91 37 58 46 85 21 61 95 49 36 5 79 92 4
+Card 14: 75 37 41 53 12 77 97 6 54 29 | 52 65 46 94 20 6 76 75 70 83 29 93 64 1 12 58 89 49 26 16 82 85 74 61 41
+Card 15: 20 88 22 99 28 87 16 78 70 71 | 20 89 56 27 61 32 53 22 78 3 54 28 70 64 33 24 23 17 5 47 55 16 21 88 9
+Card 16: 42 17 35 68 4 78 73 15 88 61 | 42 88 20 57 40 8 71 92 78 45 3 15 17 67 52 43 84 68 4 18 53 79 6 35 24
+Card 17: 19 25 13 51 36 71 56 65 24 50 | 13 82 73 37 83 78 48 88 87 59 97 75 18 53 44 17 84 34 79 95 69 66 76 28 57
+Card 18: 80 99 40 59 75 82 25 70 87 92 | 90 32 27 30 95 33 12 31 78 75 26 44 87 83 39 81 55 43 76 22 61 25 99 69 59
+Card 19: 88 78 95 67 22 4 50 39 58 72 | 74 6 10 21 77 81 53 86 71 56 37 48 23 83 87 55 80 34 89 16 65 8 28 92 97
+Card 20: 54 40 10 45 26 75 88 67 60 3 | 59 69 71 36 95 53 76 80 68 25 96 61 39 65 13 6 49 46 92 28 20 27 7 83 44
+Card 21: 70 48 22 94 63 45 25 85 79 24 | 9 4 82 74 14 65 23 20 10 50 48 81 92 16 27 47 60 22 59 55 2 15 62 41 38
+Card 22: 21 55 81 79 16 64 96 39 56 72 | 28 67 20 18 3 25 29 46 48 83 14 5 64 62 8 45 32 89 85 80 2 55 65 9 61
+Card 23: 17 53 27 13 18 58 81 31 82 35 | 54 78 6 49 75 52 4 19 68 94 80 88 99 89 60 5 83 96 33 23 95 77 27 57 21
+Card 24: 1 12 33 55 68 89 91 43 73 16 | 79 93 14 84 42 80 37 86 44 90 39 81 26 72 46 35 59 28 6 76 19 58 95 7 92
+Card 25: 2 90 83 88 35 17 95 5 9 72 | 72 37 53 51 95 26 16 88 5 66 76 2 84 4 15 22 93 47 6 82 28 9 90 83 23
+Card 26: 63 15 58 95 96 67 27 48 97 40 | 74 96 18 57 14 54 78 40 76 39 10 27 8 87 15 26 66 63 56 49 89 97 95 38 13
+Card 27: 34 21 92 88 66 44 63 2 96 81 | 44 26 88 96 34 51 73 74 72 2 54 60 63 79 62 66 58 70 81 16 7 98 21 92 10
+Card 28: 73 23 8 50 57 31 9 76 89 87 | 76 50 81 44 57 8 18 89 99 83 78 64 72 47 24 14 2 87 56 10 31 13 96 74 68
+Card 29: 52 25 92 30 12 95 38 77 51 36 | 5 7 87 85 70 33 57 10 50 44 61 39 96 65 93 60 79 94 43 52 37 54 6 32 62
+Card 30: 96 10 11 51 58 20 70 91 80 85 | 24 96 98 91 51 11 57 85 95 20 84 80 10 62 6 5 70 34 58 29 42 40 59 55 32
+Card 31: 55 36 29 98 89 58 82 93 94 22 | 9 3 93 56 97 41 15 94 63 13 42 73 55 20 18 98 89 22 77 45 53 12 44 29 36
+Card 32: 92 85 9 6 65 87 59 12 71 55 | 85 96 87 36 93 92 55 88 74 60 71 6 3 65 82 9 94 19 84 59 12 98 28 37 18
+Card 33: 90 3 61 94 8 12 62 77 60 14 | 96 62 81 59 3 8 60 7 90 61 23 12 70 5 51 99 71 14 58 63 94 85 50 57 77
+Card 34: 20 4 44 50 53 19 88 29 68 56 | 9 44 22 56 53 4 50 40 88 29 80 5 1 30 19 20 49 68 63 47 28 92 93 2 83
+Card 35: 26 11 96 48 72 39 19 10 12 70 | 14 56 84 85 30 67 29 90 2 52 20 83 93 73 27 79 82 78 63 3 50 43 6 15 32
+Card 36: 40 77 87 9 24 54 71 97 76 32 | 8 93 19 12 66 97 75 9 76 1 71 11 32 15 54 51 83 50 87 72 24 7 77 47 5
+Card 37: 79 95 36 38 99 60 29 58 88 81 | 38 60 95 50 22 10 87 59 99 88 67 89 15 39 13 12 44 51 34 86 65 90 2 24 58
+Card 38: 33 8 40 69 4 57 79 56 93 9 | 48 11 64 83 95 19 70 36 99 16 30 91 18 4 12 43 38 1 41 44 17 72 98 2 22
+Card 39: 75 80 39 25 90 11 20 46 99 17 | 83 74 29 75 61 33 95 51 80 13 76 46 39 8 44 47 49 6 17 22 2 10 85 66 62
+Card 40: 76 94 24 53 72 92 28 10 34 39 | 85 69 8 81 48 44 27 42 73 83 25 74 28 66 41 98 95 39 52 82 18 67 55 1 26
+Card 41: 92 97 13 88 24 17 54 80 75 79 | 14 41 81 43 39 6 85 56 10 88 27 86 58 7 80 98 97 61 75 93 62 26 59 73 91
+Card 42: 15 42 98 99 10 40 58 74 11 97 | 53 52 57 74 25 36 42 86 97 88 43 15 56 99 83 24 19 60 61 10 68 5 18 98 3
+Card 43: 14 74 56 87 96 66 94 90 40 93 | 10 87 93 57 98 15 36 17 70 12 1 11 33 32 84 65 41 74 83 25 63 77 56 30 72
+Card 44: 24 21 66 99 96 41 84 97 75 78 | 20 78 22 89 71 6 60 35 58 36 18 8 39 4 40 81 34 32 77 26 14 42 53 48 13
+Card 45: 36 15 61 12 68 95 60 90 65 84 | 74 20 90 4 37 11 53 25 34 59 15 45 84 91 58 63 7 27 97 93 73 3 31 65 30
+Card 46: 72 54 37 45 89 8 67 85 39 62 | 69 57 83 24 93 54 33 3 17 13 8 51 98 7 48 11 28 41 19 38 40 60 62 34 84
+Card 47: 29 2 51 82 16 25 46 50 28 6 | 42 24 1 43 87 36 94 74 21 98 15 83 37 50 10 57 62 17 96 33 40 73 93 39 59
+Card 48: 80 77 65 41 73 5 88 37 16 47 | 79 48 55 83 93 62 61 95 66 26 7 32 33 21 14 3 43 36 90 44 15 11 37 4 71
+Card 49: 4 33 50 26 90 86 63 6 81 42 | 28 14 2 29 22 44 24 36 53 54 17 45 78 68 60 93 31 59 85 57 3 16 64 41 84
+Card 50: 65 54 84 16 46 57 47 6 85 81 | 6 69 63 3 91 95 15 34 71 76 81 24 64 94 57 22 19 59 99 1 54 83 65 16 88
+Card 51: 83 48 81 82 55 92 25 76 39 56 | 35 81 96 94 82 25 85 11 39 55 56 76 59 62 84 48 58 37 78 2 27 92 83 69 73
+Card 52: 47 56 99 64 59 13 25 60 81 93 | 61 19 25 60 41 28 67 49 47 13 36 5 56 81 66 23 52 30 59 99 39 6 93 84 64
+Card 53: 59 56 12 96 92 49 1 66 20 2 | 65 66 96 92 56 20 29 59 27 1 97 17 54 53 94 82 75 39 7 34 2 60 49 12 93
+Card 54: 4 29 30 48 99 56 60 27 3 95 | 26 17 59 35 73 66 58 57 2 64 76 67 34 65 10 12 6 53 97 63 19 20 70 86 11
+Card 55: 84 70 37 64 2 43 91 69 5 93 | 5 53 37 46 25 16 45 70 84 34 91 20 3 62 55 64 10 43 94 93 69 42 2 90 40
+Card 56: 57 36 17 21 72 9 39 77 52 53 | 55 47 59 52 85 41 24 74 81 53 42 6 58 51 17 34 54 72 73 2 70 67 10 71 79
+Card 57: 75 15 56 65 21 30 43 83 90 59 | 85 9 83 61 70 69 86 51 47 32 96 23 16 7 67 72 99 13 12 93 91 33 3 48 2
+Card 58: 77 49 71 63 66 72 97 87 24 95 | 4 12 97 98 24 46 72 14 23 71 87 60 89 73 82 20 9 49 27 85 95 75 77 79 8
+Card 59: 81 29 18 22 70 93 59 58 90 31 | 19 90 76 62 15 78 71 52 75 44 4 88 61 73 10 14 25 27 94 50 77 66 89 55 63
+Card 60: 97 95 5 56 63 81 94 7 16 17 | 29 68 83 4 10 69 79 89 47 30 97 58 85 44 14 32 50 78 99 81 52 6 46 71 51
+Card 61: 99 45 17 68 39 48 25 20 38 55 | 23 95 90 64 9 8 71 89 1 31 42 50 74 77 49 33 30 92 94 81 6 61 36 96 68
+Card 62: 64 96 55 52 56 74 28 26 57 27 | 11 33 29 40 70 90 4 64 68 39 35 18 42 85 58 83 23 52 48 6 88 13 74 41 69
+Card 63: 36 80 16 61 89 50 11 2 57 96 | 96 13 35 91 62 81 58 90 55 57 99 73 32 76 61 94 60 89 83 27 48 16 70 86 42
+Card 64: 99 33 85 46 90 54 11 61 76 27 | 43 6 90 87 59 71 74 4 41 82 10 64 97 17 75 29 95 63 91 7 47 12 77 25 32
+Card 65: 30 99 44 66 5 89 8 58 16 78 | 79 36 80 3 24 81 48 22 29 26 33 19 57 6 28 95 86 94 49 51 98 10 55 8 18
+Card 66: 98 95 22 68 25 89 6 88 90 35 | 88 18 75 81 65 60 39 77 47 53 85 33 40 44 8 27 66 82 48 63 64 97 24 49 29
+Card 67: 63 96 55 9 23 17 42 66 12 56 | 14 76 60 70 78 58 42 52 25 18 94 86 31 79 68 57 73 47 51 89 32 12 63 29 28
+Card 68: 75 57 84 29 91 22 36 69 25 32 | 78 28 96 12 42 1 44 54 60 73 48 16 41 23 37 83 31 64 21 92 86 79 33 24 14
+Card 69: 51 7 82 59 78 34 39 42 19 24 | 50 9 41 82 94 46 25 31 32 88 92 75 55 63 69 56 98 65 86 93 79 54 10 43 28
+Card 70: 4 74 46 53 28 9 14 63 73 21 | 2 36 71 91 42 66 7 77 84 86 49 94 16 83 82 96 25 70 58 53 78 29 23 17 13
+Card 71: 21 39 77 83 14 12 5 88 97 47 | 43 38 57 91 3 81 90 30 25 33 84 80 58 10 27 20 28 73 6 54 13 65 31 70 36
+Card 72: 68 33 8 24 59 58 65 57 36 38 | 2 95 17 38 58 24 45 31 36 33 59 83 32 6 37 11 67 78 88 48 57 68 80 26 8
+Card 73: 56 6 28 51 83 64 35 17 60 87 | 51 93 56 43 30 17 67 61 35 97 88 83 64 24 40 6 68 84 87 75 46 95 60 28 89
+Card 74: 82 44 97 85 88 42 61 56 1 40 | 56 12 66 67 44 22 97 40 29 43 24 1 50 42 78 79 7 80 82 88 61 85 89 38 41
+Card 75: 83 90 15 43 93 50 8 37 17 89 | 12 89 90 50 91 83 15 37 94 7 10 88 31 14 17 19 43 3 59 71 46 93 63 52 8
+Card 76: 14 38 56 48 40 2 43 42 44 75 | 8 55 65 79 87 30 95 89 3 39 22 6 99 74 88 32 98 91 9 70 59 92 78 66 24
+Card 77: 36 27 48 94 84 77 75 6 70 22 | 75 48 99 5 45 87 63 6 49 31 94 22 29 37 27 77 50 36 23 80 10 84 70 97 93
+Card 78: 95 18 51 10 43 90 23 99 56 68 | 5 94 49 92 22 87 47 36 62 30 7 32 12 64 31 25 41 73 39 34 14 27 80 50 91
+Card 79: 17 75 70 51 40 42 84 30 38 15 | 17 86 42 15 75 88 70 84 29 51 39 4 59 65 80 1 40 74 92 46 38 71 64 61 30
+Card 80: 36 16 59 77 82 72 87 98 99 32 | 76 9 70 12 97 75 20 30 10 54 74 44 93 22 4 43 32 33 18 17 82 29 28 55 21
+Card 81: 97 82 92 35 20 71 15 78 98 6 | 82 71 43 68 70 20 31 55 90 67 19 24 81 60 15 8 88 18 27 76 63 78 47 91 22
+Card 82: 42 40 60 2 95 56 10 94 14 99 | 75 89 27 40 35 33 42 79 38 14 94 71 25 85 95 56 82 92 60 99 58 65 2 13 57
+Card 83: 60 31 59 4 63 39 23 73 56 24 | 31 23 56 19 59 4 64 42 85 1 34 60 72 35 24 55 16 37 78 52 7 39 2 73 63
+Card 84: 13 89 46 61 4 86 94 47 22 63 | 79 7 67 19 72 77 54 15 29 92 65 17 75 70 91 78 26 63 53 21 58 51 43 23 39
+Card 85: 38 1 35 22 60 19 24 82 99 43 | 21 82 99 56 60 64 44 24 1 83 23 27 40 35 55 47 43 87 85 12 22 39 4 25 63
+Card 86: 32 43 80 27 57 48 65 11 67 90 | 22 67 28 23 36 53 80 39 32 45 43 11 95 2 57 26 40 99 33 27 82 50 48 84 91
+Card 87: 44 76 92 13 51 25 35 15 81 61 | 76 44 16 1 41 35 6 84 67 13 5 30 51 34 8 7 55 15 73 90 60 21 50 25 81
+Card 88: 40 83 37 66 78 56 26 32 38 11 | 82 58 33 2 24 51 79 56 44 29 90 94 11 40 12 83 37 16 66 96 72 10 34 77 65
+Card 89: 75 60 87 69 50 48 91 72 66 64 | 47 30 61 11 17 88 62 71 3 9 67 93 46 13 21 86 23 18 37 4 89 92 51 54 52
+Card 90: 44 58 88 53 37 43 33 74 50 15 | 21 76 69 8 87 20 44 74 84 31 52 63 23 91 29 82 42 57 83 5 11 56 34 97 85
+Card 91: 61 41 52 39 83 93 33 67 11 6 | 49 13 76 15 98 53 62 19 16 14 1 24 66 27 58 79 23 54 77 63 46 25 57 33 50
+Card 92: 10 29 99 80 36 48 74 88 28 5 | 86 22 93 19 24 29 87 92 58 96 10 68 72 75 35 60 26 37 67 79 3 62 63 18 20
+Card 93: 28 31 69 88 94 39 36 99 1 90 | 5 38 46 96 53 26 37 66 65 16 31 79 8 92 11 68 93 27 73 33 51 17 86 1 70
+Card 94: 81 83 18 7 5 12 59 11 41 26 | 2 16 20 74 65 55 23 88 21 99 35 49 12 33 70 25 91 36 50 6 51 15 45 13 34
+Card 95: 14 43 76 25 18 95 15 22 66 83 | 4 45 57 46 33 61 52 17 98 53 37 89 23 27 67 12 86 81 68 9 44 87 24 1 75
+Card 96: 82 98 24 1 85 50 20 57 60 93 | 57 92 59 85 81 20 89 50 28 60 64 38 94 71 61 21 93 98 24 82 58 65 42 76 1
+Card 97: 20 59 25 39 48 12 85 17 44 65 | 56 49 89 58 83 95 25 2 93 26 42 14 37 77 10 11 40 90 86 59 3 61 87 62 16
+Card 98: 56 9 13 23 47 31 54 95 17 58 | 30 59 65 52 23 85 72 75 19 36 95 41 54 49 42 83 64 15 80 31 16 9 27 20 29
+Card 99: 38 82 89 49 24 20 65 87 42 31 | 50 64 92 85 1 14 29 61 18 96 53 10 99 17 15 97 88 74 69 12 72 40 66 54 86
+Card 100: 16 78 53 13 62 18 9 63 61 94 | 16 10 73 6 36 13 24 63 94 57 5 8 18 52 67 20 62 68 29 78 61 69 53 9 38
+Card 101: 20 53 48 71 35 65 26 31 89 44 | 42 10 97 20 1 91 29 96 76 21 78 27 46 3 18 25 68 48 90 41 37 65 28 88 17
+Card 102: 63 31 48 76 34 46 44 99 39 35 | 50 56 53 38 46 39 99 73 61 32 18 65 63 31 74 97 48 41 62 35 44 26 4 34 76
+Card 103: 31 61 96 44 3 32 51 10 74 95 | 60 15 29 39 19 20 68 28 83 40 42 52 50 41 10 36 7 71 11 18 27 16 75 93 99
+Card 104: 38 98 96 64 66 93 53 95 87 73 | 16 45 77 87 92 69 99 3 33 36 31 89 63 93 98 4 83 10 13 51 59 64 37 47 85
+Card 105: 24 86 51 27 23 99 25 97 82 72 | 20 27 7 60 71 94 26 33 52 41 6 48 36 22 46 51 44 64 63 3 50 86 47 12 53
+Card 106: 71 75 52 24 61 13 45 59 30 1 | 6 96 7 20 65 55 95 57 16 29 22 18 87 56 53 81 51 67 66 23 50 11 91 44 72
+Card 107: 47 31 1 45 94 76 35 77 41 96 | 9 47 12 59 89 83 14 5 38 52 39 55 50 90 97 75 87 68 37 26 22 46 27 10 15
+Card 108: 90 35 81 74 7 82 11 79 80 33 | 84 74 82 15 34 26 19 83 25 95 90 81 79 97 71 99 22 35 8 41 65 11 7 55 62
+Card 109: 80 18 68 10 31 61 64 98 84 7 | 81 54 26 20 52 94 68 88 19 15 87 40 12 91 10 61 1 56 45 85 66 25 82 57 92
+Card 110: 79 75 95 63 62 32 78 67 88 3 | 45 80 76 94 10 82 55 26 24 41 65 78 5 47 75 91 38 7 37 88 2 52 97 50 99
+Card 111: 69 4 78 87 15 59 22 90 86 40 | 98 4 27 21 9 71 40 5 67 69 94 38 87 92 91 47 54 17 65 43 30 1 51 72 70
+Card 112: 30 93 66 43 89 12 32 46 1 76 | 79 63 16 15 95 88 44 7 8 59 32 74 19 97 45 80 61 30 34 68 70 1 3 28 55
+Card 113: 36 8 6 21 92 96 67 98 59 34 | 73 44 85 41 11 47 50 53 40 27 90 75 20 79 32 69 3 74 99 78 66 93 56 14 82
+Card 114: 74 31 59 5 70 12 95 33 97 46 | 53 92 99 74 94 78 86 25 73 10 17 58 21 37 2 71 79 90 77 76 50 93 87 52 4
+Card 115: 38 75 68 26 66 52 13 17 76 33 | 73 60 35 27 91 15 39 41 63 36 4 19 61 5 6 3 70 55 24 11 23 71 67 29 51
+Card 116: 73 26 82 27 63 88 34 91 78 59 | 35 56 58 68 71 14 4 94 33 75 72 6 67 55 80 57 28 11 65 84 66 54 3 95 20
+Card 117: 66 2 31 29 64 73 92 10 33 83 | 43 42 55 20 61 51 57 58 94 37 14 15 84 69 41 28 11 10 67 34 65 91 78 18 1
+Card 118: 63 82 19 38 31 57 93 79 32 56 | 1 43 81 72 32 24 79 84 45 94 38 92 56 5 42 70 63 91 93 71 57 96 51 31 83
+Card 119: 34 48 60 44 4 64 3 35 66 30 | 47 3 60 76 67 97 31 1 35 55 84 65 81 52 45 30 50 7 34 71 14 74 89 11 66
+Card 120: 86 93 50 94 55 11 83 84 61 15 | 11 42 14 17 63 36 75 49 86 15 55 94 84 61 50 48 80 6 83 39 23 93 67 87 46
+Card 121: 92 85 58 71 34 94 60 49 14 17 | 34 74 61 77 89 50 99 49 94 60 68 83 71 27 17 56 46 63 76 26 20 70 41 85 39
+Card 122: 99 2 97 77 34 42 35 16 13 33 | 6 42 60 26 9 13 98 30 94 97 33 40 58 91 32 46 47 68 78 34 77 35 93 22 39
+Card 123: 34 16 84 71 29 13 53 57 79 43 | 24 37 74 85 35 7 51 44 97 29 9 70 67 45 61 15 65 77 86 20 90 66 73 11 58
+Card 124: 39 83 88 46 71 8 66 68 67 52 | 75 66 93 8 20 67 3 73 34 39 71 83 45 15 58 55 31 38 69 29 46 40 48 42 68
+Card 125: 73 16 48 77 94 75 79 40 39 22 | 98 37 36 63 10 84 52 53 94 82 46 17 73 2 88 42 16 33 64 62 95 22 77 43 55
+Card 126: 10 84 50 23 39 71 86 74 38 53 | 71 16 38 23 28 86 97 53 43 69 10 84 5 72 4 96 15 37 74 50 83 22 39 49 12
+Card 127: 92 69 94 70 14 35 44 58 3 96 | 18 89 21 14 2 17 76 50 29 72 87 56 39 25 33 37 68 60 55 66 53 80 62 26 38
+Card 128: 58 45 46 29 74 94 61 1 18 72 | 20 76 24 41 14 86 53 85 90 80 83 68 48 10 49 25 75 89 92 93 23 37 38 96 33
+Card 129: 9 19 94 34 58 89 13 1 47 37 | 53 21 17 73 50 79 24 25 2 92 47 75 8 30 98 12 85 80 62 65 86 84 40 49 67
+Card 130: 66 46 68 96 19 2 21 32 63 13 | 82 68 63 21 25 43 44 91 40 97 20 75 2 46 80 83 5 59 66 56 45 93 98 95 47
+Card 131: 13 20 75 52 6 26 90 36 3 82 | 58 98 40 5 12 82 56 64 16 9 17 74 77 76 85 31 53 28 67 4 18 97 47 57 43
+Card 132: 90 86 97 51 21 60 45 8 94 91 | 97 70 38 89 73 14 30 10 39 18 91 8 55 12 86 45 37 54 9 5 23 33 29 51 71
+Card 133: 18 22 20 1 76 64 59 26 73 15 | 75 54 45 77 30 51 32 6 78 11 70 40 22 26 59 79 2 50 94 24 85 29 31 25 73
+Card 134: 61 72 44 50 47 22 78 62 21 32 | 51 61 59 81 67 54 58 55 87 52 85 62 48 34 35 68 74 82 91 11 84 80 98 1 94
+Card 135: 81 98 77 10 91 59 49 66 55 79 | 8 30 40 46 53 50 41 18 66 76 83 72 34 1 49 11 87 9 94 51 79 7 63 90 37
+Card 136: 96 28 21 15 42 65 91 43 82 60 | 95 23 34 51 29 58 31 89 4 16 36 20 5 61 33 47 59 75 80 55 9 67 28 74 45
+Card 137: 53 27 50 59 83 75 48 25 90 89 | 93 87 31 17 35 1 13 24 91 16 90 52 94 99 60 42 4 10 19 32 7 69 80 38 71
+Card 138: 40 8 61 37 83 55 88 50 77 5 | 99 73 66 63 90 78 24 3 29 62 35 75 92 6 39 42 19 95 13 80 25 64 54 49 68
+Card 139: 24 87 36 5 58 46 84 4 80 19 | 31 10 49 87 53 17 67 37 44 80 19 43 46 86 32 4 15 24 58 64 85 66 5 81 82
+Card 140: 92 93 56 21 97 86 5 11 45 3 | 45 21 66 59 56 44 79 16 86 13 8 3 88 71 52 55 54 60 2 37 93 92 97 11 5
+Card 141: 98 73 9 7 74 71 43 63 5 89 | 83 73 44 12 86 97 74 71 43 78 14 98 8 53 16 51 7 20 88 89 93 37 46 58 63
+Card 142: 57 96 47 59 56 58 76 52 1 84 | 80 68 6 61 82 24 42 17 86 79 22 65 31 81 27 41 70 33 77 54 49 99 37 66 64
+Card 143: 34 98 19 48 99 54 66 28 26 33 | 99 89 39 44 81 98 71 67 91 47 48 45 54 7 24 55 51 94 33 34 26 66 19 95 28
+Card 144: 82 37 3 29 57 39 34 44 5 70 | 3 6 39 1 2 10 5 82 37 56 29 50 30 48 47 70 58 12 44 9 69 57 88 51 34
+Card 145: 73 65 86 88 99 81 26 70 11 62 | 86 3 14 88 66 11 90 30 67 80 8 79 23 44 2 1 45 13 32 72 31 26 55 64 70
+Card 146: 8 54 27 20 89 28 51 3 19 40 | 13 81 90 98 9 6 93 88 1 82 79 48 14 31 20 58 65 91 78 38 62 7 73 64 52
+Card 147: 70 63 99 58 80 73 38 95 69 90 | 67 82 72 73 70 92 91 63 80 20 4 69 95 64 38 58 50 10 90 99 78 68 49 1 26
+Card 148: 61 41 24 78 96 40 91 23 70 19 | 28 1 16 76 19 95 60 92 82 41 25 87 63 30 91 96 12 70 77 27 23 90 24 72 61
+Card 149: 43 89 27 28 50 39 6 83 69 45 | 12 43 34 39 73 40 66 95 36 96 74 6 72 81 24 25 78 92 42 22 87 86 59 89 97
+Card 150: 9 14 44 72 64 11 95 68 73 75 | 44 14 60 54 97 64 11 4 57 79 40 53 39 2 51 46 75 42 9 37 6 83 80 25 72
+Card 151: 91 12 67 98 83 16 14 62 69 36 | 35 66 73 90 28 36 43 37 69 24 95 85 27 48 39 44 16 62 53 72 15 1 63 19 5
+Card 152: 42 27 33 9 32 99 76 30 3 53 | 42 43 17 41 5 6 47 8 91 66 85 12 31 9 99 76 58 13 90 11 46 53 54 29 30
+Card 153: 51 60 22 62 57 11 16 85 9 3 | 17 52 62 87 97 73 25 34 65 88 72 16 94 3 32 27 96 86 42 91 80 41 95 79 11
+Card 154: 36 13 59 96 52 90 79 6 14 74 | 28 92 63 4 48 85 12 6 13 91 86 76 44 16 93 97 43 54 52 49 60 84 8 75 21
+Card 155: 91 27 43 97 4 68 6 79 5 72 | 22 77 90 15 50 4 52 70 88 85 24 27 12 80 82 81 74 36 45 92 39 78 54 71 5
+Card 156: 80 45 22 79 4 23 21 63 34 37 | 6 99 74 11 62 54 36 63 59 14 37 70 44 25 31 15 97 12 39 2 75 90 4 46 18
+Card 157: 43 37 94 45 96 99 15 33 54 38 | 18 70 62 12 5 7 17 33 24 8 79 15 51 44 87 57 99 4 25 34 74 65 63 13 76
+Card 158: 21 65 8 67 37 97 99 24 16 68 | 51 85 26 80 72 81 57 37 82 93 46 94 68 54 24 32 18 48 1 69 49 29 27 40 39
+Card 159: 3 2 61 25 92 69 30 10 57 78 | 88 46 33 3 52 89 55 4 24 82 9 98 62 66 54 23 28 13 50 68 39 1 15 63 74
+Card 160: 1 28 51 92 96 79 22 97 17 62 | 64 46 44 75 50 43 39 30 37 91 82 11 4 34 27 71 65 40 81 53 38 52 60 2 23
+Card 161: 26 12 82 16 52 15 97 42 2 20 | 68 22 49 59 32 53 10 72 4 92 25 56 84 65 69 75 88 9 37 86 1 78 89 41 99
+Card 162: 3 32 24 52 49 80 10 39 43 72 | 60 39 23 25 56 21 10 12 24 70 32 83 80 43 19 28 34 22 52 72 49 74 3 15 29
+Card 163: 77 57 96 84 68 59 24 92 60 5 | 66 33 57 73 44 92 60 34 39 62 96 80 2 77 91 5 24 51 31 64 68 59 36 84 88
+Card 164: 76 60 92 78 34 44 23 14 22 1 | 92 17 44 32 53 34 54 28 73 93 89 67 84 18 60 72 85 10 26 21 23 78 33 51 79
+Card 165: 66 99 39 27 18 79 96 7 50 44 | 7 96 41 98 78 57 44 8 61 50 79 68 99 38 40 10 66 31 14 18 27 89 70 39 69
+Card 166: 73 42 83 91 88 21 43 16 10 55 | 73 8 28 10 76 16 99 55 97 62 42 65 35 72 83 52 57 50 91 21 37 74 36 88 96
+Card 167: 64 38 97 19 73 72 67 79 94 21 | 21 38 54 73 66 49 29 25 75 19 85 6 64 34 97 13 30 28 79 67 36 72 94 68 82
+Card 168: 16 37 31 29 99 88 54 66 3 57 | 88 31 38 21 11 79 13 9 36 27 78 47 97 74 64 7 42 32 2 50 46 80 87 96 60
+Card 169: 6 18 54 82 21 27 34 62 91 12 | 52 26 12 56 39 21 5 91 89 6 18 34 43 62 40 67 76 83 27 31 92 82 54 45 55
+Card 170: 31 82 50 80 27 16 34 22 38 54 | 80 22 63 31 23 38 34 66 16 82 9 75 64 54 85 50 99 81 92 53 77 30 13 27 35
+Card 171: 44 50 51 70 77 73 55 41 80 60 | 63 60 69 80 25 48 36 56 96 1 88 14 75 30 7 50 40 95 87 51 41 59 11 65 70
+Card 172: 33 60 55 35 38 86 78 56 31 14 | 60 67 83 33 21 40 14 69 38 94 32 54 3 17 49 19 22 86 31 79 73 71 56 75 78
+Card 173: 75 30 84 6 15 21 76 28 66 83 | 98 94 57 58 26 74 90 69 64 66 51 30 28 38 82 21 86 15 75 78 97 9 19 72 56
+Card 174: 49 63 32 42 78 24 55 70 76 95 | 78 90 82 98 50 60 76 3 49 44 74 18 68 32 55 29 72 24 63 99 96 12 70 59 31
+Card 175: 15 69 87 40 61 58 81 77 21 12 | 27 31 77 43 47 85 80 44 21 1 33 3 84 7 54 51 69 40 70 71 12 49 61 22 15
+Card 176: 40 7 45 71 92 88 27 97 58 8 | 2 82 67 15 81 63 16 49 65 89 35 60 79 29 74 43 56 45 95 84 10 32 92 96 64
+Card 177: 8 70 28 81 60 12 64 98 84 72 | 32 58 80 65 90 79 95 31 56 43 82 45 94 21 92 55 89 96 53 54 19 51 6 52 33
+Card 178: 16 59 30 28 62 24 8 6 92 91 | 96 24 30 28 37 42 50 69 67 62 49 84 92 65 95 34 68 17 47 59 2 60 79 53 16
+Card 179: 68 58 26 30 90 16 9 6 44 92 | 97 4 95 64 12 18 52 96 29 67 84 69 91 23 56 24 10 20 98 87 80 79 65 22 48
+Card 180: 30 32 52 1 10 23 62 43 51 79 | 70 72 87 82 3 83 24 73 34 64 75 71 84 89 26 65 27 47 41 39 81 37 36 18 17
+Card 181: 80 2 77 4 29 98 52 21 86 90 | 46 61 34 66 6 57 8 59 32 16 80 89 86 83 26 27 53 29 55 31 92 84 18 56 14
+Card 182: 77 54 92 15 91 12 89 56 45 87 | 82 13 40 26 15 16 44 97 9 52 33 20 36 63 99 57 49 46 19 22 79 3 32 37 73
+Card 183: 41 43 38 48 97 95 69 98 81 80 | 22 93 36 50 23 37 34 9 27 8 35 49 82 71 65 98 39 56 10 5 69 86 16 88 21
+Card 184: 50 96 62 20 87 19 90 13 41 82 | 52 85 38 89 59 30 64 91 74 6 39 60 61 77 97 18 42 49 12 36 55 56 3 75 96
+Card 185: 43 62 42 28 85 36 21 39 59 16 | 63 1 35 52 15 98 65 68 27 61 40 95 74 80 11 83 94 89 47 90 25 72 32 31 23
+Card 186: 48 6 85 22 91 9 76 2 15 21 | 83 44 33 78 24 96 38 43 20 16 59 67 99 86 36 58 80 31 11 14 28 98 5 57 42
+Card 187: 18 71 35 72 10 45 11 4 44 56 | 16 72 23 30 56 73 45 63 99 10 57 88 65 4 12 8 94 71 11 18 44 35 80 74 78
+Card 188: 89 11 73 22 99 41 28 61 66 52 | 98 85 99 64 97 28 71 66 26 58 53 3 92 95 22 67 83 13 51 11 57 79 25 19 89
+Card 189: 61 49 23 38 82 95 62 2 15 67 | 14 2 68 82 61 11 86 65 70 40 38 95 67 80 23 62 27 36 90 55 25 57 35 49 15
+Card 190: 74 47 34 96 42 10 58 71 82 80 | 32 42 68 58 74 6 93 82 50 91 80 33 71 55 47 30 70 43 62 98 75 11 4 96 10
+Card 191: 48 39 13 22 77 86 8 34 71 6 | 44 20 73 16 31 67 66 1 21 2 80 54 49 42 45 35 30 87 83 57 60 4 50 76 26
+Card 192: 70 77 39 63 81 88 7 78 85 44 | 97 81 85 12 96 71 63 84 88 45 9 77 27 78 51 52 82 44 7 10 80 60 70 39 49
+Card 193: 11 62 85 7 5 47 58 68 88 65 | 98 55 47 5 7 85 22 62 82 46 38 59 68 30 26 84 45 40 58 31 81 11 65 93 88
+Card 194: 60 49 75 21 54 34 40 6 39 67 | 84 60 14 34 65 49 7 39 32 54 74 25 40 75 21 72 6 35 5 41 78 20 26 77 67
+Card 195: 55 11 12 81 4 7 97 61 15 58 | 69 29 95 11 12 77 4 30 55 15 44 39 2 89 38 71 51 25 40 6 21 81 58 7 98
+Card 196: 90 78 2 3 77 24 33 45 32 30 | 16 11 39 27 85 34 79 59 6 33 46 21 48 36 58 99 40 74 63 82 96 42 7 95 90
+Card 197: 21 13 3 45 1 33 54 70 23 22 | 23 73 21 34 76 78 4 1 46 11 60 64 42 26 81 13 90 51 2 79 74 45 3 72 84
+Card 198: 44 17 16 71 52 50 11 69 14 86 | 90 70 65 7 91 17 63 81 24 39 69 42 87 57 36 35 74 31 22 80 50 88 13 41 78
+Card 199: 60 13 93 42 74 66 3 89 40 8 | 43 37 38 54 99 36 44 62 1 91 60 52 76 21 20 86 17 97 98 7 79 57 28 48 35
+Card 200: 40 39 37 63 65 8 25 47 85 12 | 62 35 28 68 63 27 98 40 43 17 78 87 41 86 13 61 5 23 4 20 93 31 66 18 49
+Card 201: 41 57 5 59 95 15 18 44 75 28 | 1 33 29 38 76 73 36 17 19 4 52 84 68 32 35 27 92 58 81 78 2 61 97 85 22
+Card 202: 60 80 88 13 96 57 1 58 39 52 | 52 34 58 2 59 50 79 92 63 98 96 36 62 77 37 56 78 4 54 51 9 76 85 21 57
+Card 203: 39 28 57 98 3 73 22 8 23 68 | 44 9 43 17 50 14 97 1 41 76 61 90 20 62 78 5 89 85 64 55 16 72 19 4 37
+Card 204: 99 82 81 86 88 31 92 8 93 94 | 28 74 53 55 76 77 57 94 97 45 41 17 38 36 98 86 39 24 10 42 27 65 73 34 96
+Card 205: 55 7 8 82 24 95 85 99 22 59 | 58 64 84 42 26 59 20 37 49 57 62 15 18 1 32 2 86 69 96 63 47 77 60 19 93
+Card 206: 73 34 51 18 57 42 91 27 84 95 | 6 88 80 82 98 89 36 10 33 78 37 21 45 96 5 93 15 63 62 92 49 94 1 64 85
+Card 207: 83 32 10 94 28 8 61 98 53 48 | 31 78 60 79 87 37 97 34 11 71 66 1 29 74 24 41 22 42 46 85 80 47 17 54 14
+Card 208: 11 17 75 84 85 40 89 23 54 80 | 31 54 85 61 39 79 27 56 62 64 11 80 3 72 14 73 19 48 99 89 15 42 23 9 97
+Card 209: 30 75 20 84 70 26 72 23 9 97 | 5 76 67 41 18 84 36 54 70 65 75 25 82 23 50 9 7 46 33 85 38 11 97 95 40
+Card 210: 76 25 97 64 92 68 60 43 63 53 | 31 1 91 45 39 62 89 50 77 37 38 25 8 28 71 97 49 99 55 9 27 52 64 76 73
+Card 211: 62 52 55 90 57 38 95 65 39 92 | 67 46 95 3 38 18 26 5 75 55 92 41 85 28 84 42 37 73 64 69 33 14 34 94 35
+Card 212: 91 93 76 59 88 48 97 44 96 78 | 22 20 48 74 61 91 69 25 59 44 6 93 42 36 96 76 60 88 37 32 78 97 16 47 89
+Card 213: 79 33 53 91 63 62 42 3 72 25 | 59 69 60 7 82 68 73 97 23 48 39 38 76 71 9 29 37 53 67 92 85 55 15 13 61
+Card 214: 51 20 73 22 11 83 14 71 26 74 | 85 48 41 50 93 70 21 76 2 16 22 95 6 25 20 19 72 58 11 45 83 54 26 73 51
+Card 215: 47 72 51 32 7 13 99 36 17 48 | 22 47 6 36 8 91 35 11 3 42 30 21 38 43 28 64 99 72 75 18 84 13 52 82 55
+Card 216: 34 39 74 27 3 44 62 85 42 87 | 51 59 19 80 33 89 1 79 84 82 85 60 61 56 6 50 77 92 55 21 34 83 38 98 26
+Card 217: 11 33 54 13 67 99 61 86 57 7 | 95 32 57 34 98 33 7 54 71 26 42 73 52 56 13 79 67 78 75 58 9 81 24 41 96
+Card 218: 50 9 20 47 18 95 63 31 75 30 | 73 5 26 92 74 57 77 20 96 32 8 9 88 71 75 28 17 29 81 27 90 49 25 67 87
+Card 219: 5 55 89 78 12 19 47 64 87 81 | 16 66 55 2 13 10 93 88 39 47 22 54 65 59 8 75 99 19 61 43 68 86 67 49 70
+Card 220: 84 11 98 89 83 95 48 71 45 88 | 14 7 33 52 19 30 66 81 37 57 21 8 47 17 72 95 63 59 29 18 27 26 76 91 73
+Card 221: 78 17 79 4 63 65 56 57 22 92 | 48 94 32 37 26 58 64 87 24 95 19 41 12 25 74 93 30 1 66 27 3 43 50 35 11
+Card 222: 74 14 52 95 73 11 55 26 90 78 | 17 21 93 28 90 61 63 50 19 57 91 66 86 79 62 41 3 23 75 15 56 18 92 83 49
+Card 223: 98 82 47 14 2 48 1 50 18 62 | 67 78 16 58 35 87 93 44 77 13 74 34 32 92 88 54 36 61 91 72 9 59 89 73 5
diff --git a/gleam.toml b/gleam.toml
deleted file mode 100644
index 79d3ab7..0000000
--- a/gleam.toml
+++ /dev/null
@@ -1,24 +0,0 @@
-name = "advent_of_code"
-version = "1.0.0"
-
-# Fill out these fields if you intend to generate HTML documentation or publish
-# your project to the Hex package manager.
-#
-# description = ""
-# licences = ["Apache-2.0"]
-# repository = { type = "github", user = "", repo = "" }
-# links = [{ title = "Website", href = "" }]
-#
-# For a full reference of all the available options, you can have a look at
-# https://gleam.run/writing-gleam/gleam-toml/.
-
-[dependencies]
-gleam_stdlib = ">= 0.34.0 and < 2.0.0"
-simplifile = ">= 2.2.0 and < 3.0.0"
-gleam_regexp = ">= 1.0.0 and < 2.0.0"
-gleam_yielder = ">= 1.1.0 and < 2.0.0"
-gleam_otp = ">= 0.14.1 and < 1.0.0"
-argv = ">= 1.0.2 and < 2.0.0"
-
-[dev-dependencies]
-gleeunit = ">= 1.0.0 and < 2.0.0"
diff --git a/manifest.toml b/manifest.toml
deleted file mode 100644
index 3e9655e..0000000
--- a/manifest.toml
+++ /dev/null
@@ -1,23 +0,0 @@
-# This file was generated by Gleam
-# You typically do not need to edit this file
-
-packages = [
- { name = "argv", version = "1.0.2", build_tools = ["gleam"], requirements = [], otp_app = "argv", source = "hex", outer_checksum = "BA1FF0929525DEBA1CE67256E5ADF77A7CDDFE729E3E3F57A5BDCAA031DED09D" },
- { name = "filepath", version = "1.1.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "filepath", source = "hex", outer_checksum = "67A6D15FB39EEB69DD31F8C145BB5A421790581BD6AA14B33D64D5A55DBD6587" },
- { name = "gleam_erlang", version = "0.33.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_erlang", source = "hex", outer_checksum = "A1D26B80F01901B59AABEE3475DD4C18D27D58FA5C897D922FCB9B099749C064" },
- { name = "gleam_otp", version = "0.14.1", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_stdlib"], otp_app = "gleam_otp", source = "hex", outer_checksum = "5A8CE8DBD01C29403390A7BD5C0A63D26F865C83173CF9708E6E827E53159C65" },
- { name = "gleam_regexp", version = "1.0.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_regexp", source = "hex", outer_checksum = "A3655FDD288571E90EE9C4009B719FEF59FA16AFCDF3952A76A125AF23CF1592" },
- { name = "gleam_stdlib", version = "0.45.0", build_tools = ["gleam"], requirements = [], otp_app = "gleam_stdlib", source = "hex", outer_checksum = "206FCE1A76974AECFC55AEBCD0217D59EDE4E408C016E2CFCCC8FF51278F186E" },
- { name = "gleam_yielder", version = "1.1.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_yielder", source = "hex", outer_checksum = "8E4E4ECFA7982859F430C57F549200C7749823C106759F4A19A78AEA6687717A" },
- { name = "gleeunit", version = "1.2.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleeunit", source = "hex", outer_checksum = "F7A7228925D3EE7D0813C922E062BFD6D7E9310F0BEE585D3A42F3307E3CFD13" },
- { name = "simplifile", version = "2.2.0", build_tools = ["gleam"], requirements = ["filepath", "gleam_stdlib"], otp_app = "simplifile", source = "hex", outer_checksum = "0DFABEF7DC7A9E2FF4BB27B108034E60C81BEBFCB7AB816B9E7E18ED4503ACD8" },
-]
-
-[requirements]
-argv = { version = ">= 1.0.2 and < 2.0.0" }
-gleam_otp = { version = ">= 0.14.1 and < 1.0.0" }
-gleam_regexp = { version = ">= 1.0.0 and < 2.0.0" }
-gleam_stdlib = { version = ">= 0.34.0 and < 2.0.0" }
-gleam_yielder = { version = ">= 1.1.0 and < 2.0.0" }
-gleeunit = { version = ">= 1.0.0 and < 2.0.0" }
-simplifile = { version = ">= 2.2.0 and < 3.0.0" }
diff --git a/src/advent_of_code.gleam b/src/advent_of_code.gleam
deleted file mode 100644
index 6e07c20..0000000
--- a/src/advent_of_code.gleam
+++ /dev/null
@@ -1,162 +0,0 @@
-import argv
-import bridge_repair as day07
-import ceres_search as day04
-import disk_fragmenter as day09
-import gleam/int
-import gleam/io
-import gleam/result
-import guard_gallivant as day06
-import historian_hysteria as day01
-import hoof_it as day10
-import mull_it_over as day03
-import print_queue as day05
-import red_nosed_reports as day02
-import resonant_collinearity as day08
-import simplifile.{read}
-
-pub fn main() {
- case argv.load().arguments {
- ["1"] -> {
- result.unwrap(
- result.map(read("data/day1.txt"), fn(data) {
- io.println(
- "[1] Historian Hysteria (Part 1): "
- <> int.to_string(day01.solve_a(data)),
- )
- io.println(
- "[1] Historian Hysteria (Part 2): "
- <> int.to_string(day01.solve_b(data)),
- )
- }),
- Nil,
- )
- }
- ["2"] -> {
- result.unwrap(
- result.map(read("data/day2.txt"), fn(data) {
- io.println(
- "[2] Red Nosed Reports (Part 1): "
- <> int.to_string(day02.solve_a(data)),
- )
- io.println(
- "[2] Red Nosed Reports (Part 2): "
- <> int.to_string(day02.solve_b(data)),
- )
- }),
- Nil,
- )
- }
- ["3"] -> {
- result.unwrap(
- result.map(read("data/day3.txt"), fn(data) {
- io.println(
- "[3] Mull It Over (Part 1): " <> int.to_string(day03.solve_a(data)),
- )
- io.println(
- "[3] Mull It Over (Part 2): " <> int.to_string(day03.solve_b(data)),
- )
- }),
- Nil,
- )
- }
- ["4"] -> {
- result.unwrap(
- result.map(read("data/day4.txt"), fn(data) {
- io.println(
- "[4] Ceres Search (Part 1): " <> int.to_string(day04.solve_a(data)),
- )
- io.println(
- "[4] Ceres Search (Part 2): " <> int.to_string(day04.solve_b(data)),
- )
- }),
- Nil,
- )
- }
- ["5"] -> {
- result.unwrap(
- result.map(read("data/day5.txt"), fn(data) {
- io.println(
- "[5] Print Queue (Part 1): " <> int.to_string(day05.solve_a(data)),
- )
- io.println(
- "[5] Print Queue (Part 2): " <> int.to_string(day05.solve_b(data)),
- )
- }),
- Nil,
- )
- }
- ["6"] -> {
- result.unwrap(
- result.map(read("data/day6.txt"), fn(data) {
- io.println(
- "[6] Guard Gallivant (Part 1): "
- <> int.to_string(day06.solve_a(data)),
- )
- io.println(
- "[6] Guard Gallivant (Part 2): "
- <> int.to_string(day06.solve_b(data)),
- )
- }),
- Nil,
- )
- }
- ["7"] -> {
- result.unwrap(
- result.map(read("data/day7.txt"), fn(data) {
- io.println(
- "[7] Bridge Repair (Part 1): " <> int.to_string(day07.solve_a(data)),
- )
- io.println(
- "[7] Bridge Repair (Part 2): " <> int.to_string(day07.solve_b(data)),
- )
- }),
- Nil,
- )
- }
-
- ["8"] -> {
- result.unwrap(
- result.map(read("data/day8.txt"), fn(data) {
- io.println(
- "[8] Resonant Collinearity (Part 1): "
- <> int.to_string(day08.solve_a(data)),
- )
- io.println(
- "[8] Resonant Collinearity (Part 2): "
- <> int.to_string(day08.solve_b(data)),
- )
- }),
- Nil,
- )
- }
- ["9"] -> {
- result.unwrap(
- result.map(read("data/day9.txt"), fn(data) {
- io.println(
- "[9] Disk Fragmenter (Part 1): "
- <> int.to_string(day09.solve_a(data)),
- )
- io.println(
- "[9] Disk Fragmenter (Part 2): "
- <> int.to_string(day09.solve_b(data)),
- )
- }),
- Nil,
- )
- }
- ["10"] -> {
- result.unwrap(
- result.map(read("data/day10.txt"), fn(data) {
- io.println(
- "[10] Hoof It (Part 1): " <> int.to_string(day10.solve_a(data)),
- )
- io.println(
- "[10] Hoof It (Part 2): " <> int.to_string(day10.solve_b(data)),
- )
- }),
- Nil,
- )
- }
- _ -> io.println_error("invalid arguments!")
- }
-}
diff --git a/src/bridge_repair.gleam b/src/bridge_repair.gleam
deleted file mode 100644
index 2a2ff44..0000000
--- a/src/bridge_repair.gleam
+++ /dev/null
@@ -1,95 +0,0 @@
-import gleam/int
-import gleam/list
-import gleam/otp/task
-import gleam/result
-import gleam/string
-import utils/list as li
-
-type Equation {
- Equation(target: Int, values: List(String))
-}
-
-fn parse_eq(line: String) -> Equation {
- let assert Ok(#(tar_str, vals_str)) = string.split_once(line, ": ")
- let assert Ok(tar_int) = int.parse(tar_str)
- let values = string.split(vals_str, " ")
-
- Equation(target: tar_int, values: values)
-}
-
-fn parse_file(input: String) -> List(Equation) {
- input
- |> string.trim
- |> string.split("\n")
- |> list.map(parse_eq)
-}
-
-fn parse_num(x: String) -> Int {
- result.unwrap(int.parse(x), 0)
-}
-
-fn mult(lhs: String, rhs: String) -> String {
- int.to_string(int.multiply(parse_num(lhs), parse_num(rhs)))
-}
-
-fn add(lhs: String, rhs: String) -> String {
- int.to_string(int.add(parse_num(lhs), parse_num(rhs)))
-}
-
-fn solve_part(eq: List(String)) -> List(String) {
- case eq {
- [lhs, opr, rhs] ->
- case opr {
- "*" -> list.wrap(mult(lhs, rhs))
- "+" -> list.wrap(add(lhs, rhs))
- "|" -> list.wrap(lhs <> rhs)
- _ -> []
- }
- _ -> []
- }
-}
-
-fn solve_eq_lr(eq: List(String)) -> List(String) {
- case list.length(eq) {
- 1 | 0 -> eq
- _ -> {
- case list.split(eq, 3) {
- #(head, tail) -> solve_eq_lr(list.append(solve_part(head), tail))
- }
- }
- }
-}
-
-fn is_satisfiable(eq: Equation, operators: List(String)) -> Bool {
- li.repeated_permutation(operators, list.length(eq.values) - 1)
- |> list.map(fn(combo) { list.interleave([eq.values, combo]) })
- |> list.flat_map(solve_eq_lr)
- |> list.any(fn(soln) { eq.target == parse_num(soln) })
-}
-
-fn extract(x: #(Equation, Bool)) {
- case x {
- #(eq, True) -> Ok(eq.target)
- _ -> Error(Nil)
- }
-}
-
-fn is_satisfiable_async(eq: Equation, operators: List(String)) {
- task.async(fn() { #(eq, is_satisfiable(eq, operators)) })
-}
-
-pub fn solve_a(input: String) -> Int {
- parse_file(input)
- |> list.map(is_satisfiable_async(_, ["*", "+"]))
- |> list.map(task.await_forever)
- |> list.filter_map(extract)
- |> list.fold(0, int.add)
-}
-
-pub fn solve_b(input: String) -> Int {
- parse_file(input)
- |> list.map(is_satisfiable_async(_, ["*", "+", "|"]))
- |> list.map(task.await_forever)
- |> list.filter_map(extract)
- |> list.fold(0, int.add)
-}
diff --git a/src/ceres_search.gleam b/src/ceres_search.gleam
deleted file mode 100644
index 7891bdf..0000000
--- a/src/ceres_search.gleam
+++ /dev/null
@@ -1,83 +0,0 @@
-import gleam/dict.{type Dict}
-import gleam/int
-import gleam/list
-import gleam/pair
-import gleam/result
-import gleam/string
-
-type Point =
- #(Int, Int)
-
-type Grid =
- Dict(Point, String)
-
-fn process_grid(input: String, f: fn(Grid) -> Int) -> Int {
- input
- |> string.trim()
- |> string.split("\n")
- |> list.map(string.to_graphemes)
- |> list.index_map(fn(line, y) {
- use grid, char, x <- list.index_fold(line, dict.new())
- dict.insert(grid, #(x, y), char)
- })
- |> list.reduce(dict.merge)
- |> result.unwrap(dict.new())
- |> f
-}
-
-fn word(points: List(Point), grid: Grid) -> String {
- use word, point <- list.fold(points, "")
- string.append(word, result.unwrap(dict.get(grid, point), ""))
-}
-
-fn all_neighbors(point: Point, word: String) -> List(List(Point)) {
- let id = fn(x, _d) { x }
- use f <- list.map([
- #(int.add, id),
- #(int.subtract, id),
- #(id, int.subtract),
- #(id, int.add),
- #(int.subtract, int.subtract),
- #(int.add, int.subtract),
- #(int.subtract, int.add),
- #(int.add, int.add),
- ])
- use d <- list.map(list.range(0, string.length(word) - 1))
- let #(x, y) = point
- #(pair.first(f)(x, d), pair.second(f)(y, d))
-}
-
-fn x_neighbors(point: #(Int, Int)) {
- let #(x, y) = point
- [
- [#(x - 1, y - 1), point, #(x + 1, y + 1)],
- [#(x + 1, y - 1), point, #(x - 1, y + 1)],
- ]
-}
-
-fn xmas_count_at_point(grid: Grid, point: Point) -> Int {
- all_neighbors(point, "XMAS")
- |> list.map(word(_, grid))
- |> list.count(fn(w) { w == "XMAS" })
-}
-
-fn point_has_x_mas(grid: Grid, point: Point) -> Bool {
- x_neighbors(point)
- |> list.map(word(_, grid))
- |> list.all(fn(w) { w == "MAS" || w == "SAM" })
-}
-
-pub fn solve_a(input: String) -> Int {
- use grid <- process_grid(input)
-
- dict.keys(grid)
- |> list.map(xmas_count_at_point(grid, _))
- |> list.fold(0, int.add)
-}
-
-pub fn solve_b(input: String) -> Int {
- use grid <- process_grid(input)
-
- dict.keys(grid)
- |> list.count(point_has_x_mas(grid, _))
-}
diff --git a/src/disk_fragmenter.gleam b/src/disk_fragmenter.gleam
deleted file mode 100644
index 4134d12..0000000
--- a/src/disk_fragmenter.gleam
+++ /dev/null
@@ -1,105 +0,0 @@
-import gleam/int
-import gleam/list
-import gleam/result
-import gleam/string
-import utils/list as li
-
-type Block {
- File(Int)
- None
-}
-
-type Disk =
- List(Block)
-
-fn generate_file_block(block_count, file_index) -> Disk {
- case block_count {
- "0" -> []
- _ ->
- list.range(1, result.unwrap(int.parse(block_count), 0))
- |> list.map(fn(_) { File(file_index / 2) })
- }
-}
-
-fn generate_space_block(block_count) -> Disk {
- case block_count {
- "0" -> []
- _ ->
- list.range(1, result.unwrap(int.parse(block_count), 0))
- |> list.map(fn(_) { None })
- }
-}
-
-fn generate_block(block_count, file_index) -> Disk {
- case int.is_even(file_index) {
- True -> generate_file_block(block_count, file_index)
- False -> generate_space_block(block_count)
- }
-}
-
-fn disk_map(input: String) -> Disk {
- string.to_graphemes(input)
- |> list.index_map(generate_block)
- |> list.flatten
-}
-
-fn defrag_complete(disk: List(Block), current_index: Int) -> Bool {
- let #(_, after) = list.split(disk, current_index + 1)
-
- result.is_error(list.find(after, fn(x) { x != None }))
-}
-
-fn rotate_block(disk: Disk, state: Disk) -> Disk {
- case li.pop(disk) {
- #(Ok(None), rest) -> rotate_block(rest, list.append(state, [None]))
- #(Ok(anyval), rest) -> list.append([anyval], list.append(rest, state))
- #(Error(_), _) -> disk
- }
-}
-
-fn disk_defrag(disk: Disk, current_index: Int) -> Disk {
- case defrag_complete(disk, current_index) {
- True -> disk
- False ->
- case li.at(disk, current_index) {
- Ok(None) -> {
- let #(defragged, undefragged) = list.split(disk, current_index)
- let assert #([None], remaining_undefragged) =
- list.split(undefragged, 1)
- let new_current_disk_map =
- list.append(
- defragged,
- list.append(rotate_block(remaining_undefragged, []), [None]),
- )
-
- disk_defrag(new_current_disk_map, current_index + 1)
- }
- Ok(_) -> disk_defrag(disk, current_index + 1)
- Error(_) -> disk
- }
- }
-}
-
-fn get_blkid(blk: Block) -> Result(Int, Nil) {
- case blk {
- File(id) -> Ok(id)
- None -> Error(Nil)
- }
-}
-
-fn checksum(input: Disk) -> Int {
- input
- |> list.filter_map(fn(x) { get_blkid(x) })
- |> list.index_map(int.multiply)
- |> list.fold(0, int.add)
-}
-
-pub fn solve_a(input: String) -> Int {
- disk_map(input)
- |> disk_defrag(0)
- |> checksum
-}
-
-pub fn solve_b(_input: String) -> Int {
- 0
-}
diff --git a/src/guard_gallivant.gleam b/src/guard_gallivant.gleam
deleted file mode 100644
index 4f9bbab..0000000
--- a/src/guard_gallivant.gleam
+++ /dev/null
@@ -1,217 +0,0 @@
-import gleam/dict.{type Dict}
-import gleam/list
-import gleam/option.{type Option, Some}
-import gleam/otp/task
-import gleam/pair.{first as pf, second as ps}
-import gleam/result
-import gleam/string
-import utils/list as li
-
-type Entity {
- Guard
- Obstacle
- Path
- Unknown(String)
-}
-
-type Point =
- #(Int, Int)
-
-type Grid =
- Dict(Point, Entity)
-
-type Direction {
- Up
- Down
- Left
- Right
-}
-
-type History =
- #(Point, Direction)
-
-type IterState {
- IterState(
- point: Point,
- direction: Direction,
- grid: Grid,
- histories: List(History),
- max_bound: Int,
- looping: Bool,
- )
-}
-
-fn parse_column(line, y) {
- use grid, char, x <- list.index_fold(line, dict.new())
- dict.insert(grid, #(x, y), case char {
- "." -> Path
- "#" -> Obstacle
- "^" -> Guard
- uchr -> Unknown(uchr)
- })
-}
-
-fn parse_grid(input: String) -> Grid {
- input
- |> string.trim()
- |> string.split("\n")
- |> list.map(string.to_graphemes)
- |> list.index_map(parse_column)
- |> list.reduce(dict.merge)
- |> result.unwrap(dict.new())
-}
-
-fn is_guard_position(pos: Point, g: Grid) -> Bool {
- case dict.get(g, pos) {
- Ok(Guard) -> True
- _ -> False
- }
-}
-
-fn init_state(g: Grid) -> IterState {
- let assert Ok(gp) = list.find(dict.keys(g), is_guard_position(_, g))
- IterState(
- point: gp,
- direction: Up,
- grid: g,
- histories: [#(gp, Up)],
- max_bound: li.max(list.map(dict.keys(g), pf)),
- looping: False,
- )
-}
-
-fn incr_pos(pos: Point, dir: Direction) -> Point {
- case dir {
- Up -> #(pf(pos), ps(pos) - 1)
- Down -> #(pf(pos), ps(pos) + 1)
- Left -> #(pf(pos) - 1, ps(pos))
- Right -> #(pf(pos) + 1, ps(pos))
- }
-}
-
-fn is_obstacle(position: Point, grid: Grid) -> Bool {
- case dict.get(grid, position) {
- Ok(Obstacle) -> True
- _ -> False
- }
-}
-
-fn rotate_cw(d: Direction) -> Direction {
- case d {
- Up -> Right
- Down -> Left
- Right -> Down
- Left -> Up
- }
-}
-
-fn next_coordinates(pos: Point, dir: Direction, g: Grid) -> #(Point, Direction) {
- let np = incr_pos(pos, dir)
- case is_obstacle(np, g) {
- True -> next_coordinates(pos, rotate_cw(dir), g)
- False -> #(np, dir)
- }
-}
-
-fn guard_exited(pos: Point, b: Int) -> Bool {
- let #(x, y) = pos
- x > b || x < 0 || y < 0 || y > b
-}
-
-fn emulate(is: IterState) -> IterState {
- let #(ngp, ngd) = next_coordinates(is.point, is.direction, is.grid)
- case guard_exited(ngp, is.max_bound) {
- True -> is
- False ->
- emulate(IterState(
- point: ngp,
- direction: ngd,
- grid: is.grid,
- histories: list.append(is.histories, [#(ngp, ngd)]),
- max_bound: is.max_bound,
- looping: False,
- ))
- }
-}
-
-fn visited_count(is: IterState) -> Int {
- is.histories
- |> list.map(pf)
- |> list.unique
- |> list.length
-}
-
-fn visited_paths(is: IterState) -> #(Grid, List(Point)) {
- #(is.grid, list.unique(list.map(is.histories, pf)))
-}
-
-fn iterate(is: IterState) -> IterState {
- let #(ngp, ngd) = next_coordinates(is.point, is.direction, is.grid)
- let ngh = list.append(is.histories, [#(ngp, ngd)])
-
- case guard_exited(ngp, is.max_bound) {
- True -> is
- False ->
- case li.contains(is.histories, #(ngp, ngd)) {
- True ->
- IterState(
- point: ngp,
- direction: ngd,
- grid: is.grid,
- histories: ngh,
- max_bound: is.max_bound,
- looping: True,
- )
- False ->
- iterate(IterState(
- point: ngp,
- direction: ngd,
- grid: is.grid,
- histories: ngh,
- max_bound: is.max_bound,
- looping: False,
- ))
- }
- }
-}
-
-fn add_obst(g: Grid, pt: Point) -> Grid {
- dict.upsert(g, pt, fn(ent: Option(Entity)) {
- case ent {
- Some(Guard) -> Guard
- _ -> Obstacle
- }
- })
-}
-
-fn is_infinite_loop_obstacle(g: Grid, point: Point) {
- task.async(fn() {
- add_obst(g, point)
- |> init_state
- |> iterate
- |> fn(x) { x.looping }
- })
-}
-
-fn count_infinite_loop_obstacles(info) -> Int {
- let #(g, original_path) = info
-
- original_path
- |> list.map(is_infinite_loop_obstacle(g, _))
- |> list.count(task.await_forever)
-}
-
-pub fn solve_a(input: String) -> Int {
- parse_grid(input)
- |> init_state
- |> emulate
- |> visited_count
-}
-
-pub fn solve_b(input: String) -> Int {
- parse_grid(input)
- |> init_state
- |> emulate
- |> visited_paths
- |> count_infinite_loop_obstacles
-}
diff --git a/src/historian_hysteria.gleam b/src/historian_hysteria.gleam
deleted file mode 100644
index c2ae741..0000000
--- a/src/historian_hysteria.gleam
+++ /dev/null
@@ -1,43 +0,0 @@
-import gleam/int
-import gleam/list
-import gleam/pair
-import gleam/result
-import gleam/string
-
-fn parse_line(line: String) -> List(Int) {
- use a <- list.map(string.split(line, " "))
- result.unwrap(int.parse(a), 0)
-}
-
-fn dist(scans: #(Int, Int)) {
- int.absolute_value(pair.second(scans) - pair.first(scans))
-}
-
-fn freq_score_gen(ys: List(Int)) {
- fn(x) { x * list.count(ys, fn(y) { y == x }) }
-}
-
-pub fn solve_a(input) -> Int {
- input
- |> string.trim()
- |> string.split("\n")
- |> list.map(parse_line)
- |> list.transpose()
- |> list.map(list.sort(_, int.compare))
- |> list.reduce(fn(x, y) { list.map(list.zip(x, y), dist) })
- |> result.map(list.reduce(_, int.add))
- |> result.flatten()
- |> result.unwrap(0)
-}
-
-pub fn solve_b(input) -> Int {
- input
- |> string.trim()
- |> string.split("\n")
- |> list.map(parse_line)
- |> list.transpose()
- |> list.reduce(fn(x, y) { list.map(x, freq_score_gen(y)) })
- |> result.map(list.reduce(_, int.add))
- |> result.flatten()
- |> result.unwrap(0)
-}
diff --git a/src/hoof_it.gleam b/src/hoof_it.gleam
deleted file mode 100644
index e566585..0000000
--- a/src/hoof_it.gleam
+++ /dev/null
@@ -1,7 +0,0 @@
-pub fn solve_a(_: String) -> Int {
- 0
-}
-
-pub fn solve_b(_: String) -> Int {
- 0
-}
diff --git a/src/main.rs b/src/main.rs
new file mode 100644
index 0000000..2d13a65
--- /dev/null
+++ b/src/main.rs
@@ -0,0 +1,49 @@
+mod solutions;
+
+use anyhow::{anyhow, Result};
+use solutions::cube_conundrum as day02;
+use solutions::scratchcards as day04;
+use solutions::trebuchet as day01;
+use std::env::args;
+use std::fs::File;
+use std::io::Read;
+
+fn read_file(path: &str) -> Result {
+ let mut file = File::open(path)?;
+ let mut contents = String::new();
+ file.read_to_string(&mut contents)?;
+
+ Ok(contents)
+}
+
+fn main() -> Result<()> {
+ let day = args()
+ .nth(1)
+ .expect("[ERR] Solution Day Not Specified!")
+ .parse::()?;
+
+ match day {
+ 1 => {
+ let input: String = read_file("data/day01.txt")?;
+ println!("Part A => {}", day01::solve_part1(&input));
+ println!("Part B => {}", day01::solve_part2(&input));
+
+ Ok(())
+ }
+ 2 => {
+ let input: String = read_file("data/day02.txt")?;
+ println!("Part A => {}", day02::solve_part1(&input));
+ println!("Part B => {}", day02::solve_part2(&input));
+
+ Ok(())
+ }
+ 4 => {
+ let input: String = read_file("data/day04.txt")?;
+ println!("Part A => {}", day04::solve_part1(&input));
+ println!("Part B => {}", day04::solve_part2(&input));
+
+ Ok(())
+ }
+ _ => Err(anyhow!("No Solution Found!")),
+ }
+}
diff --git a/src/mull_it_over.gleam b/src/mull_it_over.gleam
deleted file mode 100644
index b0986db..0000000
--- a/src/mull_it_over.gleam
+++ /dev/null
@@ -1,45 +0,0 @@
-import gleam/int
-import gleam/list
-import gleam/pair
-import gleam/regexp
-import gleam/result
-
-pub fn process_isr(instr: String) -> Int {
- let assert Ok(args_rex) = regexp.from_string("\\d{1,3}")
- regexp.scan(args_rex, instr)
- |> list.map(fn(x) { x.content })
- |> list.map(fn(x) { result.unwrap(int.parse(x), -1) })
- |> list.fold_right(1, int.multiply)
-}
-
-pub fn process_cond_isr(state: #(Bool, Int), instr: String) -> #(Bool, Int) {
- case instr {
- "do()" -> #(True, pair.second(state))
- "don't()" -> #(False, pair.second(state))
- _ ->
- case pair.first(state) {
- True -> #(True, int.add(process_isr(instr), pair.second(state)))
- False -> state
- }
- }
-}
-
-pub fn solve_a(input: String) -> Int {
- let assert Ok(rex) = regexp.from_string("(mul\\([0-9]{1,3},[0-9]{1,3}\\))")
-
- regexp.scan(rex, input)
- |> list.map(fn(match) { match.content })
- |> list.map(process_isr)
- |> list.reduce(int.add)
- |> result.unwrap(0)
-}
-
-pub fn solve_b(input: String) -> Int {
- let assert Ok(rex) =
- regexp.from_string("(mul\\([0-9]{1,3},[0-9]{1,3}\\)|do\\(\\))|don't\\(\\)")
-
- regexp.scan(rex, input)
- |> list.map(fn(match) { match.content })
- |> list.fold(#(True, 0), process_cond_isr)
- |> pair.second
-}
diff --git a/src/print_queue.gleam b/src/print_queue.gleam
deleted file mode 100644
index 4f4b908..0000000
--- a/src/print_queue.gleam
+++ /dev/null
@@ -1,98 +0,0 @@
-import gleam/bool
-import gleam/int
-import gleam/list
-import gleam/pair.{first as pf, second as ps}
-import gleam/result
-import gleam/string
-import gleam/yielder
-import utils/list as li
-
-type Rule =
- #(Int, Int)
-
-type Order =
- List(Int)
-
-fn parse_rule(input: String) -> Rule {
- let assert Ok(#(first, second)) = string.split_once(input, "|")
- let assert Ok(fnum) = int.parse(first)
- let assert Ok(snum) = int.parse(second)
-
- #(fnum, snum)
-}
-
-fn parse_order(input: String) -> List(Int) {
- use numres <- list.map(string.split(input, ","))
-
- result.unwrap(int.parse(numres), 0)
-}
-
-fn parse_file(input: String) -> #(List(Rule), List(Order)) {
- let assert Ok(#(rules, orders)) =
- string.split_once(string.trim(input), "\n\n")
-
- let parsed_rules = list.map(string.split(rules, "\n"), parse_rule)
- let parsed_orders = list.map(string.split(orders, "\n"), parse_order)
- #(parsed_rules, parsed_orders)
-}
-
-fn rule_applicable(order: Order, rule: Rule) -> Bool {
- list.all(li.from_pair(rule), li.contains(order, _))
-}
-
-fn rule_satisfied(order: Order, rule: Rule) -> Bool {
- let #(rf, rs) = rule
- let assert [x, y] = list.filter(order, fn(x) { x == rf || x == rs })
-
- x == rf && y == rs
-}
-
-fn order_follows_rules(order: Order, rules: List(Rule)) -> Bool {
- rules
- |> list.filter(rule_applicable(order, _))
- |> list.all(rule_satisfied(order, _))
-}
-
-fn rule_satisfied_or_swap(order: Order, rule: Rule) -> Order {
- case rule_satisfied(order, rule) {
- True -> order
- False -> li.swap(order, pf(rule), ps(rule))
- }
-}
-
-fn make_order_follow_rules(order: Order, rules: List(Rule)) -> Order {
- case order_follows_rules(order, rules) {
- True -> order
- False -> {
- list.filter(rules, rule_applicable(order, _))
- |> list.fold(order, rule_satisfied_or_swap)
- |> make_order_follow_rules(rules)
- }
- }
-}
-
-fn middle(order: Order) -> Int {
- order
- |> yielder.from_list
- |> yielder.at(list.length(order) / 2)
- |> result.unwrap(0)
-}
-
-pub fn solve_a(input: String) -> Int {
- let #(rules, orders) = parse_file(input)
-
- orders
- |> list.filter(order_follows_rules(_, rules))
- |> list.map(middle)
- |> list.fold(0, int.add)
-}
-
-pub fn solve_b(input: String) -> Int {
- let #(rules, orders) = parse_file(input)
-
- orders
- |> list.filter(fn(order) { bool.negate(order_follows_rules(order, rules)) })
- |> list.map(make_order_follow_rules(_, rules))
- |> list.map(middle)
- |> list.fold(0, int.add)
-}
diff --git a/src/red_nosed_reports.gleam b/src/red_nosed_reports.gleam
deleted file mode 100644
index 781f599..0000000
--- a/src/red_nosed_reports.gleam
+++ /dev/null
@@ -1,56 +0,0 @@
-import gleam/int
-import gleam/list
-import gleam/pair
-import gleam/result
-import gleam/string
-
-fn parse_line(line: String) -> List(Int) {
- use a <- list.map(string.split(line, " "))
- result.unwrap(int.parse(a), 0)
-}
-
-fn all_incr(report: List(Int)) -> Bool {
- use nums <- list.all(list.window_by_2(report))
- case pair.second(nums) - pair.first(nums) {
- x if x > 0 && x < 4 -> True
- _ -> False
- }
-}
-
-fn all_decr(report: List(Int)) -> Bool {
- use nums <- list.all(list.window_by_2(report))
- case pair.first(nums) - pair.second(nums) {
- x if x > 0 && x < 4 -> True
- _ -> False
- }
-}
-
-fn valid(report: List(Int), d: Bool) -> Bool {
- case d {
- False -> all_incr(report) || all_decr(report)
- True ->
- valid(report, False)
- || {
- report
- |> list.combinations(list.length(report) - 1)
- |> list.any(valid(_, False))
- }
- }
-}
-
-pub fn solve_a(input: String) -> Int {
- input
- |> string.trim()
- |> string.split("\n")
- |> list.map(parse_line)
- |> list.count(valid(_, False))
-}
-
-pub fn solve_b(input: String) -> Int {
- input
- |> string.trim()
- |> string.split("\n")
- |> list.map(parse_line)
- |> list.filter(valid(_, True))
- |> list.length()
-}
diff --git a/src/resonant_collinearity.gleam b/src/resonant_collinearity.gleam
deleted file mode 100644
index 425394d..0000000
--- a/src/resonant_collinearity.gleam
+++ /dev/null
@@ -1,160 +0,0 @@
-import gleam/dict.{type Dict}
-import gleam/float
-import gleam/int
-import gleam/list
-import gleam/result
-import gleam/string
-
-type Point =
- #(Float, Float)
-
-type Grid =
- Dict(Point, String)
-
-type Direction {
- Forward
- Reverse
-}
-
-fn parse_column(line, y) {
- use grid, char, x <- list.index_fold(line, dict.new())
- dict.insert(grid, #(int.to_float(x), int.to_float(y)), char)
-}
-
-fn square(input: Float) -> Float {
- case float.power(input, 2.0) {
- Ok(val) -> val
- _ -> 0.0
- }
-}
-
-fn find_collinear_vector(
- point_a: Point,
- point_b: Point,
-) -> #(Float, #(Float, Float)) {
- let #(x1, y1) = point_a
- let #(x2, y2) = point_b
-
- let assert Ok(distance) =
- float.add(square(float.subtract(x2, x1)), square(float.subtract(y2, y1)))
- |> float.square_root
-
- let assert Ok(dx) = float.divide(float.subtract(x2, x1), distance)
- let assert Ok(dy) = float.divide(float.subtract(y2, y1), distance)
-
- #(distance, #(dx, dy))
-}
-
-fn find_collinear_in_direction(
- points: List(Point),
- direction: Direction,
-) -> Point {
- let assert [point_a, point_b] = points
- let #(distance, #(dx, dy)) = find_collinear_vector(point_a, point_b)
- let #(x1, y1) = point_a
- let #(x2, y2) = point_b
-
- case direction {
- Forward -> #(
- float.ceiling(float.add(x2, float.multiply(dx, distance))),
- float.ceiling(float.add(y2, float.multiply(dy, distance))),
- )
- Reverse -> #(
- float.ceiling(float.subtract(x1, float.multiply(dx, distance))),
- float.ceiling(float.subtract(y1, float.multiply(dy, distance))),
- )
- }
-}
-
-fn find_harmonic_collinear_in_direction(
- found: List(Point),
- grid: Grid,
- direction: Direction,
-) -> List(Point) {
- let #(head, rest) = list.split(found, 2)
- let assert [p1, p2] = head
- let collinear_in_direction = find_collinear_in_direction(head, direction)
-
- case point_within_map(collinear_in_direction, grid) {
- True ->
- case direction {
- Forward ->
- find_harmonic_collinear_in_direction(
- list.append([p2, collinear_in_direction], list.append(rest, [p1])),
- grid,
- direction,
- )
- Reverse ->
- find_harmonic_collinear_in_direction(
- list.append([collinear_in_direction, p1], list.append(rest, [p2])),
- grid,
- direction,
- )
- }
- False -> found
- }
-}
-
-fn find_all_harmonic_collinears(points: List(Point), grid: Grid) -> List(Point) {
- list.append(
- find_harmonic_collinear_in_direction(points, grid, Forward),
- find_harmonic_collinear_in_direction(points, grid, Reverse),
- )
-}
-
-fn find_all_collinears(points: List(Point)) -> List(Point) {
- list.wrap(find_collinear_in_direction(points, Forward))
- |> list.append(list.wrap(find_collinear_in_direction(points, Reverse)))
-}
-
-fn find_antenna_locations(antenna: String, grid: Grid) -> List(Point) {
- dict.keys(dict.filter(grid, fn(_, ant) { ant == antenna }))
-}
-
-fn point_within_map(point: Point, g: Grid) -> Bool {
- result.is_ok(list.find(dict.keys(g), fn(x) { x == point }))
-}
-
-fn collinears_for_antenna(antenna: String, g: Grid) -> List(Point) {
- find_antenna_locations(antenna, g)
- |> list.combinations(2)
- |> list.flat_map(find_all_collinears)
- |> list.filter(point_within_map(_, g))
- |> list.unique
-}
-
-fn harmonic_collinears_for_antenna(antenna: String, g: Grid) -> List(Point) {
- find_antenna_locations(antenna, g)
- |> list.combinations(2)
- |> list.flat_map(find_all_harmonic_collinears(_, g))
- |> list.filter(point_within_map(_, g))
-}
-
-fn parse_input(input: String) -> Grid {
- input
- |> string.trim()
- |> string.split("\n")
- |> list.map(string.to_graphemes)
- |> list.index_map(parse_column)
- |> list.fold(dict.new(), dict.merge)
-}
-
-pub fn solve_a(input: String) -> Int {
- let grid = parse_input(input)
-
- list.filter(list.unique(dict.values(grid)), fn(x) { x != "." })
- |> list.map(collinears_for_antenna(_, grid))
- |> list.flatten
- |> list.unique
- |> list.length
-}
-
-pub fn solve_b(input: String) -> Int {
- let grid = parse_input(input)
-
- list.filter(list.unique(dict.values(grid)), fn(x) { x != "." })
- |> list.map(harmonic_collinears_for_antenna(_, grid))
- |> list.flatten
- |> list.unique
- |> list.length
-}
diff --git a/src/solutions/cube_conundrum.rs b/src/solutions/cube_conundrum.rs
new file mode 100644
index 0000000..ac1414f
--- /dev/null
+++ b/src/solutions/cube_conundrum.rs
@@ -0,0 +1,183 @@
+#[derive(Debug, Clone, Hash, PartialEq, Eq)]
+enum Cube {
+ Red(u32),
+ Blue(u32),
+ Green(u32),
+ Invalid,
+}
+
+#[derive(Debug, Clone)]
+struct Game {
+ id: u32,
+ pub sets: Vec>,
+}
+
+#[derive(Debug, Clone)]
+struct Config {
+ red: u32,
+ green: u32,
+ blue: u32,
+}
+
+impl Game {
+ pub fn is_valid(&self, config: Config) -> bool {
+ self.sets
+ .clone()
+ .into_iter()
+ .filter(|cubes| {
+ cubes.iter().any(|cube| match cube {
+ Cube::Green(count) => count.gt(&config.green),
+ Cube::Red(count) => count.gt(&config.red),
+ Cube::Blue(count) => count.gt(&config.blue),
+ _ => false,
+ })
+ })
+ .count()
+ .eq(&0)
+ }
+
+ pub fn min_cubes(&self) -> u32 {
+ Ok::<(u32, u32, u32), anyhow::Error>(self.sets.iter().fold(
+ (0, 0, 0),
+ |(max_red, max_blue, max_green), cubes| {
+ cubes.iter().fold(
+ (max_red, max_blue, max_green),
+ |(red, blue, green), cube| match cube {
+ Cube::Red(x) => (red.max(*x), blue, green),
+ Cube::Blue(x) => (red, blue.max(*x), green),
+ Cube::Green(x) => (red, blue, green.max(*x)),
+ _ => (red, blue, green),
+ },
+ )
+ },
+ ))
+ .map(|(max_red, max_blue, max_green)| max_red * max_blue * max_green)
+ .unwrap_or(0)
+ }
+}
+
+mod parser {
+ use super::{Cube, Game};
+ use nom::{
+ branch::alt,
+ bytes::complete::tag,
+ character::complete::{digit1, line_ending, space1},
+ combinator::{eof, map_res},
+ multi::{many1, separated_list1},
+ sequence::{terminated, tuple},
+ Err as NomErr, IResult,
+ };
+ pub struct Parser;
+
+ impl Parser {
+ pub fn games(input: &str) -> IResult<&str, Vec> {
+ map_res(
+ many1(tuple((Self::game_id, many1(Self::game_set)))),
+ |games: Vec<(u32, Vec>)>| {
+ Ok::, NomErr<&str>>(
+ games
+ .into_iter()
+ .map(|(id, sets)| Game { id, sets })
+ .collect(),
+ )
+ },
+ )(input)
+ }
+
+ fn game_id(input: &str) -> IResult<&str, u32> {
+ map_res(
+ tuple((tag("Game "), map_res(digit1, str::parse::), tag(":"))),
+ |(_, id, _)| Ok::>(id),
+ )(input)
+ }
+
+ fn game_set(input: &str) -> IResult<&str, Vec> {
+ map_res(
+ terminated(
+ separated_list1(
+ tag(","),
+ tuple((
+ space1,
+ map_res(digit1, str::parse::),
+ space1,
+ alt((tag("blue"), tag("red"), tag("green"))),
+ )),
+ ),
+ alt((tag(";"), eof, line_ending)),
+ ),
+ |combinations: Vec<(&str, u32, &str, &str)>| {
+ Ok::, NomErr<&str>>(
+ combinations
+ .into_iter()
+ .map(|(_, count, _, color)| match color {
+ "red" => Cube::Red(count),
+ "green" => Cube::Green(count),
+ "blue" => Cube::Blue(count),
+ _ => Cube::Invalid,
+ })
+ .collect::>(),
+ )
+ },
+ )(input)
+ }
+ }
+}
+
+use parser::Parser;
+pub fn solve_part1(input: &str) -> u32 {
+ Parser::games(input)
+ .map(|(_, parsed)| parsed)
+ .unwrap_or_default()
+ .into_iter()
+ .filter(|game| {
+ game.is_valid(Config {
+ red: 12,
+ green: 13,
+ blue: 14,
+ })
+ })
+ .map(|game| game.id)
+ .sum::()
+}
+
+pub fn solve_part2(input: &str) -> u32 {
+ Parser::games(input)
+ .map(|(_, parsed)| parsed)
+ .unwrap_or_default()
+ .into_iter()
+ .map(|game| game.min_cubes())
+ .sum::()
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn test_part_a() {
+ let test_data = vec![
+ "Game 1: 3 blue, 4 red; 1 red, 2 green, 6 blue; 2 green",
+ "Game 2: 1 blue, 2 green; 3 green, 4 blue, 1 red; 1 green, 1 blue",
+ "Game 3: 8 green, 6 blue, 20 red; 5 blue, 4 red, 13 green; 5 green, 1 red",
+ "Game 4: 1 green, 3 red, 6 blue; 3 green, 6 red; 3 green, 15 blue, 14 red",
+ "Game 5: 6 red, 1 blue, 3 green; 2 blue, 1 red, 2 green",
+ ]
+ .join("\n");
+ let solution = solve_part1(&test_data);
+ assert_eq!(solution, 8)
+ }
+
+ #[test]
+ fn test_part_b() {
+ let test_data = vec![
+ "Game 1: 3 blue, 4 red; 1 red, 2 green, 6 blue; 2 green",
+ "Game 2: 1 blue, 2 green; 3 green, 4 blue, 1 red; 1 green, 1 blue",
+ "Game 3: 8 green, 6 blue, 20 red; 5 blue, 4 red, 13 green; 5 green, 1 red",
+ "Game 4: 1 green, 3 red, 6 blue; 3 green, 6 red; 3 green, 15 blue, 14 red",
+ "Game 5: 6 red, 1 blue, 3 green; 2 blue, 1 red, 2 green",
+ ]
+ .join("\n");
+ let solution = solve_part2(&test_data);
+ assert_eq!(solution, 2286)
+ }
+}
diff --git a/src/solutions/mod.rs b/src/solutions/mod.rs
new file mode 100644
index 0000000..254c433
--- /dev/null
+++ b/src/solutions/mod.rs
@@ -0,0 +1,3 @@
+pub mod cube_conundrum;
+pub mod scratchcards;
+pub mod trebuchet;
diff --git a/src/solutions/scratchcards.rs b/src/solutions/scratchcards.rs
new file mode 100644
index 0000000..8d52c0b
--- /dev/null
+++ b/src/solutions/scratchcards.rs
@@ -0,0 +1,116 @@
+use anyhow::Result;
+
+#[allow(unused)]
+#[derive(Debug)]
+struct Card {
+ id: u32,
+ winning_numbers: Vec,
+ own_numbers: Vec,
+}
+
+impl Card {
+ fn points(&self) -> Result {
+ Ok(self
+ .winning_numbers
+ .iter()
+ .filter(|winnum| self.own_numbers.iter().any(|ownnum| ownnum == *winnum))
+ .count())
+ .map(|cnt| {
+ if cnt.eq(&0) {
+ 0
+ } else {
+ u32::pow(2, (cnt as u32) - 1)
+ }
+ })
+ }
+}
+
+mod parser {
+ use super::Card;
+ use nom::{
+ branch::alt,
+ bytes::complete::tag,
+ character::complete::{digit1, space0, space1},
+ combinator::{eof, map_res},
+ multi::many1,
+ sequence::{terminated, tuple},
+ Err, IResult,
+ };
+
+ pub struct Parser;
+
+ impl Parser {
+ fn card_number_parser(inp: &str) -> IResult<&str, u32> {
+ map_res(
+ tuple((
+ tag("Card"),
+ space1,
+ map_res(digit1, |s: &str| -> Result> {
+ Ok(s.parse::().unwrap())
+ }),
+ tag(": "),
+ )),
+ |(_, _, card_id, _)| Ok::>(card_id),
+ )(inp)
+ }
+
+ fn own_numbers_parser(inp: &str) -> IResult<&str, Vec> {
+ terminated(
+ many1(map_res(
+ tuple((space0, terminated(digit1, space0))),
+ |(_, n): (&str, &str)| Ok::>(n.parse::().unwrap()),
+ )),
+ alt((tag("\n"), eof)),
+ )(inp)
+ }
+
+ fn winning_numbers_parser(inp: &str) -> IResult<&str, Vec> {
+ terminated(
+ many1(map_res(
+ tuple((space0, terminated(digit1, space0))),
+ |(_, n): (&str, &str)| Ok::>(n.parse::().unwrap()),
+ )),
+ tag("| "),
+ )(inp)
+ }
+
+ fn card_parser(inp: &str) -> IResult<&str, Card> {
+ map_res(
+ tuple((
+ Self::card_number_parser,
+ Self::winning_numbers_parser,
+ Self::own_numbers_parser,
+ )),
+ |(card_id, winning, own)| {
+ Ok::>(Card {
+ id: card_id,
+ winning_numbers: winning,
+ own_numbers: own,
+ })
+ },
+ )(inp)
+ }
+
+ fn card_list_parser(inp: &str) -> IResult<&str, Vec> {
+ many1(Self::card_parser)(inp)
+ }
+
+ pub fn parse(input: &str) -> IResult<&str, Vec> {
+ Self::card_list_parser(input)
+ }
+ }
+}
+
+use parser::Parser;
+pub fn solve_part1(input: &str) -> u32 {
+ Parser::parse(input)
+ .map(|(_, res)| res)
+ .unwrap_or_default()
+ .iter()
+ .map(|card| Card::points(card).unwrap_or_default())
+ .sum::()
+}
+
+pub fn solve_part2(_input: &str) -> i32 {
+ 0
+}
diff --git a/src/solutions/trebuchet.rs b/src/solutions/trebuchet.rs
new file mode 100644
index 0000000..dff4a52
--- /dev/null
+++ b/src/solutions/trebuchet.rs
@@ -0,0 +1,88 @@
+use itertools::Itertools;
+use regex::Regex;
+
+pub fn solve_part1(input: &str) -> u32 {
+ input
+ .lines()
+ .map(|line| {
+ line.trim()
+ .chars()
+ .filter(|c| c.is_numeric())
+ .map(|c| c.to_digit(10).unwrap())
+ .collect::>()
+ })
+ .map(|n| (10 * n.first().unwrap()) + n.last().unwrap())
+ .sum::()
+}
+
+pub fn solve_part2(input: &str) -> u32 {
+ let patterns = [
+ "zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", r"\d",
+ ]
+ .into_iter()
+ .map(|pattern| Regex::new(pattern).unwrap())
+ .collect::>();
+
+ let parse_int = |s: &str| -> u32 {
+ match s {
+ "one" => 1,
+ "two" => 2,
+ "three" => 3,
+ "four" => 4,
+ "five" => 5,
+ "six" => 6,
+ "seven" => 7,
+ "eight" => 8,
+ "nine" => 9,
+ "zero" => 0,
+ x => x.parse::().unwrap(),
+ }
+ };
+
+ input
+ .lines()
+ .map(|line| {
+ patterns
+ .clone()
+ .iter()
+ .flat_map(|pattern| {
+ pattern
+ .find_iter(line.trim())
+ .map(move |m| (m.start(), m.as_str()))
+ .collect::>()
+ })
+ .sorted_by(|(i1, _), (i2, _)| i1.cmp(i2))
+ .map(|(_, s)| parse_int(s))
+ .collect::>()
+ })
+ .map(|n| (n.first().unwrap() * 10) + n.last().unwrap())
+ .sum::()
+}
+
+#[cfg(test)]
+mod test {
+ use super::*;
+
+ #[test]
+ fn test_part_a() {
+ let test_data = vec!["1abc2", "pqr3stu8vwx", "a1b2c3d4e5f", "treb7uchet"].join("\n");
+ let solution = solve_part1(&test_data);
+ assert_eq!(solution, 142)
+ }
+
+ #[test]
+ fn test_part_b() {
+ let test_data = vec![
+ "two1nine",
+ "eightwothree",
+ "abcone2threexyz",
+ "xtwone3four",
+ "4nineeightseven2",
+ "zoneight234",
+ "7pqrstsixteen",
+ ]
+ .join("\n");
+ let solution = solve_part2(&test_data);
+ assert_eq!(solution, 281)
+ }
+}
diff --git a/src/utils/list.gleam b/src/utils/list.gleam
deleted file mode 100644
index f755c3b..0000000
--- a/src/utils/list.gleam
+++ /dev/null
@@ -1,64 +0,0 @@
-import gleam/list as li
-import gleam/pair.{first as pf, second as ps}
-import gleam/result as res
-
-pub fn index(ls: List(a), item: a) -> Result(Int, Nil) {
- li.index_map(ls, fn(x, index) { #(index, x) })
- |> li.find(fn(x) { ps(x) == item })
- |> res.map(pf)
-}
-
-pub fn at(ls: List(a), i: Int) -> Result(a, Nil) {
- li.index_map(ls, fn(x, ci) { #(x, ci) })
- |> li.find(fn(x) { ps(x) == i })
- |> res.map(pf)
-}
-
-pub fn from_pair(p: #(a, a)) -> List(a) {
- [pf(p), ps(p)]
-}
-
-pub fn pop(ls: List(a)) -> #(Result(a, Nil), List(a)) {
- case at(ls, li.length(ls) - 1) {
- Ok(someval) -> {
- #(Ok(someval), li.take(ls, li.length(ls) - 1))
- }
- Error(_) -> #(Error(Nil), ls)
- }
-}
-
-pub fn index_filter(ls: List(a), f: fn(Int, a) -> Bool) -> List(a) {
- li.index_map(ls, fn(item, index) { #(index, item) })
- |> li.filter(fn(x) { f(pf(x), ps(x)) })
- |> li.map(ps)
-}
-
-pub fn contains(ls: List(a), item: a) -> Bool {
- res.is_ok(li.find(ls, fn(x) { x == item }))
-}
-
-pub fn swap(ls: List(a), ea: a, eb: a) -> List(a) {
- use x <- li.map(ls)
- case x {
- val if val == ea -> eb
- val if val == eb -> ea
- val -> val
- }
-}
-
-pub fn max(ls: List(Int)) -> Int {
- li.fold(ls, 0, fn(cmx, cx) {
- case cx {
- cxx if cxx > cmx -> cxx
- _ -> cmx
- }
- })
-}
-
-pub fn repeated_permutation(ls: List(a), n: Int) {
- use acc, _ <- li.fold(li.range(1, n), [[]])
- use y <- li.flat_map(acc)
- use z <- li.map(ls)
-
- li.append(y, li.wrap(z))
-}
diff --git a/test/advent_of_code_test.gleam b/test/advent_of_code_test.gleam
deleted file mode 100644
index ecd12ad..0000000
--- a/test/advent_of_code_test.gleam
+++ /dev/null
@@ -1,5 +0,0 @@
-import gleeunit
-
-pub fn main() {
- gleeunit.main()
-}
diff --git a/test/bridge_repair_test.gleam b/test/bridge_repair_test.gleam
deleted file mode 100644
index 647462e..0000000
--- a/test/bridge_repair_test.gleam
+++ /dev/null
@@ -1,21 +0,0 @@
-import bridge_repair as day07
-import gleam/string
-import gleeunit/should
-
-fn test_data() -> String {
- string.join(
- [
- "190: 10 19", "3267: 81 40 27", "83: 17 5", "156: 15 6", "7290: 6 8 6 15",
- "161011: 16 10 13", "192: 17 8 14", "21037: 9 7 18 13", "292: 11 6 16 20",
- ],
- "\n",
- )
-}
-
-pub fn solve_a_test() {
- should.equal(day07.solve_a(test_data()), 3749)
-}
-
-pub fn solve_b_test() {
- should.equal(day07.solve_b(test_data()), 11_387)
-}
diff --git a/test/ceres_search_test.gleam b/test/ceres_search_test.gleam
deleted file mode 100644
index 79a3b42..0000000
--- a/test/ceres_search_test.gleam
+++ /dev/null
@@ -1,21 +0,0 @@
-import ceres_search as day04
-import gleam/string
-import gleeunit/should
-
-fn test_data() -> String {
- string.join(
- [
- "MMMSXXMASM", "MSAMXMSMSA", "AMXSXMAAMM", "MSAMASMSMX", "XMASAMXAMM",
- "XXAMMXXAMA", "SMSMSASXSS", "SAXAMASAAA", "MAMMMXMMMM", "MXMXAXMASX",
- ],
- "\n",
- )
-}
-
-pub fn solve_a_test() {
- should.equal(day04.solve_a(test_data()), 18)
-}
-
-pub fn solve_b_test() {
- should.equal(day04.solve_b(test_data()), 9)
-}
diff --git a/test/disk_fragmenter_test.gleam b/test/disk_fragmenter_test.gleam
deleted file mode 100644
index 6f7e85b..0000000
--- a/test/disk_fragmenter_test.gleam
+++ /dev/null
@@ -1,10 +0,0 @@
-import disk_fragmenter as day09
-import gleeunit/should
-
-pub fn solve_a_test() {
- should.equal(day09.solve_a("2333133121414131402"), 1928)
-}
-
-pub fn solve_b_test() {
- should.equal(day09.solve_b("2333133121414131402"), 0)
-}
diff --git a/test/guard_gallivant_test.gleam b/test/guard_gallivant_test.gleam
deleted file mode 100644
index 930ae9b..0000000
--- a/test/guard_gallivant_test.gleam
+++ /dev/null
@@ -1,21 +0,0 @@
-import gleam/string
-import gleeunit/should
-import guard_gallivant as day05
-
-fn test_data() {
- string.join(
- [
- "....#.....", ".........#", "..........", "..#.......", ".......#..",
- "..........", ".#..^.....", "........#.", "#.........", "......#...",
- ],
- "\n",
- )
-}
-
-pub fn solve_a_test() {
- should.equal(day05.solve_a(test_data()), 41)
-}
-
-pub fn solve_b_test() {
- should.equal(day05.solve_b(test_data()), 6)
-}
diff --git a/test/historian_hysteria_test.gleam b/test/historian_hysteria_test.gleam
deleted file mode 100644
index ce24da7..0000000
--- a/test/historian_hysteria_test.gleam
+++ /dev/null
@@ -1,14 +0,0 @@
-import gleeunit/should
-import historian_hysteria as day01
-
-fn test_data() -> String {
- "3 4\n4 3\n2 5\n1 3\n3 9\n3 3"
-}
-
-pub fn solve_a_test() {
- should.equal(day01.solve_a(test_data()), 11)
-}
-
-pub fn solve_b_test() {
- should.equal(day01.solve_b(test_data()), 31)
-}
diff --git a/test/hoof_it_test.gleam b/test/hoof_it_test.gleam
deleted file mode 100644
index af1258f..0000000
--- a/test/hoof_it_test.gleam
+++ /dev/null
@@ -1,21 +0,0 @@
-import gleam/string
-import gleeunit/should
-import hoof_it as day10
-
-fn test_data() -> String {
- string.join(
- [
- "89010123", "78121874", "87430965", "96549874", "45678903", "32019012",
- "01329801", "10456732",
- ],
- "\n",
- )
-}
-
-pub fn solve_a_test() {
- should.equal(day10.solve_a(test_data()), 36)
-}
-
-pub fn solve_b_test() {
- should.equal(day10.solve_b(test_data()), 0)
-}
diff --git a/test/mull_it_over_test.gleam b/test/mull_it_over_test.gleam
deleted file mode 100644
index 1b61b91..0000000
--- a/test/mull_it_over_test.gleam
+++ /dev/null
@@ -1,14 +0,0 @@
-import gleeunit/should
-import mull_it_over as day03
-
-pub fn solve_a_test() {
- "xmul(2,4)%&mul[3,7]!@^do_not_mul(5,5)+mul(32,64]then(mul(11,8)mul(8,5))"
- |> day03.solve_a()
- |> should.equal(161)
-}
-
-pub fn solve_b_test() {
- "xmul(2,4)&mul[3,7]!^don't()_mul(5,5)+mul(32,64](mul(11,8)undo()?mul(8,5))"
- |> day03.solve_b()
- |> should.equal(48)
-}
diff --git a/test/print_queue_test.gleam b/test/print_queue_test.gleam
deleted file mode 100644
index c34ac33..0000000
--- a/test/print_queue_test.gleam
+++ /dev/null
@@ -1,38 +0,0 @@
-import gleam/string
-import gleeunit/should
-import print_queue as day05
-
-fn test_data() -> String {
- string.join(
- [
- string.join(
- [
- "47|53", "97|13", "97|61", "97|47", "75|29", "61|13", "75|53", "29|13",
- "97|29", "53|29", "61|53", "97|53", "61|29", "47|13", "75|47", "97|75",
- "47|61", "75|61", "47|29", "75|13", "53|13",
- ],
- "\n",
- ),
- string.join(
- [
- "75,47,61,53,29", "97,61,53,29,13", "75,29,13", "75,97,47,61,53",
- "61,13,29", "97,13,75,29,47",
- ],
- "\n",
- ),
- ],
- "\n\n",
- )
-}
-
-pub fn solve_a_test() {
- test_data()
- |> day05.solve_a()
- |> should.equal(143)
-}
-
-pub fn solve_b_test() {
- test_data()
- |> day05.solve_b()
- |> should.equal(123)
-}
diff --git a/test/red_nosed_reports_test.gleam b/test/red_nosed_reports_test.gleam
deleted file mode 100644
index 5bc090e..0000000
--- a/test/red_nosed_reports_test.gleam
+++ /dev/null
@@ -1,21 +0,0 @@
-import gleam/string
-import gleeunit/should
-import red_nosed_reports as day01
-
-fn test_data() -> String {
- string.join(
- [
- "7 6 4 2 1", "1 2 7 8 9", "9 7 6 2 1", "1 3 2 4 5", "8 6 4 4 1",
- "1 3 6 7 9",
- ],
- "\n",
- )
-}
-
-pub fn solve_a_test() {
- should.equal(day01.solve_a(test_data()), 2)
-}
-
-pub fn solve_b_test() {
- should.equal(day01.solve_b(test_data()), 4)
-}
diff --git a/test/resonant_collinearity_test.gleam b/test/resonant_collinearity_test.gleam
deleted file mode 100644
index 57f2d9d..0000000
--- a/test/resonant_collinearity_test.gleam
+++ /dev/null
@@ -1,22 +0,0 @@
-import gleam/string
-import gleeunit/should
-import resonant_collinearity as day08
-
-fn test_data() -> String {
- string.join(
- [
- "............", "........0...", ".....0......", ".......0....",
- "....0.......", "......A.....", "............", "............",
- "........A...", ".........A..", "............", "............",
- ],
- "\n",
- )
-}
-
-pub fn solve_a_test() {
- should.equal(day08.solve_a(test_data()), 14)
-}
-
-pub fn solve_b_test() {
- should.equal(day08.solve_b(test_data()), 34)
-}