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..0fa5c73 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,5 +1,8 @@
-*.beam
-*.ez
-/build
-erl_crash.dump
-data/*.txt
+**/target/**
+**/deps/**
+**/_build/**
+**/.cookie
+**/.envrc
+**/benchmarks/**
+**/.clj-kondo/**
+**/.lsp/**
diff --git a/Cargo.lock b/Cargo.lock
new file mode 100644
index 0000000..c69cd01
--- /dev/null
+++ b/Cargo.lock
@@ -0,0 +1,219 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 3
+
+[[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",
+ "itertools",
+ "nom",
+ "petgraph",
+ "rayon",
+ "tap",
+ "uint",
+]
+
+[[package]]
+name = "autocfg"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
+
+[[package]]
+name = "byteorder"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
+
+[[package]]
+name = "cfg-if"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
+
+[[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 = "crunchy"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7"
+
+[[package]]
+name = "either"
+version = "1.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07"
+
+[[package]]
+name = "equivalent"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
+
+[[package]]
+name = "fixedbitset"
+version = "0.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80"
+
+[[package]]
+name = "hashbrown"
+version = "0.14.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604"
+
+[[package]]
+name = "hex"
+version = "0.4.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
+
+[[package]]
+name = "indexmap"
+version = "2.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f"
+dependencies = [
+ "equivalent",
+ "hashbrown",
+]
+
+[[package]]
+name = "itertools"
+version = "0.10.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473"
+dependencies = [
+ "either",
+]
+
+[[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 = "nom"
+version = "7.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a"
+dependencies = [
+ "memchr",
+ "minimal-lexical",
+]
+
+[[package]]
+name = "petgraph"
+version = "0.6.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e1d3afd2628e69da2be385eb6f2fd57c8ac7977ceeff6dc166ff1657b0e386a9"
+dependencies = [
+ "fixedbitset",
+ "indexmap",
+]
+
+[[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 = "scopeguard"
+version = "1.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
+
+[[package]]
+name = "static_assertions"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
+
+[[package]]
+name = "tap"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369"
+
+[[package]]
+name = "uint"
+version = "0.9.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "76f64bba2c53b04fcab63c01a7d7427eadc821e3bc48c34dc9ba29c501164b52"
+dependencies = [
+ "byteorder",
+ "crunchy",
+ "hex",
+ "static_assertions",
+]
diff --git a/Cargo.toml b/Cargo.toml
new file mode 100644
index 0000000..baa8174
--- /dev/null
+++ b/Cargo.toml
@@ -0,0 +1,15 @@
+[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"
+itertools = "0.10.5"
+nom = "7.1.1"
+petgraph = "0.6.2"
+rayon = "1.6.0"
+tap = "1.0.1"
+uint = "0.9.3"
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..d520941 100644
--- a/README.md
+++ b/README.md
@@ -1,22 +1,19 @@
-# 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
-```
+### Rust
-## Solution Status
+```bash
+git clone https://github.com/sreedevk/advent-of-code
+cd advent-of-code/rust
+cargo run -r
+```
-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)
+### Ruby
+```bash
+git clone
+cd advent-of-code/ruby
+cd
+ruby main.rb data.txt
+```
diff --git a/data/.keep b/data/.keep
deleted file mode 100644
index e69de29..0000000
diff --git a/data/day01.txt b/data/day01.txt
new file mode 100644
index 0000000..df7db11
--- /dev/null
+++ b/data/day01.txt
@@ -0,0 +1,2250 @@
+7769
+6798
+11685
+10826
+11807
+5786
+7932
+
+54883
+
+7069
+5792
+1519
+7380
+7034
+6203
+5706
+1850
+4933
+5562
+3826
+6661
+
+9150
+6417
+5057
+3568
+9352
+7134
+6040
+2451
+2295
+
+10996
+11802
+5525
+5705
+8266
+3742
+
+5140
+5527
+5686
+2488
+2518
+6260
+1692
+3149
+9109
+
+22590
+17677
+25444
+
+4146
+2282
+1957
+3673
+4830
+3220
+3823
+4619
+3222
+4076
+4594
+4550
+4806
+
+1426
+2726
+3566
+4089
+2195
+1512
+2547
+2284
+5687
+7429
+1043
+
+7877
+7446
+9753
+3184
+5417
+2306
+1680
+7121
+
+21326
+26045
+
+22638
+7066
+10062
+
+8585
+9072
+3466
+
+7022
+2085
+4942
+4034
+4285
+2498
+9268
+1444
+3302
+
+13269
+9710
+10391
+10915
+2195
+8559
+
+3035
+9421
+4497
+1802
+8447
+5675
+7580
+9053
+8004
+
+2777
+5293
+1866
+5019
+8129
+4632
+1530
+3438
+5812
+5460
+
+2982
+4005
+4036
+6510
+4817
+3958
+5057
+2049
+2603
+1227
+5960
+4043
+5261
+4780
+
+5642
+8518
+13634
+7727
+10729
+2587
+
+15874
+11122
+15896
+4477
+
+7772
+10595
+6827
+4469
+10385
+3420
+7657
+8950
+
+2062
+30422
+
+2007
+
+5148
+3451
+2735
+12950
+6576
+10785
+
+5578
+5978
+5716
+4026
+1429
+7684
+6552
+7630
+5834
+4936
+7936
+
+4417
+7072
+7646
+4604
+6426
+3020
+1286
+7360
+
+20192
+6831
+10425
+
+3685
+8863
+1300
+11973
+11525
+11077
+7184
+
+5352
+2370
+3014
+1386
+1486
+1718
+1898
+6896
+4930
+1628
+2798
+1681
+5751
+
+2150
+2901
+3490
+4291
+8998
+5673
+3623
+3894
+7435
+
+2235
+3164
+1231
+3675
+4188
+4865
+1611
+4652
+6333
+3262
+3124
+6215
+2704
+3183
+
+5215
+3259
+3550
+4965
+4096
+2036
+4517
+2554
+3266
+5571
+5266
+1466
+5259
+5882
+2782
+
+4755
+3402
+4269
+8242
+
+1365
+4100
+3131
+3596
+4719
+4250
+4580
+5418
+1687
+6533
+5938
+5865
+4605
+
+9739
+11547
+11940
+10268
+11939
+10825
+5522
+
+11534
+3303
+8778
+4682
+7643
+
+8045
+8298
+5813
+7881
+8605
+4114
+4524
+3837
+7631
+6763
+
+3781
+4709
+2733
+4606
+4291
+1785
+5297
+5929
+1424
+5951
+6175
+5367
+2370
+
+5882
+2097
+3154
+4166
+1556
+3414
+3977
+4348
+5069
+4092
+3614
+5803
+3460
+5374
+
+2814
+5388
+1641
+1526
+4489
+2291
+2573
+5389
+3109
+3422
+5342
+1461
+3105
+4265
+
+4726
+4817
+4047
+3690
+1101
+4853
+5962
+2049
+4059
+2172
+4509
+3395
+4854
+3838
+1019
+
+7358
+6318
+16327
+9518
+4995
+
+6426
+9428
+1077
+4142
+1989
+4019
+6187
+
+3162
+4035
+1359
+4364
+2392
+3819
+5132
+4721
+4794
+1622
+4693
+5318
+6089
+1588
+3199
+
+1273
+2231
+3534
+4970
+1685
+2565
+1847
+5926
+5778
+4919
+4238
+1422
+3945
+1252
+4234
+
+9120
+13317
+3969
+4758
+13615
+7951
+
+66512
+
+1501
+6913
+4990
+5948
+2597
+5644
+2876
+3515
+4264
+3768
+4731
+3944
+
+10132
+19382
+
+6047
+5939
+2528
+7985
+1897
+3393
+5548
+4948
+6010
+5878
+3060
+
+9054
+9776
+4515
+5124
+7522
+8530
+2383
+
+5847
+2878
+4148
+1173
+2170
+2647
+2068
+5523
+4020
+1211
+6391
+3562
+5005
+1904
+
+6823
+7455
+4026
+4248
+3707
+1157
+5135
+5637
+2967
+5746
+3987
+
+7376
+6875
+7041
+7713
+12827
+13582
+
+17060
+11310
+19892
+
+8053
+12649
+1222
+12407
+12724
+
+39856
+
+7534
+2592
+1012
+4760
+2118
+8180
+1054
+3230
+7718
+
+6017
+3402
+3896
+5801
+4055
+5034
+1063
+3694
+6663
+6079
+4364
+5712
+3366
+
+4197
+7022
+5256
+1425
+7656
+6799
+7117
+5580
+6349
+4039
+
+20138
+1054
+
+2340
+9011
+8717
+1458
+11325
+4563
+8634
+
+5553
+4344
+2022
+1712
+4142
+2372
+2444
+3286
+1456
+4778
+4125
+3745
+2776
+4688
+5256
+
+15243
+10322
+6333
+11283
+
+3932
+1767
+8008
+1064
+6096
+1695
+3423
+4814
+
+2592
+4604
+2710
+2273
+4703
+1705
+5528
+5053
+5556
+1562
+5820
+5347
+2978
+2734
+5782
+
+1890
+7379
+18132
+18576
+
+6752
+8949
+11389
+7170
+2131
+3725
+7053
+
+5545
+11110
+13900
+5552
+11452
+2249
+
+9323
+7633
+11404
+5092
+1683
+2705
+10840
+
+20742
+14722
+
+9990
+12357
+17458
+17411
+
+1698
+9149
+7872
+2331
+7464
+5228
+5603
+2551
+6590
+
+4927
+5047
+12168
+15288
+14202
+
+13034
+4809
+3511
+10173
+2745
+
+69228
+
+1810
+14168
+
+3939
+15152
+23394
+
+5366
+3942
+4203
+4337
+4559
+6474
+4586
+5663
+3658
+5700
+6654
+6103
+1057
+
+9680
+8092
+
+4204
+7952
+6443
+5174
+3142
+5908
+10695
+5827
+
+66023
+
+8071
+2036
+16786
+15029
+
+18357
+10466
+13614
+19749
+
+3429
+7627
+5875
+2678
+3260
+1265
+8377
+7841
+
+4403
+16663
+22998
+
+5571
+5978
+2363
+1170
+3368
+4273
+1975
+3272
+3885
+3288
+3287
+5319
+5073
+1543
+3815
+
+12653
+13250
+6247
+2301
+
+2817
+26802
+
+8427
+7538
+7405
+6634
+2889
+1705
+7171
+6067
+3737
+
+5708
+1287
+1923
+6351
+5986
+3291
+1295
+6439
+3591
+2498
+5135
+2927
+5476
+6504
+
+9888
+8000
+4035
+1566
+3005
+6312
+7637
+6485
+
+8797
+9447
+7955
+5218
+1487
+11930
+9613
+
+6618
+3290
+1626
+2828
+1212
+4021
+5720
+4838
+4069
+2792
+3864
+6113
+1059
+
+13347
+14049
+9926
+2695
+7591
+
+19734
+12813
+14941
+5044
+
+11219
+14430
+6907
+1295
+10293
+
+5012
+4809
+3807
+5257
+2325
+5551
+1899
+4972
+3409
+5340
+4525
+3395
+2881
+
+12541
+15894
+16431
+12428
+
+2641
+4872
+1533
+2437
+5982
+4387
+3221
+7000
+4438
+2051
+1046
+1708
+
+8702
+10811
+13926
+12768
+2506
+
+6568
+4598
+2225
+4648
+3543
+2542
+1099
+7314
+
+1692
+6923
+4315
+8777
+14624
+
+10646
+17681
+3207
+19894
+
+7926
+11094
+17423
+15371
+
+5048
+8089
+11169
+5040
+6221
+5191
+
+8682
+6191
+11354
+13461
+10597
+2513
+
+2189
+5321
+4750
+1844
+4592
+2686
+4028
+6125
+1162
+3405
+4721
+5505
+2934
+1095
+
+2068
+10452
+5876
+3227
+1290
+4654
+6635
+
+1936
+2110
+5374
+4185
+1198
+4599
+1146
+1929
+3807
+4076
+4765
+3831
+5478
+5989
+
+23444
+14453
+8534
+
+1019
+4669
+1444
+6127
+4243
+3660
+1274
+5428
+5662
+4909
+2672
+1241
+
+7346
+7316
+4450
+4987
+3131
+4318
+7189
+3525
+1041
+2680
+
+10645
+2358
+2163
+4477
+9860
+1345
+3691
+2085
+
+7383
+6160
+2327
+3158
+2693
+7236
+4629
+2416
+7986
+3383
+1136
+
+1190
+4026
+8538
+6659
+2981
+5995
+9724
+6940
+
+10340
+3805
+4627
+
+14249
+5887
+12930
+2407
+14495
+
+7516
+9033
+2525
+7708
+6145
+10001
+2655
+3141
+
+7379
+
+6608
+16917
+1035
+10703
+
+33797
+34907
+
+6797
+6996
+6591
+6379
+6973
+2831
+1277
+7051
+3832
+2433
+
+7531
+14776
+6826
+17630
+
+7386
+9544
+7237
+
+6602
+6957
+3141
+3585
+6978
+6463
+6948
+1051
+1433
+5963
+3190
+3433
+
+10667
+1972
+
+8003
+3968
+1911
+2211
+1255
+4850
+6125
+6806
+1283
+6968
+6659
+
+4095
+4468
+1307
+3095
+6596
+6039
+4003
+6669
+3820
+1938
+4527
+6348
+
+3603
+6057
+16940
+
+1702
+7175
+3506
+1917
+1901
+7955
+9292
+4531
+6309
+
+10460
+3439
+10344
+4353
+14564
+
+4848
+2725
+1146
+5588
+1671
+4461
+1109
+2933
+1639
+4587
+6680
+1035
+3288
+
+10223
+9558
+8984
+6259
+8858
+4175
+4696
+4865
+
+9629
+1673
+3138
+7637
+5938
+2470
+8013
+4296
+
+7350
+3432
+7036
+8337
+1497
+7476
+2665
+3929
+
+4781
+6914
+12163
+9402
+7776
+
+4099
+4560
+5915
+1973
+5439
+1400
+6595
+5966
+1196
+4074
+1936
+5854
+5206
+
+8515
+2858
+5997
+6508
+2452
+4353
+2981
+1926
+2914
+1393
+
+5453
+2358
+1559
+5635
+3544
+5985
+3780
+1973
+2762
+4714
+4959
+6217
+
+1189
+5940
+5972
+3127
+5704
+1270
+4245
+5290
+2370
+1828
+4501
+3431
+1382
+2932
+
+6204
+9810
+4609
+3992
+11958
+2599
+
+1879
+1009
+9081
+8621
+8883
+5696
+11034
+
+7627
+3776
+7000
+10332
+4325
+3876
+2789
+8333
+
+7701
+1778
+4980
+4505
+5648
+
+1799
+3098
+4398
+3948
+4257
+4112
+1364
+3813
+5036
+3469
+4468
+2531
+1348
+
+4378
+2265
+5366
+1511
+2074
+1163
+1459
+5241
+2568
+1730
+5780
+5065
+3062
+1122
+1117
+
+3812
+5343
+4364
+6951
+2722
+3256
+7022
+3296
+3913
+5731
+5034
+3887
+
+13509
+11975
+12287
+10636
+12399
+7668
+
+19677
+1190
+1202
+
+10816
+4836
+5309
+14165
+14288
+
+5490
+4786
+4274
+5379
+4549
+4178
+2801
+1439
+5323
+4588
+5163
+1764
+4159
+5876
+5784
+
+16630
+10090
+19629
+4208
+
+4828
+6769
+8968
+7615
+5761
+3303
+8317
+4078
+1484
+
+6249
+6524
+1303
+12159
+8931
+8535
+
+3704
+2998
+1785
+1520
+4399
+4624
+4708
+3660
+4117
+2092
+4172
+3349
+3104
+1789
+2007
+
+11372
+15360
+14226
+7483
+16378
+
+4261
+2686
+1891
+5516
+5035
+1525
+5360
+4027
+3811
+6325
+5813
+4172
+6415
+
+24072
+19037
+25145
+
+2885
+6595
+4536
+2928
+3890
+8081
+6309
+4441
+6922
+4877
+
+16459
+9019
+4823
+4890
+
+1962
+5355
+7809
+9413
+6811
+8709
+5073
+4847
+4097
+
+2745
+7978
+6573
+5295
+8034
+3894
+1410
+2764
+4644
+7553
+6257
+
+25171
+8046
+4857
+
+6783
+4054
+3275
+2976
+4343
+2370
+1621
+7456
+6762
+3160
+1156
+
+2686
+2728
+2184
+4152
+6487
+3462
+2738
+2908
+5387
+1577
+6751
+6695
+5232
+
+6177
+7217
+2564
+2443
+4514
+8294
+5415
+2623
+9681
+
+4950
+1038
+10383
+5835
+1327
+1302
+9590
+
+17215
+9922
+6402
+19625
+
+4168
+1146
+5827
+3497
+5063
+5336
+3091
+1710
+2455
+4036
+2016
+1400
+1839
+1280
+1802
+
+14115
+1542
+17633
+
+3405
+3819
+1079
+2957
+2594
+3639
+1941
+3709
+
+5027
+7097
+2180
+5866
+6339
+10088
+10331
+10009
+
+8795
+11892
+1803
+10020
+7485
+2252
+
+6020
+6734
+2366
+4256
+11042
+7705
+1154
+
+4649
+7673
+4275
+3178
+5322
+4959
+5990
+1480
+5206
+3693
+
+1033
+34996
+
+8495
+4414
+7618
+7494
+4141
+10026
+7653
+6703
+
+7338
+2459
+3138
+1169
+6969
+2912
+5215
+5295
+
+6828
+2861
+8421
+1358
+6303
+3986
+1616
+2345
+8176
+2108
+
+4784
+1321
+5487
+6182
+5706
+5460
+5418
+2886
+5906
+6230
+1211
+1325
+3766
+3473
+
+32044
+9585
+
+4129
+3880
+2446
+7678
+7171
+6122
+4815
+6490
+7811
+
+4998
+5114
+4812
+7291
+1189
+1140
+7418
+6180
+3614
+6185
+7174
+4112
+
+2120
+8291
+8297
+5972
+5091
+3300
+2250
+8252
+1798
+5973
+
+4580
+4253
+2599
+1260
+1319
+2410
+3880
+1891
+5663
+6015
+2826
+1685
+6015
+2218
+2074
+
+5484
+3947
+5030
+6716
+4840
+1353
+3667
+6815
+4884
+5050
+5678
+2224
+3010
+
+3357
+2304
+3432
+5239
+2342
+5433
+1529
+5368
+1377
+1955
+5154
+2021
+2777
+4191
+2437
+
+5674
+1979
+7064
+2839
+6346
+2751
+1055
+3565
+6608
+2640
+2418
+
+5639
+10983
+17671
+17911
+
+15626
+2960
+6655
+10375
+5736
+
+7035
+5732
+7114
+1535
+2199
+11194
+9774
+
+5832
+
+10467
+12415
+4879
+1429
+
+6075
+4309
+6002
+6426
+3744
+3310
+4451
+3076
+1509
+1748
+1692
+4507
+5036
+4895
+
+11696
+4115
+8159
+10845
+2786
+10615
+
+48621
+
+1192
+3957
+4091
+2855
+2872
+3079
+6075
+2858
+5498
+1143
+3565
+5869
+5297
+1698
+
+7795
+1985
+7103
+1419
+1310
+11662
+10826
+
+5503
+1258
+3528
+1705
+5995
+1163
+7702
+5395
+7432
+
+14868
+4477
+6259
+13077
+8291
+
+8320
+16041
+11934
+10727
+11090
+
+12551
+13807
+10502
+
+9432
+11708
+8636
+10825
+5787
+12812
+
+35147
+3076
+
+25130
+12321
+
+8915
+1256
+5757
+4542
+7654
+6386
+6577
+5309
+7586
+
+8039
+4206
+1881
+7297
+5462
+1961
+2831
+3112
+6699
+2228
+7562
+
+1922
+2168
+2585
+6069
+3197
+5424
+4482
+1832
+5677
+2958
+5352
+5895
+3866
+3543
+
+5634
+4583
+6213
+4733
+4093
+4552
+1115
+1413
+3362
+1079
+5891
+5299
+3532
+6085
+
+3765
+1926
+7096
+9431
+8271
+5419
+4734
+5307
+
+25704
+
+2025
+4435
+1940
+4431
+3579
+6629
+5778
+3161
+6755
+3089
+5531
+4578
+1898
+
+21458
+13856
+14167
+
+10658
+5673
+5497
+8117
+4249
+5299
+4091
+
+9437
+8079
+2943
+1661
+1856
+9904
+4602
+6529
+
+2512
+2786
+3226
+10440
+3819
+10685
+8838
+9662
+
+8602
+4695
+3934
+2730
+1767
+9104
+7493
+1063
+1794
+
+7080
+4569
+6256
+4728
+1399
+1907
+4763
+1715
+3886
+1251
+3224
+
+3959
+1907
+5456
+2086
+3711
+5971
+3294
+1861
+2780
+1913
+4832
+5076
+1830
+
+5804
+2484
+3124
+3675
+2231
+7385
+6162
+7721
+8320
+6636
+
+2776
+1481
+3775
+5827
+7069
+6834
+2274
+5570
+4355
+5544
+3954
+7455
+
+5864
+2635
+2103
+5153
+7465
+3629
+9144
+1026
+1281
+
+2245
+4411
+7641
+3676
+4231
+7080
+6825
+1638
+1669
+5421
+
+24591
+21630
+25260
+
+11157
+5983
+7801
+8726
+1466
+4673
+4161
+
+29272
+3399
+
+14240
+15303
+21022
+
+4601
+1980
+4747
+1424
+4354
+4854
+5111
+4812
+2612
+3479
+2243
+1010
+3081
+2162
+
+2499
+2823
+2552
+3999
+5433
+4645
+1491
+4132
+3319
+2680
+2814
+3418
+1762
+6143
+
+4333
+1177
+6107
+6535
+4587
+5845
+4595
+1898
+4140
+3508
+5708
+6816
+
+7619
+7616
+7029
+10521
+6949
+4053
+1093
+1831
+
+2343
+6227
+1128
+2486
+6296
+1852
+1198
+1012
+5792
+3116
+1241
+2703
+6783
+
+2330
+4075
+3239
+6472
+4512
+2701
+2322
+1281
+4283
+3289
+3978
+1141
+6478
+3138
+
+9950
+14105
+8952
+12549
+7905
+
+3088
+5831
+5452
+2038
+1116
+3670
+3025
+3749
+5040
+2507
+3787
+1674
+4437
+2630
+5239
+
+4742
+8167
+8733
+2304
+1227
+7007
+5281
+3939
+4327
+
+2821
+7212
+7353
+5102
+3808
+7328
+2741
+1436
+6321
+6249
+6961
+
+8502
+6346
+6807
+5110
+4949
+2355
+9254
+
+1071
+25798
+5915
+
+9040
+9174
+11739
+14248
+8788
+
+10873
+14148
+3787
+11629
+2610
+
+2689
+4455
+3461
+5468
+1308
+1111
+4181
+3832
+1172
+2809
+3782
+2943
+1926
+1470
+5324
+
+2093
+7919
+1178
+7995
+4279
+1018
+1011
+1690
+2987
+5071
+
+8113
+2934
+
+5764
+2369
+4718
+2864
+6292
+5603
+3142
+8156
+1571
+2106
+
+3583
+1792
+5592
+5648
+5637
+3586
+1685
+1042
+4020
+6204
+4111
+4887
+6858
+
+9068
+
+9609
+4036
+1227
+11370
+11483
+10833
+3292
+
+1797
+1186
+1161
+3359
+5955
+5332
+3462
+2192
+1729
+2805
+1171
+5332
+3731
+4957
+5346
+
+5676
+7085
+3867
+9663
+13102
+
+5308
+3903
+8988
+15818
+2696
+
+7063
+7044
+7147
+2751
+6535
+1043
+6057
+4090
+3731
+7334
+
+7758
+5823
+6563
+2108
+9679
+5786
+4832
+3159
diff --git a/data/day02.txt b/data/day02.txt
new file mode 100644
index 0000000..1930858
--- /dev/null
+++ b/data/day02.txt
@@ -0,0 +1,2500 @@
+C Z
+C Z
+A X
+A X
+B Z
+B Z
+B Z
+A Z
+B X
+A X
+A X
+A X
+C Z
+C Z
+C X
+A X
+A X
+A X
+C Z
+B Z
+C Z
+A Y
+B Z
+A X
+C Y
+A X
+A X
+C Y
+C Z
+A Y
+B Z
+A X
+C Y
+B Z
+B Z
+B Z
+A X
+C X
+C X
+B Z
+A X
+C Z
+A X
+B Z
+A Y
+C X
+A X
+C Z
+C Z
+B Z
+C Y
+C X
+C X
+C X
+C X
+A Y
+C Y
+C Z
+C Y
+A X
+C Y
+A X
+B Z
+A Y
+C X
+A X
+B Y
+A X
+C X
+C X
+C Z
+A X
+C X
+A X
+C X
+B Z
+A Z
+B Y
+B Z
+B Z
+A X
+C Y
+B X
+A X
+A X
+B Z
+A X
+C X
+C Z
+C Z
+A X
+C Z
+C Z
+C Z
+C X
+C Z
+A X
+B Z
+B Y
+C Z
+B Z
+B Z
+A X
+B Z
+C Y
+C Z
+A X
+A Y
+C Z
+A X
+B Y
+C Y
+C Z
+A X
+C Y
+C X
+A X
+C X
+A X
+C Z
+A X
+C Y
+A Y
+C Z
+C X
+C Y
+C Y
+A Y
+A Y
+C Y
+C Y
+A Y
+A X
+C Z
+C Z
+C X
+C X
+C Z
+A Y
+C Z
+C Z
+A Y
+A Y
+B Z
+A X
+B Z
+C Y
+B Z
+C Z
+C Y
+C Y
+B Y
+C X
+A X
+A X
+A X
+A Y
+A X
+C Z
+C Z
+C Z
+A X
+B Z
+A X
+B Z
+C Y
+C Z
+A Y
+C Y
+A X
+A X
+C Z
+B X
+C Z
+C Z
+B Z
+B Z
+B Z
+C Z
+C X
+C Z
+A X
+B Z
+C Z
+C X
+A X
+A Y
+B Y
+A X
+B Z
+A X
+C Z
+C Z
+C X
+B Z
+C Z
+C Z
+C X
+A X
+A X
+B Y
+C Y
+C Z
+B Y
+A X
+B Z
+A X
+B X
+B Z
+C X
+C X
+C Y
+C X
+B Y
+B Z
+C X
+A Y
+C X
+C Y
+A X
+C Z
+C Z
+C X
+B Z
+A Y
+B Z
+A Y
+B X
+A X
+C Z
+B Z
+C X
+C X
+C X
+A X
+C X
+B Z
+C Z
+B Y
+B Z
+A X
+A X
+C Z
+B Z
+A X
+A Z
+C Y
+B Z
+C X
+C Z
+A Y
+C X
+A X
+A X
+A Y
+B Z
+A X
+B Z
+A Y
+B X
+C X
+C Y
+A X
+C Z
+B X
+C Z
+C X
+C X
+C Z
+A X
+B Z
+C Z
+C X
+C Z
+B Y
+A X
+C X
+C Y
+A X
+C Z
+A X
+B Z
+C X
+C X
+B Z
+C Z
+C Z
+C Y
+A X
+C Z
+C X
+A X
+C Y
+C Z
+C Z
+C Y
+B Y
+B Z
+A X
+B Y
+C X
+A X
+A X
+C Y
+C Z
+B Z
+C X
+C X
+B Z
+C Z
+A X
+A Y
+A X
+C Y
+A Y
+B Y
+A X
+A X
+C X
+C X
+B Z
+A Y
+B Z
+C Z
+A X
+A Y
+A X
+C X
+A X
+C Z
+B Y
+C Z
+A X
+B Z
+C Z
+C Z
+A X
+A X
+B Z
+B Z
+B Z
+A X
+C X
+A X
+A X
+C Y
+C Y
+C X
+C X
+A X
+A Y
+B Y
+C Z
+C Z
+B Y
+C X
+C Z
+A Y
+C X
+C Z
+C X
+B Z
+C Y
+C Z
+C X
+C Y
+C Z
+B Z
+C Z
+B Z
+A X
+B Y
+B Y
+C Z
+B Z
+C X
+C Z
+C Z
+C Z
+B Y
+B Z
+C Z
+B Y
+A X
+A X
+C X
+A X
+C X
+A X
+B Z
+A X
+A X
+A X
+C Z
+A Y
+A X
+C Z
+C X
+A X
+C X
+A X
+B Z
+C Z
+C Z
+C Z
+A X
+A X
+C Z
+A X
+B Z
+C X
+C Z
+C Y
+B Z
+A X
+B Z
+A X
+A Z
+B Y
+B Z
+B Z
+B Z
+A Y
+C Z
+A X
+B Y
+C X
+B X
+B Z
+C X
+B Y
+C Z
+A X
+C X
+B Z
+A X
+B Z
+A X
+A X
+B Y
+C Y
+C X
+C X
+C Z
+A X
+C Z
+A X
+B Y
+C X
+C Y
+B Y
+B Y
+A Y
+C X
+A Y
+C Z
+C Y
+A X
+C Z
+C Z
+B Z
+A X
+A X
+A X
+A X
+B Z
+C Z
+C X
+C X
+C Z
+A X
+B Z
+B Y
+C Y
+A Y
+C X
+B Z
+A Y
+B Z
+C Z
+B Z
+C X
+A X
+B Z
+A X
+A Y
+C Y
+B Z
+B Z
+C X
+C Z
+C Z
+C Z
+A X
+B Z
+A Y
+A X
+C Y
+A Y
+B Z
+A Y
+C Z
+A Y
+A Y
+C X
+A X
+B Z
+A Y
+B Z
+C X
+A X
+B Y
+B Z
+C Z
+C Z
+B Z
+A X
+A X
+B Y
+C Z
+C Y
+B Z
+C Z
+A Y
+A X
+C X
+C Z
+A X
+A X
+A Z
+C X
+C X
+B X
+B Z
+A Y
+C X
+A Y
+C X
+C Z
+A Y
+B Z
+A X
+B X
+A Y
+C X
+C Y
+A Y
+C X
+B Y
+C Y
+A X
+B Z
+A X
+C Z
+A X
+A X
+C Z
+C Z
+B X
+C X
+A Y
+B Z
+C Z
+A X
+A X
+C Z
+C Y
+A X
+C X
+C Z
+C Y
+C X
+C Y
+C X
+C Z
+C Z
+B Z
+A X
+A Y
+B Z
+A X
+B Z
+C X
+B Y
+A X
+A X
+A X
+A X
+B Z
+C Z
+B Z
+B Y
+C Z
+C X
+C Z
+C X
+B Z
+C Z
+A X
+C Z
+C Z
+A Y
+C X
+A X
+B Z
+A X
+B Z
+B Y
+A X
+A X
+A X
+A Y
+C Z
+A X
+B Y
+A Y
+B Y
+C Y
+A X
+A X
+C Y
+A X
+C Z
+B Z
+C X
+C Z
+A X
+B Z
+C Z
+B Z
+B Z
+B Z
+C X
+C Z
+A X
+A Y
+C X
+C Z
+B Z
+B Y
+C Z
+B Y
+B Z
+C Z
+A Y
+B Z
+C X
+C Y
+A X
+B Y
+A X
+C Z
+C X
+C Z
+A X
+C X
+B Z
+B X
+C Z
+B Z
+A Y
+A X
+A Y
+C Z
+C Y
+A X
+B X
+A Z
+C Y
+C X
+C Y
+C X
+C Y
+B Z
+C X
+B Y
+C Z
+C Y
+B Z
+A Y
+B Y
+C Z
+C X
+B Z
+A Y
+C Z
+C Z
+C Z
+C Y
+C X
+C X
+B Y
+C Z
+A Y
+C Z
+C X
+B Y
+C X
+B Z
+B Z
+B Z
+B Z
+C Y
+C Z
+C X
+B X
+C Z
+C Z
+C Z
+C X
+B Y
+B Z
+C X
+A X
+C Y
+B X
+C X
+C X
+C Z
+A X
+A X
+B Z
+B Z
+A X
+C Z
+A X
+A Y
+C X
+B X
+C Y
+C Y
+A X
+A X
+C Z
+C Z
+B Y
+B Y
+B Z
+C X
+A X
+A Z
+C Z
+B Y
+C Y
+C X
+C Y
+B Z
+C X
+A X
+A X
+C Z
+C Y
+B X
+C Z
+B Z
+A X
+C X
+A Y
+C Y
+C Z
+B Z
+C Z
+A X
+C Y
+B Z
+C Y
+B X
+C Z
+C Z
+A X
+A X
+C X
+C Z
+C X
+C Y
+C Z
+A Y
+C X
+C Z
+B Y
+B Y
+C Z
+A X
+C Y
+A X
+C X
+C X
+B Y
+C Z
+C Z
+A X
+A Y
+C Z
+B Z
+C Y
+A X
+A X
+C Z
+C Z
+A X
+C Z
+C Z
+B Z
+B Z
+A X
+A Y
+A X
+C Z
+C X
+A X
+B X
+C Z
+C Z
+B Y
+A X
+B Z
+C X
+C Z
+C Z
+C Z
+C X
+A Y
+A X
+A Y
+A X
+A Y
+C Z
+C Z
+B Z
+B Y
+A X
+B Z
+C Z
+C X
+C Y
+C Z
+A X
+C Y
+B Y
+B Z
+C Z
+B Y
+C X
+C Z
+B Y
+B Z
+B Y
+C X
+C Z
+C X
+C Z
+B Y
+B Z
+C X
+A X
+A Y
+B Z
+B Y
+A X
+A X
+C Z
+A X
+A X
+C X
+A X
+C Z
+C X
+A X
+B X
+A Y
+C X
+A X
+C Y
+A X
+C Z
+A X
+A X
+C Z
+A X
+A X
+C Z
+A X
+B Y
+B Z
+A X
+C X
+A X
+C X
+B Z
+C Y
+A Y
+C Z
+B Z
+A X
+C X
+A X
+B Y
+C X
+B Y
+B Z
+A X
+B Z
+C X
+B Z
+A X
+A X
+C X
+A X
+C X
+A Y
+C Z
+A X
+B Y
+B Z
+C Z
+C Z
+A X
+C Y
+B Z
+C X
+B Z
+B Z
+C Z
+A X
+C X
+C X
+A Y
+A X
+C Z
+B Z
+A X
+B X
+A X
+B Z
+B Z
+C Z
+B Y
+C Z
+A X
+C Z
+C Z
+C Z
+C X
+A X
+A X
+C Y
+B Y
+C Z
+B Y
+A X
+B Z
+A Y
+C Y
+B Y
+C Z
+C X
+C X
+A X
+B Y
+A X
+A X
+C Z
+C X
+C Y
+A X
+A X
+A X
+C X
+B Z
+B Y
+A X
+B Y
+C X
+C Z
+B Z
+A X
+C X
+C Z
+B Y
+A X
+C Z
+B Z
+B Z
+A X
+B Y
+A X
+B Y
+C Z
+C Z
+B Z
+C Z
+C Y
+A X
+B Z
+C Z
+A Y
+C Z
+B Z
+B Z
+C Z
+B Y
+C Z
+C Z
+B Z
+A Y
+C X
+C Y
+B Z
+C X
+C Z
+A X
+A X
+C Y
+A Z
+C Z
+C X
+B Z
+B Z
+C Y
+A X
+A Y
+C Z
+A X
+A X
+B Z
+A X
+C X
+C X
+B X
+B X
+A Z
+B Y
+A X
+A Y
+C Z
+A X
+A X
+B Z
+B Z
+C Y
+A X
+C Y
+C Z
+A Y
+C Y
+B X
+C X
+A X
+B Z
+A X
+A X
+A X
+A X
+A X
+B X
+A X
+C Z
+B Z
+B Z
+B X
+A X
+C Z
+B Z
+C Z
+C Z
+C Y
+A X
+C Y
+C Y
+C Z
+A Y
+C Z
+A X
+C X
+C Z
+A X
+A Y
+C Z
+C X
+A X
+C X
+B Y
+C Z
+B Z
+A X
+C Y
+B Z
+B Y
+A X
+C Z
+A X
+B Z
+C Z
+C Y
+C Z
+A X
+A X
+B Z
+B Y
+A X
+C X
+C Y
+B X
+C Z
+A Y
+C X
+B Y
+B Z
+A Y
+C Y
+C Z
+C Z
+C X
+A X
+A X
+C X
+C X
+C Z
+C X
+C X
+B X
+B Z
+B Z
+C X
+C Z
+C X
+A X
+A X
+A X
+C Z
+C Y
+B Z
+C X
+C X
+A X
+C X
+C Y
+A X
+B Y
+A X
+C Z
+C Z
+B Z
+A X
+A X
+A X
+B Z
+C X
+A X
+B Y
+B Z
+C X
+B Y
+C X
+B Y
+C Z
+B X
+A X
+A X
+B Z
+A X
+A X
+A X
+B Z
+A X
+C Z
+C X
+C Z
+A X
+C Y
+C Y
+C Z
+C Z
+C Z
+A X
+C Z
+C X
+C Z
+C Z
+A X
+B Z
+C X
+C Y
+B X
+B Z
+B Z
+A X
+C Y
+B Y
+C Z
+B Z
+C Z
+C X
+A Z
+C Z
+B X
+C X
+C Z
+C Z
+C X
+C Z
+C Z
+A X
+B Z
+C Z
+C X
+A X
+B Z
+C Y
+C Y
+B Y
+C X
+A X
+A X
+C Z
+B Z
+C X
+C X
+C X
+B Y
+C Z
+B X
+C X
+C Z
+A X
+A X
+C Z
+C Z
+C X
+C X
+C Z
+A X
+C Z
+C X
+C Z
+C Z
+A X
+C Z
+A X
+A X
+A X
+B Z
+A X
+B Z
+C Z
+C Z
+A X
+C Z
+C Z
+B Z
+C Z
+A Y
+C X
+A X
+A X
+C X
+A X
+C X
+C X
+A Y
+B Y
+C Z
+B Z
+C X
+B Y
+C Y
+C X
+C Z
+A X
+C Y
+B Z
+B Y
+A X
+B Y
+B Y
+A X
+C X
+C X
+A X
+A Y
+C Y
+B Z
+A X
+B Z
+A Y
+B Y
+C Z
+C Z
+C Z
+A Y
+B Y
+B Y
+C Z
+B Z
+C Z
+A X
+C Y
+A X
+B Y
+B Z
+C X
+C Y
+A X
+B Z
+B Z
+A X
+B Z
+C Y
+A X
+C X
+C Z
+C Z
+A X
+C Y
+A X
+C X
+C X
+B Z
+B Y
+A X
+C Y
+B Z
+B Y
+A X
+C Z
+A X
+B Y
+A X
+A X
+A X
+C X
+A X
+C Z
+B Z
+C Z
+A X
+A X
+B Y
+C X
+C Y
+C Z
+A X
+C Z
+B Z
+A X
+B Z
+A X
+B Y
+B Z
+C Z
+C Z
+C Y
+C X
+A X
+C Z
+A Y
+A X
+B Z
+B Y
+A X
+C X
+C Z
+B Z
+A X
+C Z
+C X
+C Y
+A X
+A X
+C Z
+A X
+A X
+C X
+C X
+A X
+C X
+C Z
+A X
+A X
+C Y
+A Y
+B Z
+C X
+C X
+B Y
+B Z
+A X
+B Z
+C Z
+C Z
+A Y
+C Y
+C Z
+A X
+C Z
+A X
+C Y
+C X
+B X
+B Z
+A X
+A X
+B Z
+A X
+C X
+C X
+A Y
+A X
+A X
+C Y
+B Z
+A X
+B Y
+C X
+B Z
+C Y
+B Y
+A X
+C Z
+B Y
+B Z
+A X
+B Y
+C X
+C Z
+A X
+B Z
+A X
+C Y
+C Z
+A X
+A X
+C Y
+C Y
+C X
+A Y
+C Z
+B Z
+A X
+A Y
+C Z
+C Z
+C Z
+C Z
+B Y
+A Y
+A X
+A X
+C X
+A X
+B Y
+C Z
+B Z
+A Y
+C X
+C X
+A Y
+A X
+A X
+C X
+C Z
+C X
+A X
+A Y
+C X
+C Z
+C X
+A X
+A X
+C Z
+C X
+A X
+C X
+C Z
+A X
+A X
+C Z
+B Y
+A X
+C Z
+C Y
+C Z
+C Z
+B X
+B Z
+B X
+A X
+C Z
+B X
+C Z
+A X
+C Z
+A Y
+A Z
+B Z
+C X
+A X
+A X
+A X
+A X
+A X
+C Z
+A X
+B X
+A Y
+A X
+C X
+A X
+A Y
+A Y
+B Y
+C X
+A Y
+A X
+C Z
+C Z
+C Y
+B Z
+C X
+C Z
+A Y
+C X
+C Y
+C X
+A X
+B Y
+C Z
+C Z
+A X
+C Z
+B Z
+B Z
+C X
+C X
+A X
+B Y
+C X
+C X
+A X
+C Z
+B Y
+C Y
+C Z
+A X
+B Z
+C Z
+B Y
+C X
+A X
+B Y
+B Z
+A X
+C Y
+B Z
+C Z
+C X
+A X
+C X
+A X
+B Y
+C X
+A X
+C Y
+B Z
+B Z
+B Z
+C Y
+A X
+A X
+A Y
+C Z
+B X
+B Z
+A X
+A X
+C X
+A X
+C X
+A X
+C X
+A X
+A X
+A X
+A Y
+A Y
+B Y
+A X
+B Y
+A X
+B Y
+B Z
+B Y
+A Y
+C Z
+C Z
+C Z
+C Z
+A X
+C Z
+C X
+C Y
+C Z
+B Z
+B Z
+B Z
+C Y
+C Z
+B Z
+C X
+A Y
+A X
+C X
+C Y
+A Y
+B Y
+C X
+C X
+B Y
+C Z
+A X
+C X
+C X
+C X
+C X
+C X
+C X
+B Z
+C Y
+A X
+A X
+B Y
+B Z
+A X
+C X
+C Z
+A X
+B X
+B Z
+C Y
+B Z
+C Z
+C Y
+A X
+C Z
+B Y
+C X
+A X
+A Y
+A X
+C X
+A Y
+A Y
+C Z
+B Z
+C Z
+C X
+C Y
+B Y
+A X
+C X
+C Z
+B Y
+A X
+B X
+B Z
+C Z
+B Z
+B Z
+A X
+A Y
+A X
+A X
+B Z
+C Z
+A X
+A Y
+C Z
+C Z
+C Y
+A X
+B Z
+C X
+C X
+A Y
+A X
+C X
+C Y
+C Z
+C Y
+C X
+A X
+B Z
+C Y
+B Z
+C X
+A X
+A X
+C X
+C Z
+C Y
+C Y
+A X
+A Y
+C Z
+A Y
+B Y
+C Y
+A Y
+C Z
+B Y
+C X
+A X
+B Z
+C Z
+A X
+A X
+B Z
+C X
+B Z
+C Z
+C Z
+A Y
+A X
+C X
+A X
+B Z
+C X
+A X
+A X
+B Y
+A Z
+B Z
+C X
+C Z
+C X
+C Z
+C X
+A X
+C Z
+B Y
+C Y
+C Z
+A X
+C Z
+A X
+A Z
+A X
+A X
+C Z
+A X
+B Z
+C X
+B Z
+A X
+C X
+A X
+C X
+C Z
+B Z
+A Y
+C Y
+C Z
+C Z
+C X
+C Z
+A X
+A X
+B Y
+B Z
+C Y
+B Z
+A Y
+A X
+A X
+B Z
+B X
+A X
+B Y
+B Z
+C X
+A X
+A X
+C Z
+B Y
+C X
+B Y
+A Y
+A Z
+A X
+B Y
+C X
+C Z
+C Z
+C Y
+C Z
+A X
+B X
+C X
+A Y
+A X
+C Z
+C Y
+C X
+B Z
+A X
+C X
+C Z
+A X
+C Z
+A X
+C X
+C X
+A Y
+C Z
+A X
+C X
+C Z
+C Y
+A X
+A Y
+A Y
+C Z
+C X
+A X
+C Z
+A Y
+A Y
+A X
+B Z
+C Z
+B Y
+C Z
+B Y
+C X
+C Z
+B Y
+A X
+A X
+B Z
+A X
+C Z
+A X
+A X
+B Y
+A X
+B Z
+A Y
+A X
+A Y
+C Z
+B Z
+A X
+B X
+B Y
+B Z
+A X
+A Z
+B Y
+B Z
+C X
+B Z
+A X
+B Z
+C Z
+B Y
+C X
+A X
+A Y
+B Y
+A Y
+C X
+C X
+B Y
+A Y
+B Z
+C Z
+B Z
+A Y
+A X
+B Z
+B Z
+A Y
+C Z
+C Z
+B Z
+C X
+B Z
+B Y
+B Z
+B Z
+A X
+A X
+C X
+C Z
+B Z
+A X
+B Z
+C Y
+C Z
+A Z
+A X
+A X
+C Z
+A X
+C Z
+C Z
+C Z
+B Z
+A X
+A Y
+B X
+A X
+A X
+A X
+C Z
+B X
+B X
+A X
+C Z
+A X
+B X
+A X
+A X
+B Z
+A X
+C Z
+C Y
+A X
+B Z
+A X
+C Z
+B Z
+A X
+A X
+B Y
+B Y
+C Y
+A X
+B Z
+C Y
+A X
+C Z
+B Z
+A X
+C Z
+B Z
+C X
+B X
+B Z
+C Z
+A X
+B Z
+A X
+A X
+A X
+A X
+C Z
+B Z
+B Y
+C Z
+A X
+C Z
+A X
+C X
+C X
+A X
+B Y
+C X
+B Z
+A Y
+C Y
+B Z
+C Y
+C X
+A X
+B Z
+C X
+B Y
+A X
+A Y
+B Y
+B Y
+A X
+C X
+C Z
+B Z
+A Y
+A X
+B Y
+C X
+B Z
+B X
+C Y
+B X
+C X
+B Y
+C X
+A X
+C Z
+B Z
+B Y
+B Y
+A X
+A X
+A Z
+B Z
+B Z
+C X
+C Y
+A Y
+C Z
+C X
+A X
+C Z
+C X
+B Z
+A Y
+B Z
+C Z
+B Z
+B Z
+C X
+B Z
+C X
+C X
+B Z
+A X
+B Y
+B Z
+A X
+C X
+A X
+C Y
+A X
+C X
+B X
+C Z
+C Y
+C Z
+B Z
+C X
+A X
+A X
+A Y
+C Z
+C Y
+A Y
+C Z
+B Z
+C Z
+C Y
+A X
+A X
+C X
+C Z
+C Z
+A Z
+C Z
+A X
+B Z
+C X
+C Z
+A X
+B Z
+C X
+A X
+A Y
+B Y
+C X
+A X
+A X
+C X
+C Y
+B Z
+C X
+A X
+C X
+B Z
+B Y
+A Y
+C Z
+A X
+C Z
+C Z
+A X
+C Y
+B Z
+A Y
+B Y
+B Y
+A X
+A X
+C X
+C X
+B Y
+C Z
+C Z
+C Z
+C X
+C Y
+C Z
+B Z
+C Z
+A Y
+C Z
+A X
+B Z
+B Y
+B Z
+A X
+A X
+A X
+A X
+C X
+C Z
+B Z
+C X
+B Z
+C Z
+A X
+C X
+C Z
+B Y
+A X
+C X
+A X
+B Z
+B Z
+A X
+A X
+B Y
+C Y
+C Y
+C X
+A X
+B Z
+C Y
+B Z
+A Y
+B Y
+B Y
+A X
+B Z
+A X
+C X
+C Z
+A X
+B Z
+A Y
+C Y
+B Z
+C Z
+C Y
+A X
+C Y
+A X
+C X
+B Z
+C X
+A X
+C Z
+A X
+B Y
+B Z
+C X
+C Y
+B X
+A X
+B Z
+A X
+B Y
+C X
+C X
+C Y
+C Y
+C X
+B Y
+C Z
+C X
+B Z
+B Y
+C X
+A Y
+C Z
+C Z
+C X
+B X
+B Y
+A X
+A X
+C Z
+C X
+C Y
+A X
+C Y
+A Y
+C Z
+C X
+A X
+C Z
+C X
+A X
+B X
+C X
+C X
+C X
+B Y
+B Z
+C X
+C Z
+A Y
+B Y
+C X
+C X
+A X
+B Z
+C Z
+A X
+C Y
+C Z
+A Y
+B Z
+C X
+C Z
+A X
+C Z
+B Z
+B Y
+B Z
+A X
+C X
+A Y
+C X
+C Z
+B Y
+C Y
+C Z
+C Z
+A X
+A X
+A X
+C Z
+B Y
+C Z
+A X
+A X
+B Z
+B Y
+B Z
+C Z
+B Z
+A Y
+C Y
+C Z
+B Y
+A X
+A X
+C Z
+B Y
+C Z
+A X
+C X
+B Y
+A Y
+B Z
+A X
+A X
+A X
+B Y
+A X
+C Z
+B Y
+C Z
+B Y
+C Z
+C X
+C Y
+C X
+A X
+A X
+A X
+C Z
+C X
+C X
+B Y
+A Y
+B Z
+B X
+C Z
+B Y
+A X
+C Y
+B Z
+C X
+A X
+A X
+A X
+A X
+C X
+B Y
+A X
+A X
+B Y
+A X
+B Z
+C Z
+A X
+A X
+A X
+A X
+B Z
+A X
+C Z
+C X
+C Y
+B Z
+C Z
+A X
+C Y
+C Z
+A X
+A X
+C X
+B Z
+C X
+B Z
+C Z
+A X
+A X
+A Y
+B Y
+C Z
+B Y
+A X
+C X
+C Z
+C Z
+C X
+A X
+A X
+C Z
+A X
+A Y
+A X
+A X
+C Z
+C X
+C X
+C Z
+C X
+A X
+C Z
+C Z
+B Z
+A Y
+A Y
+B Y
+A X
+A X
+C X
+C X
+A X
+A X
+C X
+C X
+B Y
+C Z
+A X
+B Y
+A X
+A X
+A X
+C X
+C Y
+B Z
+B Y
+B Z
+C Z
+C Z
+C X
+C Z
+A X
+B Z
+A Y
+C Z
+B Z
+A X
+C Y
+B Z
+C Z
+C Y
+A X
+B Y
+C Z
+A X
+A X
+A X
+C Z
+C Z
+C X
+A Y
+C X
+B Z
+B Y
+A X
+C X
+C X
+A Y
+A Y
+A X
+B X
+B Z
+B Y
+B Y
+A X
+C Y
+A X
+C Z
+C X
+C X
+C Z
+B Z
+B Z
+C Y
+C X
+B Z
+C Z
+A Y
+C Y
+A X
+B Z
+A X
+C Y
+B Z
+B Y
+C Z
+A X
+A X
+C Z
+B Z
+B Z
+C Z
+C Y
+C Z
+C Z
+C X
+A Y
+A Y
+B Z
+C Z
+B Y
+C X
+C X
+A Z
+C Z
+A X
+A X
+C X
+A Y
+C X
+A X
+A X
+A X
+C Y
+A X
+B Y
+A X
+B Y
+A X
+A X
+A Y
+C X
+C Z
+A X
+C X
+B Y
+B Z
+B Z
+A Y
+C Z
+C X
+C X
+B Z
+B Z
+C X
+B Y
+A X
+B Y
+A X
+A X
+C Y
+B X
+C X
+A Z
+A Z
+A X
+C Z
+C Y
+C Z
+C Y
diff --git a/data/day03.txt b/data/day03.txt
new file mode 100644
index 0000000..fdd6d17
--- /dev/null
+++ b/data/day03.txt
@@ -0,0 +1,300 @@
+mjpsHcssDzLTzMsz
+tFhbtClRVtbhRCGBFntNTrLhqrwqWMDMTWTqMq
+LltbngLGRSBgSgGRCJdSdQHvdfmQccmjSQ
+lBslsZDDWdGdGpSMts
+grQhDvqLQHDNGJJtbRMQQJ
+HChCTnnLCgCrTZPPFzzVPcVD
+ShrzjhNGrNqrhWnHHfVHbhnHbbhH
+RBsvcBcDCdsRTsvgCgcPFRQpVQGQJPVFbnJfbJ
+DvsTsdlCBsGLrjzmlqqz
+WJJqZTgCnBLGCZBJCJnTLggTDDSDDMNdDSdbdSSsWDFfMsFf
+PVjqpVHmPpvmcjhrRprFmQQffbfNbQMMsSMQNQ
+cwcpRvrVlVgwtBwZqBzZ
+qfJJmpqpmhsggvvpVPZCrhdFLFzZFDdLLh
+CtCTBctGcGLSzZddGZSW
+RlNjBCnjttBHHMMcQHCsRfsbfwgggmmJvmgfpm
+ZmcgBBZhZMsnqnCPjpHPjLHp
+dGbNwNtlTMTzGfNvTvdwNGVLPpQHPjLQPCpCjPqjLbpLPR
+dvDTdfvNBhDZMBDZ
+cvvRvbqcllbBVlvVVbVVlbVDjRjDjdMsHPZPGdDPGPHrDP
+FwtpfwJtWwNtTTNnwFCtjDJsQdQPPPPMrjrPJHjH
+CwFpnppgntShgbsscbms
+cWMFMQpFNcvNDdBDgdsT
+MPrrfrCHBBsDZCBJ
+LmLjMLjjLWpVcRVR
+ZrRZqlZMqTWrMDqwvnvVtnsvddvVnlVf
+pQNhhLNNGmLjhhcfvndDpffdfdVf
+QGjCLCQGmNgPBQDFFgTMJWWwMRTrTZWWBWTr
+WrZWZPHHWZHprZVmVvqddBttBBhGhtvh
+gzDlMTJDMfqhBGllhl
+jJLqMMDDbbqjLpPHcsHLWZspPr
+bsSVRVGsrDstrrSjcQjcjlPwzjQl
+gHBggFNTTvTgfqgCFzljWwLWQQQnrwQWnf
+NvJHgpgHvqBhNBJhHTvpBCJCZmtdpDsGsZdZMZRbVbbMdrZs
+MPPtPwPnRnMPPnwrtNSGgLSCGGGNSLtSgD
+hBhWFjfCsTbbbWqFFWBBqBhsWZVGSVglZHLSVDlNWDNHHGgV
+zsCfTsTCMdmRPwzQ
+JVQVvvszzvTsVsVJjctppcCtjtPRcTlP
+MdFgqSddMqMDbtDlNjRDSR
+qFZWZqwHlZfZvzvZfLZn
+vpqwQSsHSHDQzDpgzwZlRLRZRRZTnTrrvGhh
+JBcdmbmFMPgPbgfrZRZnRFFnrnLRln
+JNdBNgbdJmPMWSSDzwVDtwSWWW
+BDMcDDppHCStpWcHBDNtzPJjqGlllPMJzPGjwjlq
+CZdZLmgCdqbPzjblZj
+vndLfnghRQmVrhdvgBHpSCDWHBBCVHNppD
+WrhrJJGSWzpTWwts
+VlLPmqgmRNZRGwsvttjgcwsT
+PDZmlbdVqLmPlddVNRDmmmbbSFHrCFQCnFBFJHSJGrDQCBrr
+hvPdpvhHvHvPrNfVhDfjggFfRV
+zlGwJGslsSDRfjsg
+MJMWjMJzwqWGzJwMqJBTCmHndPPdCBvmdCpmHn
+PVWFpQhJhFJpGbRCvRHGCp
+jgslDjftsqhNglTgllgTqMnlHwCcvwZwRccSRCbGSGbCMHRw
+TgjhNNnjlTfjTdDqTfhjnmzmWPzWrLdrQBPJFWJWBB
+qPPRMPlfSzSSSPPnnLnqMlpQQtrrtmWpbFtQrdzrtrWt
+BBvCcwsVThsBgswDBCFQHQpdmQvtrFpWFvWp
+gCghTJgVCgDGVMlRGMqZnSWqlM
+RWbHvrbHBsbWBHJWvJwMtmdZwdtmdvwMZQff
+DRVjcqhRchhGGllhCgdGQQzfttzGQGwQfg
+cDRljchpqTcjDFTFVcPcPCWBHpNnJNNSnbWbHHrSpWHr
+dtHrRrBHrCRhddftjgBrRhgjsbbbMpbSWSTjWcsDTWDbcW
+GQPFVQVQnJlqVMDcMzpDfzpDVD
+qZZJFLlLnvFFGPGLPqnJvwQldfgHrBRBmBhgNBRHghNhhwRg
+rLbrZhPgqZhMdVFSFTSGCqFG
+zsszfRzjtHtzvRTSDdFFCtdDdtND
+fcwllfmwzRHlfmmzFvQQLrgLMLBZhJQZPrZhJLhW
+sllrCfpQQJpMHLgzwDwpNqzzVDpV
+RZPFZPGcSMFtGPRGMwNDVwdRgzvNwgqNvg
+hBmbMcBmcThmcGtSFTZfQCJjrHLJfsjhWJssJl
+DqGCbGfCRhfZCVbbqDJJGJBgRNpNdpBNNgNBBNwHnRgt
+rcWSsSSPSQtwBwHD
+MLscLMzvvTvcTLzvWWFDPTTrGqmFGGqCZJGbblbVbVZZVmFJ
+FprpsLQTrstQHNmVSVml
+JMggWPggWcRbwgJPCGMcGcfmzHlMNSjfzVNhHfVtzSMz
+cwnPnBwgnGRgRCgRbWJLpFsLtFBLFrDLFZZDrL
+lVgjLLLMgFMDCwCFqCRbngsvnGSvnSGndbsfgf
+WZJcTWcNTmJZphmTJJNQHcdvfdbvnRRGbGthdrbttfSv
+ZPQTJTpTNPJNQTmJRBZJNBHjwMVwPCMwVlVzjwwzqqjVjL
+hznNhNQNQFDWVFmDQm
+SMqZBMMbBvDbHPzzdVPH
+zzzTBTMLNTgpnTTh
+NLCdmsdCVLGHCHdQzzmznnFwRjFMDMwpTBjDRpnpTBMJ
+PrcfcrglcfWbSqgrlqvShrwpJpDBFJHpBWjTDTRTRTTB
+crSgSHtPttfdLGmtzzZNNV
+BTlTVqCBqtTcBqVhWlsJjDvsnLsvlvpJPj
+gMgggGZbSMzNRRRLmZZnQZQPPDvnsnDvJwwQ
+dMRRmMgbNfRgmfSdGFgNgTBtrhrhqfWtLCCWLTWWHc
+zcfVrPwnwrPmrvnjdFdBbHFFdd
+CCqpSSQQpQZLDCSHPpBFvFBjTHRvRR
+DMLGthLZMLtQGhGNMPqGSDflzfwcVmzJzsfgNVrswcrr
+hSgvMTQvChSqPvhTrRLlVHJgfgRJlHHHJH
+jmzsZzZzwmmLGGtwtVJWNNDRDtVcfVRl
+GnBBLbzzzFszBFpzvSdrQQCTCQbhMvSQ
+VHpTMrZMMbDbbpTZmQmTnmzhTqjqlWWQ
+GGvgNsvNCNvvGvlqqdzWZmlsmZqZ
+wNNNgccNGJSNBSRNBNvNcvJHLDDZMFRMppMLrfHDLbrrHF
+spssbPMLpPllspGNsNWMrnwddnfcqrnwwwwMwM
+VmQBFCjzzjmfnwbrngcVrd
+FQbSFjBvvzsWvWGlvWNl
+JLFSwfwRLLfGhnQJBQshvn
+pZgNcpCWpWtcvhjGGjtVvszD
+CccMcPcgTTCWmcZcWMcmTNZPmHdrqSHFRRrqwrSrRqwrHmsH
+BPMhflJRhqnPNGjNRNRjgSRm
+VdVsDswTVZbCwCZBrcDCczTwtjtNNjmjmgpmjpQggpGVSgQm
+sTbWrsTBbrTPPnqlJnPPhW
+nvrgjMWBvQWPvQnsZfGcZcRFdGFtdtZB
+bHVDwmqNNDhHNzqpphLNHVLpSJcdZtfffRZdDgRFGSddcRZt
+HNLNqNqLNbhqVVbClngjnQWPTWgsCgvT
+tfstpcScscBTFTpFnsWSmgdzJlgmgBmPPzJmvdPm
+jnrqrLHRwGrwhdPvvPvhjJmP
+qqCLRCGrZZqCHRVtVWQptFWppnbcWb
+wCDJZJgDwHpdqHhdGHBhhH
+WSPmJMlmbSmztQlQsvPhnhGGdBddBqdGddTbVB
+WzWQftWMSWtmvmmSWtMQPgggpZwLwZjggJFgrpFCfj
+MvQBJMBQhjQFNFnjnj
+dtlZmRtLmjSTSLLtTtNVwWzDRzDVwwWFwnNn
+dmmLCqTdcLqtLGqjBhpfHqBGpv
+PBPRhjTPPlLRBvlvfwffqJGfpG
+rHtMtrszFtSgbFrrggrFgMnwWGzmQqWvGWzGQpJGfNqqNz
+FggcbSMntVgMdRCwZcjChLCT
+lCqqBlCwlnDqPZTZZBLNdjJLwttNWjjdzJzc
+fVfMbvbvmbVsmSsmMVWNtzzcjgLWgjztMMtg
+VVmFhFRSfbQsvVQmvSfhSsmzHlCZqrrBrDBrHZPRTZnnzB
+CRrDWmzRRQMmDqrrBgBQmtHljhHwtwlwplcBjHGwwB
+PWfPSWnvsNZSZdfjHjZtGHjchllltl
+WVsnbSPTbNdbmqTQmmrmLzTq
+cGtMBGSJDgtgMBsBMgMvWWSHWjpjzHTWTPpqWzqW
+mNVQNsdVsdhLmCpTWWjmCjTT
+NQQwrfbQrNQNbrrdLwfQsZdgFbBBFBgggRGRDMRFFMRDgM
+lFnqgqWQvHWqgvlVglvqjPjcLdfLfBPLnrbLNLcN
+hmTmthppsRtpTRRTZMpSbLdNjNcJLcrcBNbJBZZc
+smmpRsTtpSSsRGhppmmhdCMGWwqFQgWGWWDgWwVFHQqHgg
+mWFjmcdcFWcSSQjzrpvrwRGvTwQGGG
+HRJfgMZVhtRlHJHBVJTGvGppbpbvvGTvTtrv
+glsgVMVqffdnPRDcqLnL
+MtvLJdmLLTvSSCtSzLSTcDhRjRftQjjssshfQNjPtf
+nlggrFWzRsfFjVQN
+WgwwBgbgZBHGBnccTzMCLTZJmLLL
+sRtHTBBHZtDTtZhdPzWdGcdVFdJmGcnm
+wpwMLWCgvfNvwvwbbCrwgfzPncrJPSFVGPnrcJSVznmV
+bLpvwQwMwpjWMgfvgZTsDsBttqHRjTqHlH
+mpmGpCpmlpmwfmCQVppCVfQSSjvSqgWvvvDgNwWDgnnDnW
+RBLsHRJBRrHJWFDWSNqFWj
+zZBLdsdcZrsBjGfpGVpTTPGlVc
+NBbTzgwSNmrFWpVrzrFM
+LnZQtQlZVnMrFBBG
+CCdtddBtPdNqcvHSCCcg
+ZFbZPHbZPTQVVlsGNF
+qtvDWvgRftqGNccCNVThDs
+fRwGBBjBppdMdBMZ
+GffflsZsPZVfjsssNfZsJNNZVcMDSqMWFcwFMMpcTMTTFSTS
+LhrCmvzcRbbhtmRdTCMDwWMpDWqqqMpW
+dvRQmBBvLzBRRvRhhcdbhdRgjHQNllJsfsNlZZljZGGNQN
+wjbMPsbfLzVCTMVbjLplmpshhSpHShhJhtsm
+ZrcqZTDTGDqFdJtGmdGSpl
+QNNrWvQRqRNWnTQRvqjPbjfWbCBCMbMLBwMV
+wRPRsppFfWJRlPRPFlpJfwSMzzZTBwBtZTTCMCMtdz
+vGLGrjcfrLVGjfnGTMCMtNNnCTnMtCBd
+VrjqhjhLVcrGVRqJmqQspmfFWm
+LRfdnmwMwdSBmfvJNrrgLhCNgqqJWs
+llctPPVTcPStgJgshCsrCs
+DpTlFpFVRFZRFFSv
+sPgRgsmdcqmgSvvFRRRRdqdFfTWZhhdZrZbbWfTpwDfbWTbw
+jLCCHtLljJzjlplfZSlwTfprZZ
+tBHVjQHzHQJBtSVmvRsvvFRqnGgv
+spppVDbVcbgVSFgFZZbGZgbJMRBTvHTvJJHGtHRwtMGvHT
+LldflzQLLQmQWQQfnwMWwHJtTtwRBcBt
+CPjfhCmNmNfFVchpchFVhp
+bZQJgQmQmTgnLBRtNPNnml
+ccszcqldGzhszrVsqdlHVNwLpppwHPHRtBBppDNRLt
+VSzVhVdcfrrhcqGrVhrssQQlMbJvFjMgbFSQggCvCv
+hHWVWhhlZDZVWNTgczWLjbtcTFFj
+JJnPnCdBCBnnRCjSsjStBgsbFttb
+MRpgCpGqdPRppJwpnRqRfZZhmvhHDrhllDHhhZGZ
+SPcgLDcLLnWFWCNVCRPT
+fhZQtsbtmbmfZTVTVRWfNvTCTT
+jhbbmzRsQzpLDcgLHLjg
+GSFRHrCCGRJDJtrgWdrL
+stcVQshQZBsBmjMsZhmMQQWDDvNWdncNWvzLgdDnzdDN
+sVwMBQBhVVjtQZVPlSfPCfwRpSCpRl
+bBHHJMJvBvWMJWqqccNNPhMCrclChQCC
+RPppPgfpwgmcQgrhmm
+tfwTwpFPGGwZSRtpVjJHbHLvSvLSqVLL
+jlJfZGjljJPBqJGnfGVMqGfrFWWddvDmFRDcmdFDdDvbDM
+hTCTsgsgwhTbvRdcFmsddpFd
+wbQNHTQLgCwSThhCgwnZnJfqnqJBlNlBnnVl
+CLlfbjjbLlbbDGbLzfCGhdtdWBthdBWsHvWHBnntWs
+rmJRJFqrDwVFTwFmSJvtvMtdJMMHBdBBndWt
+ZVrVVZpgTpZFSqmZqRNlNNfQQbpGjDQbbpPl
+mVCrhGHGmZhrNlDwbWnLWWvGLWWwnd
+PNsqgzspsgNFJNFfzqpWSWdwSvSPnvdWbSbvjd
+NzgJzqMcgscQqJcpJRzBmlrBRBDDlHZBBBHtHZ
+NJmNJDwcMmJNMbJJDNDqcGcsWRWHQzRPQjZLRGZWLQsjZQ
+dgSnTBgdpddtgShSTZjLRhRLHqWPPhPRPQ
+VgdTpBntlvBVrlfcbqJcMrfmcqmb
+wvqwvPwNJgFmLdvDJFDmDLvJlQZpMzSpBVflpdSSMlQnfldS
+WjCcRZCWRjjRtsZhRRhpSVBVnzplBfWnfBfSQz
+CbRbcsjHZrhbTRtsGbCrgNgDDPFFqvvJvJFDFw
+GlsCrbCChShqgqlbSCcVbqgVhBwjBDFBhBhdDWvwBFFvWvDv
+THmHMmtMnLfHRnzRZnfLBDWWsWzWFNsvWjjvjvFF
+mpHRtmZffHTTMpmLMLLnJtJCgScScsPlblcpCrPbblCPlq
+vscDLrcvrsLNStdTfBCvgJTqGBdd
+bwLbzRhbbdTfbgCB
+pplQzLwmPZVMStcDjFtQrS
+RMjCrhFJhRVRVCCFFsvmnvqrmbvqmqSmbrvm
+tzfpBgTHzttGzZpBfHGDBZHbccnGqbmvdNlGnSnlcvSwbn
+pDWTHDTzgTfWZpVVsWSPjRFSMsFs
+fmrfmrwVfjmrzjqCsqqvjsvvpG
+hFDVtFStVtJnPPtJNHbtQWGbQsCvCsQgpWGggdQC
+NBSDSNHStHNHnhStHNNrcflrmTzBlwmzrlMVVw
+SjtZZSdNcDldPQqndl
+BbgzgWgTmTBfwrbnDjQDwVPwDlnsVq
+zBBrCTTMBWLMWmfMfbbmrMtjNZLFJRRZSSvFFtStvGGJ
+CTCGLGCFRRSMGnZnLCTfdffhpbNbDfpdZBvhdv
+rJlqclVPHJWVrgPPQqjqgJlhBhDBBQdvbhwvNfhswfNpvb
+tltrcrHjlVWVCDzSGCCzLCGt
+sbHHsbCCHbLSVfJbbfSLNJBzvzMMPrhPPNztZlZNZhdt
+GTWjplTgDnGmQGpQnQhZrvvBMPztPzvrzvjZ
+mQgGWllcFcTFmgwcDppDQGTCqfsSLqsfSbqJqLSSFsbRfF
+jslsFjLLLLvFwWtQFTFDJQWp
+dGzdrNmRWqVBGcTbwpRDRnbJDRhT
+qzqzrrPNNrmfLPsjglHjgW
+QjCHcPfcgQSgPPcffQSmmmLmrJJpNpBMrJMtFrBBBMFrrpNS
+VGVZfDbbVVZWGvDbFrlBZNJBNlNMwwtM
+sbvfhqTGTRnhTVGvzgHmgQLQmPqzmPLm
+sLwnMHnbnLMjGpZsjGGtpc
+ggvJrNNTQgQrNvgqBqZCCjClWjGtWjCpGJFW
+TVdrqvVrTNTzBqQQzTRMfHbMwMbZMdMbHwRD
+bcfJQQJHsQPCpdpWdPbb
+RHjHDwZtrZmRDDtwtjRBVFdWVrrrBClldVphCF
+zDgwgNzjmDnMnzMMHncG
+vMHRvMhvHWRBRDHhRBwWvRBqLqbGwqnqnnNTbNqdNbbVVr
+pslgcZszJltrsZcZgNnnqbSSTSSndbNbzS
+cZcgsZgZZgPgmcpfJtfttWBQvmFWjDQDhBmFjDHvFr
+bVbBvdTTVLbCgCznLJsJcwHPczfz
+NFcDphSDrFjGtZNZjplZGZFnzPHPrzHHzJMnnwfPsPsRJs
+cGtGljFmWdvqmVCV
+qSNbTvcvTGTvGcgtBNvcbdrdjrnjRnjRVHdDqHrRHj
+ZZZZPLWPzPDCCsCRnRdwVFnjdwPVFP
+ChlCLLZftfcBvfDv
+cRtfctVgmRclmBFGbbMBDDFPtD
+svQZhHSHssjTvjpQjSSBBMJMJGDBpPbMzzpGzP
+ZsvsCTWhCHhSwwjrwbndldlRnfRNmb
+PQdTgdGpRcTccCfj
+hHFLHlHBhBlmlDFzHrhhfZNZbfNZcVWNVVZRDjCC
+LFLLMHJHSBhBFGGnMMvsGtGGtj
+fwmVnVCDVqpNQqqb
+ddBcZZWdvGWzBzsWvLvddlNHcHQPbQqqJQNNQHPHQT
+WgGvsMMzvgbntDhCmt
+JjwhFMmwjJwmCgTgSCSFlPLg
+WWbsbVtftBZWtnWtncbQvctTGLpLgCpzPPPlllpzlgPPTQ
+TBvnfBffWsfVtTvbZBTNjwjqddhMNqwRMMhdRMrq
+SllrbtTSQrSQrbrvvMvzFDsBsssWpWdWbGpGBWNWNW
+hhCfmmmjmPLCfmnPLfqPgqqNNBpjZBZQDNQdpWNpdBBsBp
+RhLfPhQLQfCRnHfqTHHrFJMrttTwTtzt
+BFrFBJMMJnnsNJBFCdLCnmvzbPdCmPnc
+LDLVHQRfDvdHdcCmcv
+llQDwqSVLwZLZSgsGZMNMgTjTMTr
+mrwdbqRhdCNGgZBHbH
+jVTPMjvjpvMfTfQfPlpHHZNnNBHgZDGsGMnCsZ
+TLlfQpffQvvzhtNqztRFtzcm
+DDfvJZZPDHVPSPcSvcgcWCsWQcTTdhQTTh
+dMwpbdjRtrFhhTsTFQWqhC
+bGRdNpbzlvLfDfZlLZ
+bdPQdcpdbpjFqpQcQwqqhhNRhJvWRfrrWBsJrfwN
+mMtlZfmtnLZtSnGDlmGWRRhrWLhJsBRvgRWghh
+DnMGCtmCzfGMbjdQbVzpqcFH
+jwnGggRBvvpBZCljCsCWrhhrsh
+FVMcFLqLMqcJfVtDqMJcHMHWCSblzzrWsdhSLlSzbrGCLz
+HQVFPDtDQDFFNTZpPgNnGgNn
+HNBHNqlqHJQBRNvdmZvmPdZZlpnT
+bDbbhDgSfzVVfnvPmfHmTZZd
+jgzbwrhVsDgsDWLwJqqBMqcqHL
+tzNtJzsJVBHzbjbglCHc
+nfmnGnmPhntCgHvtvmCj
+MStTwrMTWrTdBZSNLZJNVQ
+NVjmwmVGGwGFHstwFHMhTh
+psRSzzscZscZpgQQzqQtBBHTTlThHHtTTh
+rCprbpZccggcrRzbbRRbscvVVWWvNfvVWnGDCWVNddmd
+rphfGDgtPtllrPlFlGrhGjnmnTnjcBsncBBVpTTBmc
+SqqZMJCLwgCwJgQRqqgZQNwdBBsBBHVBdTHNsnVNBTccnc
+MJqZZMbqgzRCSJZwPtFfGzWhrrfGttWl
+cSZqqcwbqVzqCbqVqVZPsvvDCDrffngvphggndhdGh
+tTNTMWJNQJHMNGSSprfdGnfdth
+WNRHWWMJSRWzswbczsVPRs
+HCgcSMhSMBGMdvGf
+RNQqbDQqFdRFdmTZfGtPZvtGlQffll
+mNpdNrRDbTNrmbpzmpWmbpWcswhcHcjhscSHjSgVHwHn
+MwgcFgwMMcscCbMFsMFCgMgPPLWPvptvBvPvtvvWmBBzwG
+nhQQjTJRVDdQJrPpmnGGBmvtGvLz
+HdJQdJHjrJQDBQjhQVQJhdJcqlFHcSqsNbCbCqCHFqCFgC
+JvTnvWtdJLbhJHbMwwHjcGHCwHwQGQ
+mqtmsllmfqVFwMwMrrPjmQrC
+lfztRZSlRDRVzfdpWnSvWhNdbnpp
+rSvrgggzHTNzrHtnptpmlDngZjWj
+MdMhqMhsfMSRcGqRsQQRctjjdDnjtjClCjjpZnDlnt
+BBMRsQRfRcscGqBfRRsBssPBLLzNLFPwvVFFPTLbbLwHHTvS
+pCmCfdPFzmsFsDhFFDsttptpRtJjLnlJRtttHt
+ZQwgWZgqJhTTRtgV
+GNqWNvcqqQQrMMWcQzDDsSzBDBSssSmhhr
diff --git a/data/day04.txt b/data/day04.txt
new file mode 100644
index 0000000..5304059
--- /dev/null
+++ b/data/day04.txt
@@ -0,0 +1,1000 @@
+36-92,35-78
+26-31,25-27
+17-72,16-71
+3-77,76-90
+20-22,21-87
+5-75,6-75
+42-44,43-95
+51-73,50-52
+81-89,80-81
+7-58,47-58
+72-91,20-92
+27-64,51-64
+5-94,94-95
+88-93,88-89
+7-45,46-91
+30-40,29-29
+81-90,80-90
+4-71,4-71
+68-83,65-84
+1-4,3-79
+94-95,35-82
+30-84,31-97
+6-82,81-86
+88-88,4-89
+41-97,40-89
+95-99,34-94
+18-56,18-56
+53-64,22-53
+5-9,9-71
+18-41,40-66
+38-39,38-78
+23-99,22-94
+34-54,34-53
+33-76,85-94
+72-91,63-79
+33-94,93-94
+56-82,20-56
+60-85,60-86
+31-76,31-33
+29-79,78-80
+9-9,66-69
+6-97,6-75
+40-78,39-77
+14-30,14-15
+91-94,88-98
+1-23,10-23
+9-84,7-9
+75-76,75-98
+45-87,45-46
+11-11,11-11
+16-64,64-65
+60-60,20-61
+48-81,93-94
+5-48,32-47
+37-75,74-75
+13-76,13-13
+15-93,92-96
+41-86,86-96
+48-92,64-91
+1-9,2-97
+43-56,55-55
+7-99,98-99
+98-99,1-99
+15-97,7-99
+76-76,32-77
+71-76,76-77
+13-28,13-29
+38-69,42-50
+49-49,50-77
+68-84,71-83
+26-51,32-51
+12-40,39-63
+21-92,9-88
+7-65,65-69
+56-76,56-77
+40-62,62-62
+35-96,92-95
+37-99,12-86
+94-98,4-81
+32-38,34-39
+11-94,24-93
+1-97,1-60
+7-77,7-59
+62-81,80-96
+38-83,82-82
+44-44,43-98
+22-23,22-62
+28-97,16-97
+53-88,67-88
+2-2,56-97
+41-72,71-72
+78-80,47-79
+1-1,2-41
+23-99,33-98
+33-98,61-97
+80-95,80-80
+8-90,8-91
+4-90,50-89
+94-94,3-95
+3-83,2-99
+45-52,12-44
+22-65,66-71
+9-72,72-73
+2-62,2-82
+40-61,30-60
+57-87,25-56
+76-78,77-77
+16-88,87-88
+14-77,73-77
+37-90,36-38
+10-75,11-11
+37-99,3-97
+47-48,45-47
+6-92,7-91
+60-74,60-61
+20-29,8-21
+95-96,47-95
+63-70,31-63
+6-97,6-76
+19-91,19-92
+50-92,49-50
+17-96,18-97
+3-4,3-93
+13-51,1-13
+34-87,23-33
+2-99,98-98
+4-6,7-76
+46-60,36-45
+50-80,25-51
+60-61,24-61
+97-98,3-98
+33-34,83-99
+30-76,22-77
+27-72,72-94
+47-96,31-47
+26-90,11-27
+47-87,3-72
+86-91,9-87
+32-79,78-79
+72-95,94-94
+88-96,8-89
+11-84,12-98
+5-8,8-29
+6-38,86-86
+14-33,5-33
+20-95,39-94
+6-99,12-93
+52-91,52-90
+3-99,2-72
+72-96,56-90
+7-84,7-8
+20-37,14-37
+26-74,74-75
+40-54,4-71
+42-42,93-94
+53-69,23-52
+20-96,95-96
+1-18,18-83
+2-3,2-69
+36-87,87-87
+8-94,8-94
+59-99,59-60
+15-35,11-35
+6-26,5-26
+7-12,11-80
+79-79,79-79
+2-47,46-47
+76-96,96-97
+12-79,11-77
+45-71,46-94
+62-63,62-94
+30-84,84-85
+9-35,9-13
+18-60,18-61
+13-90,13-85
+2-38,1-2
+76-81,24-54
+48-49,48-95
+59-92,58-69
+72-72,15-73
+15-16,15-99
+79-85,60-86
+58-58,46-59
+55-60,3-54
+22-26,26-58
+6-86,7-85
+66-76,47-66
+52-73,52-53
+21-76,20-77
+44-73,16-77
+29-80,30-30
+15-47,14-16
+3-75,1-3
+55-61,9-56
+37-55,36-82
+64-83,83-84
+9-91,41-89
+22-86,33-85
+6-19,5-34
+80-92,93-93
+99-99,85-98
+96-99,14-97
+2-72,5-59
+93-94,56-94
+34-83,34-86
+33-34,34-73
+17-84,18-44
+82-83,26-83
+3-85,18-84
+88-88,9-88
+93-93,27-94
+12-13,12-14
+8-90,8-42
+78-86,41-77
+63-79,80-81
+15-66,14-16
+77-77,28-76
+9-96,8-10
+19-78,77-79
+13-95,72-93
+13-49,14-14
+84-85,84-95
+25-37,25-37
+49-93,49-91
+24-78,5-38
+2-92,2-92
+17-90,16-90
+8-50,8-50
+76-99,76-98
+71-86,77-86
+70-71,54-70
+8-84,39-84
+40-58,55-58
+8-87,1-9
+5-7,6-85
+25-97,24-25
+9-97,14-96
+17-48,10-47
+81-87,30-80
+3-83,83-84
+2-7,6-42
+20-70,70-93
+67-85,17-61
+7-18,6-20
+21-73,20-22
+80-81,18-79
+43-95,44-96
+38-45,44-44
+15-91,90-91
+32-44,34-43
+24-93,24-25
+10-16,11-12
+22-92,61-92
+3-7,6-73
+72-79,71-74
+34-47,34-46
+56-96,75-82
+31-48,48-81
+54-81,53-82
+2-91,93-97
+41-74,10-40
+51-63,52-86
+80-90,75-90
+86-87,10-87
+80-94,84-94
+46-47,9-47
+20-77,78-92
+38-38,17-37
+30-76,5-30
+6-58,58-77
+10-73,74-85
+1-96,2-31
+64-73,4-74
+60-79,59-77
+4-98,8-89
+7-9,8-78
+4-6,5-95
+29-93,53-90
+32-94,20-33
+78-91,38-79
+10-95,96-99
+5-97,86-96
+6-65,5-64
+28-71,7-72
+15-54,45-53
+3-87,46-99
+1-90,40-90
+44-86,19-86
+3-94,93-94
+92-93,1-93
+93-93,42-94
+90-97,21-91
+16-94,16-62
+20-27,79-86
+28-28,29-39
+30-94,29-30
+28-68,76-79
+54-73,54-55
+35-36,35-87
+5-42,43-47
+10-90,8-91
+15-74,23-49
+16-97,1-98
+2-82,82-89
+1-3,2-86
+16-87,15-86
+9-10,9-60
+14-90,10-14
+36-85,5-85
+36-41,37-89
+50-50,15-50
+82-86,85-86
+28-66,28-32
+15-84,14-14
+32-69,31-33
+31-95,30-96
+60-85,61-92
+10-87,86-87
+96-99,5-97
+97-97,39-96
+34-35,3-35
+51-88,33-88
+14-49,48-90
+4-51,52-56
+7-76,31-75
+3-99,3-87
+29-86,29-75
+61-64,61-65
+85-97,13-86
+59-67,6-58
+51-97,44-50
+21-64,64-93
+9-56,10-81
+20-51,50-51
+33-87,32-87
+18-79,5-90
+51-51,22-52
+24-83,21-25
+79-93,24-94
+14-14,13-83
+43-49,44-50
+72-72,10-73
+14-57,35-57
+4-63,3-4
+4-93,26-91
+26-93,25-26
+33-35,33-43
+36-87,87-92
+27-69,6-70
+38-60,30-39
+96-96,1-95
+2-96,99-99
+16-87,88-88
+41-52,41-51
+61-77,76-82
+9-77,3-10
+39-50,38-51
+12-63,12-62
+17-30,18-76
+22-86,22-23
+3-43,2-44
+21-66,66-66
+3-64,2-2
+60-65,60-65
+7-42,74-96
+81-98,38-98
+16-24,17-23
+95-97,32-96
+23-38,23-37
+42-54,40-46
+16-18,13-17
+1-81,3-63
+16-17,17-50
+82-87,88-97
+6-47,5-48
+8-81,92-94
+95-97,11-96
+23-94,22-86
+6-35,3-56
+7-93,90-92
+6-49,3-6
+24-86,86-86
+67-78,67-78
+11-98,10-96
+87-88,17-88
+8-98,99-99
+15-73,72-73
+1-60,60-60
+39-45,33-45
+77-95,41-76
+5-23,24-99
+96-98,97-97
+18-55,55-56
+97-98,60-90
+33-34,13-34
+7-96,8-96
+7-32,46-61
+75-93,20-96
+30-99,29-31
+4-99,3-97
+3-30,29-30
+40-40,39-63
+48-49,48-60
+22-24,6-22
+28-28,3-28
+64-64,37-63
+29-48,5-48
+20-37,19-36
+77-77,19-77
+18-85,2-19
+99-99,30-80
+35-36,31-35
+28-79,75-98
+26-94,26-95
+22-97,73-96
+42-42,5-41
+6-8,7-99
+10-14,13-14
+39-72,39-73
+12-90,89-90
+93-94,12-94
+50-88,89-93
+47-88,88-89
+39-64,38-38
+15-79,78-79
+28-32,32-33
+50-65,51-51
+7-79,6-64
+33-49,32-34
+82-95,75-96
+6-14,4-9
+95-95,10-96
+14-51,3-15
+97-98,21-98
+39-61,53-61
+68-69,37-68
+15-73,73-95
+42-70,43-83
+1-60,60-61
+6-11,11-94
+10-79,87-93
+36-40,41-41
+3-17,3-43
+4-81,4-82
+90-91,6-90
+2-3,5-68
+20-98,74-97
+4-86,3-85
+47-49,23-48
+26-89,26-90
+31-42,42-47
+57-81,39-58
+17-87,18-96
+9-77,9-78
+79-88,80-84
+30-84,83-83
+15-89,15-88
+11-11,10-94
+59-82,27-59
+8-78,14-33
+46-95,85-94
+93-97,92-94
+4-34,2-3
+34-80,30-82
+48-83,27-49
+47-99,47-48
+27-51,51-56
+48-49,35-48
+31-51,42-51
+96-97,19-96
+43-44,20-44
+76-76,13-75
+5-90,27-90
+26-27,27-51
+47-54,49-95
+69-72,4-73
+94-98,68-95
+1-2,3-86
+25-90,24-26
+28-90,89-89
+91-91,74-91
+56-95,40-57
+55-92,28-54
+28-34,27-35
+85-87,28-86
+8-10,10-98
+45-45,44-44
+31-83,27-59
+67-84,2-68
+17-69,51-69
+49-52,34-53
+22-81,2-23
+95-96,2-96
+82-99,17-82
+40-57,40-58
+9-40,40-40
+1-2,3-68
+1-97,90-97
+2-20,21-34
+2-2,1-92
+84-86,2-86
+7-92,97-99
+2-6,5-42
+1-52,1-52
+98-99,1-98
+38-80,29-43
+39-69,39-39
+97-99,3-98
+70-71,8-71
+26-52,25-38
+8-92,91-92
+12-49,13-27
+7-95,94-95
+91-99,15-92
+19-45,18-19
+75-76,76-97
+59-74,13-86
+3-3,2-3
+41-60,53-59
+75-99,29-96
+66-68,18-67
+3-91,3-95
+33-98,32-34
+5-78,10-77
+55-95,54-59
+6-81,6-81
+78-94,52-75
+20-93,10-94
+12-37,83-99
+46-93,92-99
+17-79,8-94
+45-99,46-46
+73-90,68-73
+82-83,58-83
+15-88,90-94
+66-96,18-65
+12-87,61-86
+35-85,36-84
+96-96,28-95
+82-95,2-83
+1-2,2-99
+59-88,59-60
+54-90,53-74
+35-48,57-57
+16-28,16-29
+35-45,36-36
+25-39,24-58
+19-74,27-75
+35-73,31-36
+16-76,6-87
+8-99,7-97
+1-1,1-89
+9-74,10-75
+12-74,11-56
+80-81,2-80
+13-97,19-92
+43-83,82-89
+55-59,60-60
+20-79,98-98
+61-62,61-86
+35-82,93-97
+21-42,43-43
+49-94,43-50
+5-81,98-99
+5-95,1-95
+6-80,91-97
+26-85,11-25
+34-68,19-48
+3-99,3-87
+81-81,19-81
+8-47,8-48
+46-70,46-71
+13-73,46-73
+13-83,14-82
+6-97,96-99
+19-33,18-34
+30-99,2-99
+50-84,1-84
+6-97,6-96
+96-96,6-96
+10-96,9-94
+38-39,38-43
+18-94,19-97
+86-86,87-91
+8-98,8-97
+84-86,78-85
+23-71,72-72
+5-99,98-98
+26-75,26-75
+87-87,20-88
+11-85,7-8
+52-61,45-62
+42-97,42-97
+25-89,21-24
+95-96,4-93
+66-69,67-68
+2-93,94-96
+8-9,9-81
+72-97,21-98
+59-75,58-60
+14-16,15-96
+71-71,70-71
+10-79,3-10
+54-54,53-98
+2-4,3-69
+14-66,14-67
+16-17,16-65
+27-99,76-99
+19-94,95-97
+3-83,83-84
+36-57,31-56
+34-83,33-83
+56-67,66-88
+30-70,17-31
+24-80,79-80
+43-52,42-43
+10-65,66-68
+50-69,1-70
+10-10,10-33
+10-99,9-98
+86-96,85-85
+30-65,31-60
+18-81,17-19
+12-84,49-71
+19-98,18-18
+3-67,4-68
+88-99,69-99
+11-87,10-11
+98-98,37-85
+8-90,47-89
+2-43,67-79
+5-5,4-97
+31-94,93-96
+13-83,14-14
+72-85,71-84
+51-53,26-52
+3-58,57-62
+41-58,41-58
+29-84,30-56
+89-98,21-90
+51-97,50-94
+8-96,8-95
+1-4,4-81
+23-51,52-95
+29-61,8-60
+11-15,1-5
+2-75,7-75
+42-66,46-66
+53-93,53-94
+5-99,3-6
+2-5,6-13
+65-97,46-99
+51-72,50-90
+36-65,64-66
+1-4,4-94
+7-8,7-86
+4-89,3-90
+61-98,60-62
+40-81,19-81
+28-73,27-73
+4-98,6-97
+63-73,63-89
+13-97,96-98
+5-13,13-88
+24-92,7-92
+15-31,14-28
+2-88,97-97
+11-45,11-45
+40-82,82-82
+51-51,50-60
+84-91,21-83
+71-98,71-97
+21-95,31-94
+1-97,1-41
+2-3,2-84
+3-4,4-91
+98-98,17-97
+15-15,16-84
+43-48,11-37
+13-83,11-15
+88-96,3-96
+55-91,24-55
+4-96,96-99
+66-82,80-80
+3-61,62-93
+99-99,11-70
+56-56,57-59
+40-40,39-99
+57-58,35-58
+36-95,94-94
+2-63,64-81
+18-24,24-62
+63-98,12-63
+81-81,18-80
+19-61,19-20
+11-18,11-22
+9-14,9-11
+6-7,6-85
+41-51,41-41
+18-43,17-19
+8-70,71-84
+76-76,11-75
+87-88,9-88
+55-73,54-56
+56-57,57-68
+4-11,11-88
+8-81,11-80
+25-70,71-71
+22-45,23-48
+14-84,5-95
+58-68,47-58
+17-66,38-66
+58-89,88-89
+7-28,14-27
+31-87,22-63
+92-96,39-91
+14-41,14-14
+62-65,3-61
+48-66,48-66
+4-95,2-96
+7-7,8-77
+17-50,18-51
+80-89,14-79
+28-50,28-89
+32-40,7-40
+19-77,18-19
+34-60,1-6
+33-50,51-91
+16-17,16-54
+29-45,19-32
+36-42,37-37
+1-95,3-87
+70-93,92-98
+4-11,46-79
+20-82,1-19
+40-41,2-42
+75-77,31-76
+8-14,14-78
+69-91,68-69
+9-63,77-89
+47-70,39-47
+3-98,97-98
+84-84,30-84
+9-9,10-95
+24-24,23-92
+27-95,21-95
+2-99,2-99
+38-59,54-59
+20-81,15-82
+6-73,13-73
+98-98,99-99
+18-92,17-19
+93-94,5-93
+13-99,13-14
+34-34,34-79
+12-88,87-96
+55-67,83-89
+6-30,1-31
+24-80,24-80
+5-90,16-91
+49-68,10-49
+11-14,13-92
+23-85,24-92
+67-81,67-68
+32-99,32-89
+85-86,35-84
+21-21,20-60
+25-85,25-84
+20-56,21-21
+6-9,9-71
+82-98,26-81
+37-37,15-38
+5-97,3-5
+11-18,19-26
+14-69,6-83
+51-73,50-75
+29-85,19-28
+8-59,5-60
+92-92,46-93
+8-57,7-9
+16-16,16-84
+10-32,10-11
+1-86,1-86
+26-98,19-91
+7-97,6-94
+41-81,42-80
+3-97,13-98
+24-25,24-87
+54-54,18-55
+49-49,33-50
+6-80,79-80
+38-95,38-95
+52-84,52-77
+6-92,1-6
+1-3,3-88
+6-71,2-5
+16-46,2-17
+79-86,15-80
+6-6,5-54
+8-41,11-40
+53-98,52-54
+2-79,1-3
+51-70,50-52
+55-55,56-69
+4-61,10-97
+75-92,12-76
+27-79,92-94
+6-55,5-7
+19-25,20-22
+79-92,65-93
+95-99,27-94
+23-88,23-88
+82-83,83-96
+2-94,2-74
+14-71,6-14
+6-14,5-7
+3-89,1-2
+48-82,13-26
+48-80,26-48
+43-93,92-92
+32-51,85-91
+3-5,5-90
+99-99,95-97
+38-39,38-88
+93-95,75-94
+15-64,14-16
+84-94,67-90
+22-47,48-80
+41-56,5-57
+2-80,7-79
+22-71,21-23
+21-49,20-22
+95-95,61-95
+56-57,57-58
+25-27,26-62
+52-76,41-61
+28-98,71-98
+74-93,4-93
+35-74,73-98
+4-57,3-57
+4-99,32-98
+8-75,7-75
+23-67,23-68
+15-15,15-56
+3-97,1-98
+10-90,91-91
+18-30,17-19
+10-38,1-90
+50-73,37-73
+40-91,92-95
+39-39,40-91
+86-87,7-87
+12-37,37-94
+78-87,14-50
+89-95,11-90
+60-98,4-94
+41-82,81-98
+66-92,67-67
+88-92,5-89
+86-91,85-86
+6-98,97-97
+34-87,95-95
+44-46,45-78
+7-87,17-87
+7-96,95-97
+15-75,76-85
+1-98,2-93
+3-55,50-54
+87-94,72-86
+19-70,19-63
+7-51,50-79
+3-73,3-73
+32-38,31-34
+2-99,98-98
+3-4,5-88
+16-37,38-38
+39-48,40-42
+65-77,65-77
+5-94,3-96
+28-89,97-98
+34-77,53-77
+24-54,25-28
+6-48,7-7
+6-38,3-6
+10-83,9-11
+26-65,64-84
+50-85,84-86
+36-91,37-92
+2-2,2-84
+4-6,5-83
+18-71,35-70
+5-85,5-64
+94-99,13-95
+1-32,2-9
+11-71,53-98
+99-99,18-97
+26-46,22-27
+39-78,91-93
+38-43,38-44
+14-76,15-54
+91-95,23-90
+7-55,3-55
+91-95,29-92
+10-23,9-59
+21-67,20-66
+17-27,20-26
+2-94,1-94
+16-97,13-97
+67-68,67-94
+81-83,27-82
+51-69,81-96
+79-81,57-80
+55-55,55-68
+34-96,34-95
+83-85,19-84
+4-81,3-80
+16-23,23-97
+45-74,46-74
+2-98,98-99
+37-59,35-59
+72-74,70-74
+16-91,91-92
+43-68,44-75
+4-77,7-92
+93-94,6-94
+18-92,93-94
+51-76,76-76
+17-42,41-79
+61-62,49-61
+19-77,9-9
+11-70,43-69
+21-62,53-61
+40-77,78-89
+10-55,10-46
+5-70,98-99
+19-21,20-86
+7-68,10-67
+2-24,3-3
+65-70,46-66
+1-78,2-77
+71-95,17-72
+25-88,88-89
+13-98,14-14
+7-81,7-8
+8-99,8-98
+13-97,14-97
+3-56,3-4
+89-99,29-73
+41-50,28-51
+76-88,76-87
+82-96,25-31
+30-41,8-42
+27-39,38-38
+46-71,46-71
+23-88,10-88
+28-83,28-84
+82-94,81-86
+99-99,1-99
+4-46,4-63
+7-68,67-99
+5-92,93-97
+91-95,3-89
+57-76,3-70
+1-89,53-88
+4-32,6-31
+75-76,2-76
+17-17,18-37
+43-90,89-94
+4-65,1-66
+88-91,90-91
+43-57,44-84
+2-95,2-94
+3-31,1-32
+12-94,30-93
+12-94,5-94
+35-54,34-54
+30-81,30-30
+51-53,52-98
+68-97,41-69
+32-94,19-31
+14-70,7-15
+1-99,41-98
+41-63,41-63
+88-88,27-87
+54-56,53-55
+26-26,27-71
+29-64,1-62
+4-54,1-92
+88-89,22-89
+15-88,15-16
+21-95,43-96
+12-13,12-27
+10-96,23-96
+82-83,22-83
+13-85,13-86
+77-83,4-65
+3-91,3-63
+73-98,73-98
+49-49,8-50
+3-96,4-4
diff --git a/data/day05.txt b/data/day05.txt
new file mode 100644
index 0000000..7cb8cf9
--- /dev/null
+++ b/data/day05.txt
@@ -0,0 +1,514 @@
+ [B] [B] [S]
+ [M] [P] [L] [B] [J]
+ [D] [R] [V] [D] [Q] [D]
+ [T] [R] [Z] [H] [H] [G] [C]
+ [P] [W] [J] [B] [J] [F] [J] [S]
+[N] [S] [Z] [V] [M] [N] [Z] [F] [M]
+[W] [Z] [H] [D] [H] [G] [Q] [S] [W]
+[B] [L] [Q] [W] [S] [L] [J] [W] [Z]
+ 1 2 3 4 5 6 7 8 9
+
+move 3 from 5 to 2
+move 5 from 3 to 1
+move 4 from 4 to 9
+move 6 from 1 to 4
+move 6 from 8 to 7
+move 5 from 2 to 7
+move 1 from 5 to 4
+move 11 from 9 to 7
+move 1 from 1 to 9
+move 6 from 4 to 6
+move 12 from 6 to 7
+move 1 from 9 to 2
+move 2 from 4 to 6
+move 1 from 8 to 9
+move 1 from 9 to 4
+move 1 from 6 to 1
+move 2 from 7 to 5
+move 2 from 6 to 7
+move 2 from 1 to 6
+move 2 from 4 to 7
+move 1 from 5 to 4
+move 1 from 5 to 6
+move 1 from 6 to 1
+move 1 from 1 to 3
+move 1 from 4 to 1
+move 1 from 1 to 4
+move 1 from 4 to 5
+move 1 from 3 to 9
+move 1 from 5 to 1
+move 4 from 2 to 1
+move 20 from 7 to 8
+move 24 from 7 to 3
+move 3 from 6 to 4
+move 1 from 1 to 9
+move 1 from 9 to 3
+move 2 from 1 to 2
+move 2 from 4 to 1
+move 2 from 2 to 1
+move 14 from 3 to 6
+move 6 from 1 to 6
+move 10 from 3 to 2
+move 1 from 2 to 3
+move 6 from 6 to 5
+move 2 from 3 to 4
+move 13 from 8 to 4
+move 1 from 9 to 7
+move 1 from 6 to 3
+move 10 from 4 to 2
+move 1 from 3 to 6
+move 2 from 8 to 7
+move 1 from 7 to 2
+move 11 from 6 to 8
+move 2 from 6 to 1
+move 2 from 1 to 3
+move 1 from 8 to 6
+move 1 from 3 to 9
+move 3 from 8 to 2
+move 1 from 3 to 6
+move 2 from 6 to 4
+move 1 from 6 to 5
+move 11 from 2 to 9
+move 2 from 4 to 6
+move 1 from 6 to 1
+move 1 from 1 to 5
+move 11 from 2 to 7
+move 12 from 7 to 5
+move 1 from 6 to 2
+move 10 from 8 to 7
+move 6 from 5 to 3
+move 4 from 5 to 4
+move 11 from 9 to 7
+move 7 from 4 to 9
+move 4 from 9 to 6
+move 12 from 7 to 3
+move 1 from 8 to 9
+move 1 from 5 to 1
+move 1 from 1 to 2
+move 1 from 6 to 9
+move 3 from 4 to 1
+move 1 from 9 to 7
+move 8 from 7 to 2
+move 3 from 6 to 1
+move 8 from 2 to 3
+move 1 from 7 to 4
+move 2 from 7 to 2
+move 1 from 5 to 2
+move 8 from 5 to 1
+move 3 from 9 to 6
+move 1 from 6 to 2
+move 1 from 4 to 5
+move 1 from 5 to 4
+move 2 from 9 to 3
+move 1 from 8 to 6
+move 1 from 4 to 5
+move 1 from 5 to 1
+move 1 from 6 to 8
+move 1 from 8 to 1
+move 7 from 1 to 5
+move 11 from 3 to 7
+move 1 from 1 to 9
+move 4 from 2 to 1
+move 5 from 1 to 3
+move 1 from 5 to 9
+move 1 from 6 to 3
+move 6 from 2 to 1
+move 5 from 7 to 3
+move 1 from 6 to 8
+move 1 from 8 to 4
+move 6 from 7 to 9
+move 4 from 9 to 8
+move 2 from 8 to 9
+move 2 from 5 to 8
+move 13 from 3 to 7
+move 1 from 3 to 8
+move 2 from 1 to 9
+move 3 from 1 to 5
+move 1 from 4 to 1
+move 6 from 5 to 9
+move 8 from 9 to 8
+move 2 from 7 to 3
+move 1 from 9 to 7
+move 1 from 5 to 2
+move 5 from 9 to 8
+move 1 from 8 to 7
+move 1 from 2 to 9
+move 7 from 1 to 2
+move 4 from 7 to 5
+move 6 from 2 to 3
+move 1 from 2 to 1
+move 10 from 8 to 9
+move 3 from 8 to 9
+move 4 from 5 to 1
+move 2 from 8 to 6
+move 9 from 9 to 8
+move 1 from 9 to 6
+move 8 from 8 to 4
+move 12 from 3 to 5
+move 1 from 4 to 2
+move 3 from 8 to 1
+move 3 from 9 to 7
+move 1 from 3 to 2
+move 1 from 6 to 9
+move 8 from 3 to 8
+move 6 from 4 to 5
+move 1 from 7 to 6
+move 1 from 8 to 1
+move 6 from 8 to 7
+move 1 from 3 to 6
+move 7 from 1 to 5
+move 1 from 4 to 9
+move 4 from 6 to 5
+move 13 from 7 to 5
+move 1 from 8 to 2
+move 2 from 9 to 3
+move 4 from 7 to 2
+move 1 from 3 to 8
+move 1 from 3 to 4
+move 4 from 1 to 2
+move 1 from 5 to 7
+move 23 from 5 to 6
+move 1 from 8 to 6
+move 1 from 9 to 4
+move 5 from 2 to 6
+move 1 from 4 to 9
+move 1 from 9 to 3
+move 1 from 7 to 8
+move 1 from 4 to 3
+move 1 from 3 to 7
+move 1 from 7 to 5
+move 1 from 8 to 7
+move 12 from 6 to 1
+move 1 from 2 to 5
+move 1 from 3 to 1
+move 20 from 5 to 2
+move 14 from 2 to 4
+move 11 from 2 to 6
+move 1 from 7 to 8
+move 13 from 1 to 8
+move 9 from 8 to 4
+move 3 from 8 to 6
+move 10 from 6 to 8
+move 6 from 6 to 4
+move 4 from 8 to 5
+move 26 from 4 to 2
+move 2 from 5 to 2
+move 5 from 8 to 1
+move 1 from 8 to 3
+move 2 from 1 to 3
+move 2 from 3 to 7
+move 27 from 2 to 7
+move 2 from 8 to 1
+move 1 from 3 to 7
+move 6 from 6 to 2
+move 4 from 6 to 1
+move 4 from 6 to 4
+move 2 from 5 to 4
+move 4 from 2 to 1
+move 3 from 1 to 8
+move 1 from 2 to 8
+move 8 from 4 to 3
+move 1 from 2 to 8
+move 5 from 8 to 6
+move 1 from 4 to 2
+move 1 from 2 to 1
+move 6 from 3 to 1
+move 13 from 7 to 1
+move 1 from 2 to 8
+move 1 from 8 to 2
+move 1 from 6 to 2
+move 1 from 2 to 8
+move 1 from 8 to 2
+move 14 from 7 to 1
+move 5 from 6 to 3
+move 2 from 3 to 1
+move 3 from 3 to 2
+move 3 from 7 to 4
+move 1 from 4 to 9
+move 1 from 9 to 7
+move 2 from 3 to 6
+move 5 from 2 to 7
+move 1 from 7 to 6
+move 5 from 7 to 6
+move 2 from 6 to 7
+move 1 from 6 to 8
+move 1 from 4 to 7
+move 4 from 6 to 9
+move 35 from 1 to 8
+move 3 from 7 to 2
+move 1 from 2 to 5
+move 24 from 8 to 3
+move 1 from 5 to 8
+move 13 from 3 to 6
+move 2 from 2 to 6
+move 6 from 6 to 4
+move 11 from 1 to 6
+move 12 from 6 to 1
+move 1 from 8 to 1
+move 2 from 1 to 3
+move 5 from 4 to 1
+move 1 from 6 to 4
+move 1 from 8 to 3
+move 13 from 3 to 9
+move 3 from 8 to 2
+move 3 from 2 to 7
+move 1 from 3 to 6
+move 3 from 7 to 8
+move 14 from 1 to 3
+move 1 from 1 to 9
+move 6 from 3 to 8
+move 17 from 8 to 6
+move 1 from 3 to 7
+move 1 from 7 to 8
+move 26 from 6 to 7
+move 1 from 1 to 9
+move 3 from 4 to 1
+move 2 from 3 to 8
+move 1 from 8 to 4
+move 14 from 9 to 7
+move 12 from 7 to 3
+move 2 from 1 to 4
+move 2 from 7 to 8
+move 2 from 8 to 3
+move 4 from 9 to 8
+move 1 from 4 to 7
+move 1 from 1 to 3
+move 2 from 4 to 2
+move 24 from 7 to 6
+move 1 from 8 to 1
+move 1 from 7 to 2
+move 1 from 7 to 9
+move 3 from 2 to 9
+move 1 from 1 to 6
+move 5 from 8 to 2
+move 5 from 3 to 4
+move 1 from 2 to 5
+move 3 from 9 to 8
+move 2 from 4 to 9
+move 16 from 6 to 3
+move 14 from 3 to 8
+move 1 from 7 to 9
+move 8 from 6 to 9
+move 4 from 8 to 5
+move 8 from 8 to 3
+move 1 from 5 to 8
+move 1 from 2 to 4
+move 4 from 8 to 7
+move 1 from 5 to 6
+move 12 from 9 to 5
+move 15 from 5 to 8
+move 1 from 6 to 1
+move 2 from 2 to 6
+move 3 from 4 to 2
+move 4 from 2 to 7
+move 8 from 7 to 3
+move 1 from 1 to 4
+move 3 from 6 to 9
+move 16 from 8 to 3
+move 3 from 9 to 4
+move 1 from 8 to 9
+move 2 from 9 to 4
+move 24 from 3 to 8
+move 19 from 8 to 7
+move 2 from 8 to 7
+move 7 from 4 to 5
+move 13 from 7 to 5
+move 4 from 7 to 8
+move 7 from 8 to 1
+move 3 from 5 to 3
+move 3 from 7 to 2
+move 1 from 1 to 4
+move 1 from 7 to 2
+move 3 from 2 to 4
+move 8 from 3 to 1
+move 11 from 1 to 3
+move 12 from 3 to 4
+move 1 from 2 to 5
+move 18 from 3 to 8
+move 3 from 1 to 9
+move 1 from 3 to 5
+move 15 from 5 to 4
+move 4 from 5 to 1
+move 23 from 4 to 6
+move 3 from 1 to 6
+move 13 from 8 to 3
+move 25 from 6 to 2
+move 1 from 9 to 5
+move 5 from 3 to 8
+move 17 from 2 to 8
+move 4 from 4 to 1
+move 1 from 9 to 7
+move 5 from 2 to 6
+move 2 from 2 to 4
+move 1 from 9 to 4
+move 6 from 3 to 9
+move 16 from 8 to 3
+move 2 from 1 to 8
+move 1 from 7 to 4
+move 5 from 4 to 7
+move 1 from 5 to 3
+move 2 from 7 to 1
+move 9 from 8 to 4
+move 3 from 7 to 2
+move 2 from 8 to 3
+move 10 from 4 to 1
+move 1 from 2 to 3
+move 5 from 3 to 7
+move 2 from 8 to 9
+move 2 from 9 to 8
+move 1 from 2 to 1
+move 3 from 9 to 6
+move 2 from 2 to 8
+move 4 from 7 to 3
+move 4 from 8 to 6
+move 1 from 7 to 1
+move 1 from 4 to 8
+move 4 from 3 to 4
+move 4 from 4 to 2
+move 6 from 1 to 2
+move 1 from 4 to 3
+move 5 from 3 to 8
+move 6 from 3 to 8
+move 2 from 2 to 8
+move 3 from 2 to 9
+move 8 from 1 to 6
+move 3 from 2 to 7
+move 2 from 7 to 2
+move 13 from 6 to 5
+move 7 from 5 to 9
+move 3 from 2 to 7
+move 1 from 2 to 9
+move 2 from 5 to 2
+move 3 from 8 to 5
+move 5 from 3 to 4
+move 2 from 2 to 1
+move 9 from 8 to 7
+move 1 from 1 to 8
+move 6 from 5 to 2
+move 4 from 2 to 8
+move 4 from 7 to 1
+move 1 from 2 to 6
+move 5 from 1 to 6
+move 1 from 8 to 2
+move 1 from 2 to 9
+move 13 from 6 to 5
+move 2 from 7 to 2
+move 1 from 8 to 7
+move 4 from 4 to 7
+move 1 from 4 to 1
+move 4 from 8 to 4
+move 6 from 5 to 9
+move 2 from 1 to 4
+move 1 from 8 to 6
+move 11 from 9 to 5
+move 1 from 7 to 8
+move 1 from 8 to 1
+move 1 from 1 to 3
+move 6 from 4 to 8
+move 1 from 8 to 4
+move 1 from 1 to 6
+move 6 from 9 to 7
+move 1 from 4 to 5
+move 3 from 2 to 1
+move 1 from 8 to 2
+move 1 from 3 to 2
+move 20 from 5 to 6
+move 3 from 1 to 6
+move 2 from 2 to 9
+move 3 from 8 to 3
+move 5 from 3 to 8
+move 1 from 1 to 6
+move 2 from 8 to 9
+move 7 from 9 to 5
+move 3 from 5 to 4
+move 3 from 8 to 3
+move 9 from 7 to 9
+move 1 from 8 to 5
+move 7 from 7 to 9
+move 2 from 5 to 2
+move 9 from 9 to 2
+move 1 from 7 to 3
+move 2 from 9 to 1
+move 2 from 5 to 9
+move 2 from 1 to 4
+move 2 from 3 to 7
+move 18 from 6 to 7
+move 7 from 9 to 1
+move 7 from 6 to 8
+move 4 from 4 to 9
+move 4 from 8 to 3
+move 2 from 8 to 2
+move 1 from 8 to 5
+move 1 from 4 to 7
+move 1 from 5 to 1
+move 2 from 9 to 3
+move 12 from 2 to 5
+move 6 from 5 to 6
+move 5 from 7 to 2
+move 3 from 6 to 4
+move 1 from 4 to 7
+move 1 from 4 to 1
+move 2 from 5 to 8
+move 1 from 8 to 2
+move 2 from 9 to 7
+move 8 from 1 to 8
+move 11 from 7 to 1
+move 5 from 8 to 2
+move 7 from 7 to 5
+move 1 from 9 to 4
+move 1 from 7 to 5
+move 7 from 5 to 7
+move 2 from 6 to 1
+move 1 from 8 to 2
+move 12 from 1 to 7
+move 2 from 1 to 2
+move 3 from 8 to 5
+move 3 from 5 to 2
+move 8 from 7 to 3
+move 1 from 3 to 1
+move 3 from 6 to 4
+move 4 from 5 to 6
+move 14 from 2 to 9
+move 3 from 6 to 9
+move 3 from 4 to 2
+move 1 from 1 to 7
+move 1 from 7 to 1
+move 3 from 3 to 5
+move 8 from 7 to 4
+move 1 from 5 to 9
+move 3 from 2 to 4
+move 1 from 3 to 4
+move 4 from 2 to 6
+move 2 from 6 to 7
+move 3 from 5 to 4
+move 16 from 4 to 1
+move 7 from 9 to 8
+move 1 from 5 to 1
+move 3 from 7 to 9
+move 3 from 9 to 4
+move 7 from 1 to 7
+move 6 from 7 to 1
+move 5 from 3 to 1
+move 11 from 9 to 2
+move 3 from 4 to 6
+move 9 from 2 to 8
+move 6 from 3 to 5
+move 2 from 8 to 6
+move 5 from 5 to 3
+move 2 from 7 to 1
+move 3 from 3 to 9
+move 1 from 2 to 4
+move 1 from 5 to 1
+move 13 from 1 to 2
+move 5 from 8 to 6
+move 2 from 3 to 9
+move 2 from 4 to 7
+move 5 from 6 to 9
+move 7 from 9 to 1
+move 3 from 7 to 2
+move 6 from 8 to 6
+move 5 from 6 to 2
+move 2 from 8 to 3
+move 2 from 9 to 4
+move 6 from 2 to 5
+move 1 from 3 to 7
diff --git a/data/day06.txt b/data/day06.txt
new file mode 100644
index 0000000..d4ca6ec
--- /dev/null
+++ b/data/day06.txt
@@ -0,0 +1 @@
+qhbhzbzzfrzrbzzcjzjrrvcvrvqvvnggnngcgssswbblplrlflfnnnmmjppgddqndnrnlnccpfcfjcjvjdjqqqmhhmwhwmmsnsvsjvjnvjnvjvsjsmjsjccwcqwcqwqjqwjwmwbmmbzbsbvsslbsbbbntnvvphpqqvrrtbrtrfftppbggpzzfhfcfsfmssffmbmzzmqzzblzzzmwwnggjwgjwgjgpgmmjvvmcvmmcfchfhllwmlljqqldqdqttsgsvscsmsnsmstmtssvgsgddwdffbppwfpplhlchhhdvvdrrmttmptmmmjsmshmmmgqmgggzjgzzmwzwcwhchqqfpfvvbqvbqbrblrrmtmstmmjvmmdnmmzczdzpztppjhjjwzjjjtdjjpljpjcppjllsffhbffbhhgttqjqzzfzbzcbzcbcrrjjrwrgwwbcbpcccctrtqtfqqfjjpgpdgdfgfrggpjjljglgclcqcqmcqmmgjjllpmphpjjgfjjqrrbppwmpmccftctjtjgjtgggzffcggwzzzdjdzzlgzgjzzvqvppczzjnjvvfhhtwtttdwtdtvddpzpnpcnppmvmcmcsmstthctchcggtssdttvztvvldlfftqqbzzjttvzztppscctzccgmcmvmhhchcscbbshbssgwwthwhmwwcgwcwrrvrzvrzzzvhvdvmmprrdmrmfmrmbmjbbmqbmbqqhbbszsjjlqjljtjstshhgphpffdhhtggtgbbqcqgqccfffcpcbpbfppwqpqcclbbwdwsscpchhfpfmpfmflfnnmggwrrznnghgvhhghrrhwrrcschcscqcmcfcvvgzztjtqjjshspsqsmmjnnmttsshvhmmqfqzztbzttvhttmwttnqnfncfcpfflmllmtlmmphmhlmmltmtztcczhzbbfmmlglnnfpppqplljwjfwfdwdzwddszddqzqnzzzwwlzzqvvjlllrwlrrmpmrmbmpplpspqsqmqcmcjjshsvstvvwtvthvvrfvvqmmjpmjmrjmmlvvnnrjjrcrwrhwwqzzvgvngncgcqqcffmfzfssbnbfblbggwhggmtgtvvqhhpttbcbczcjjbqbhqbhqbbccbhbqhbbmppdlpdllbvvdpvdvwvsvppllgblbttmcmtccbsswmswwwzfwfhhtfhthctchcfhhhfjjvhjhgjjjcwjwggrtgrttcqcwcswccfdffvpvtptprrvjjqvjjghggshhwmmcscmsmhmvmppprfrwwrhhvghhtnhncctbbbwzzbgzgdzgdzdpdvpvbbwgbwwrqwrqwqbqvvclccfcfzfdfrrthrrqcqddplpqlppbbfrfmmrmnnwhhgddmwwrzrsswpwhwdwhhsmhshqsqllbvlbllwbwbpwwfwmwsmspsvsdsbscctpctppvvpggtjjdmdqqgqbgglccvzcvcnczcgzgmzznpzzpcpnpvpcvvffrttqrqttflfbfjfnnwnlwlhwwqzqnqfftstdsttglldwwgqwwvqqzczfzdffbfsfssfwswdwnwdnnbcncwctttvsvjsvsrvvbtvvzhhvjvtvtjtsjjvhjjwpjjnzzpczzppgcpgcpgcgsgvsgvsscrcpcpspllzvzddpssssdpsddhffllzmzhzfhhdvhhvbvwwpwqpwqpwwmvwmvwvgvmvpvmpmrmzrrblltjtggvnggvppthhzjhzhffrvrhvrhrlrslsflfhhtvhvmmhppjgpjpcccmqcqvqhvvfssrtmnwjjslwhjgpvrwspjlwdwrmvfgwmplrmjrllndrjzvjfbwvzpjpfqrnjspwcpsgcvdlmfdfrvwdcvmbrnzncgnqlcvgqtpsbbpvprncdsgvpqbpcnffwqmmfsvnzspchhrlnzbhcdfdgtsllmqfbrcqwbmmzrfvsghjpmrndsdbqvtprmblnbvbnpvhtphbpjwdssvwgdzwztbpzdcsqzldjzrgcwhhspblrtncvntppcgttlflflnntcnzpbpgsclcjvbjhldcdzwjjhnfwzjmgcwtljhvbncwqnjhbrhfqcmnsdvntsbgnpqttzvbhzzpdznrhjpnsqzsztsblstbghlpwbmqjctlnqnttwshfvmjdhgbgjdhbzrfjqndrrhlqcmplczjtwpstlsmwwzqzmgvhsvjgbrtfwmvwlbhpccbqvmfmlgmbmbmldbcwmmhpnnbnffbnqgwhclgpzgbpjqvzmqhhhpltnwrdfrrnmlfrzflpnjztlnfzzzgmncprtblpsvrqgrnzbzfzhzhjjjdrnpvjpnwmlmlgvvtqmdvpnhvcrdmthcnnnvhnzmvgrtdvcthgjtvcgmtpsvmfztrflrrzbmcfhftwwcnjfpjtsnzjccmvdnrrwvbfjgcjttdvzncqhlqqphwphclztbhlqcfmnhcjmsscplnrsjqpdzrrzbthbcdnrzgdmstpgqqsvzclvmzjjdfqhhhttwcjtmwcbltghmslqvltqbjqqjpjvgntvnlttjcnhltflglgsmjwjjfldpfgjgrhttbwfhpsdbsmsfmfbtjlnhvjfqjrqhwdrcwpfthdgqzjjjfcvgdffrhvvwzfghpszmjjgscjvjnlgnbfbgfrbbzbzbnzngthrddfmsgsqqdddpfqwlchfblrvjdcgnzfzwmmnmvnzmpfmhbbhsbfdfclzcnbrlgpbsvfgfpshrpvpgccmmghphrcvzwnlqjcfwrtwvlvcsdldldvnpwgrcsqlftllcctnvcwbdswvqlzwzzbpmvvctcrgnjfstbqvnzczrjlljfqzrwtfwmlvvdfbfntrrljtbrtbdfsqpnppfbppbsmghbnqddhrvwmgzttnqjrqlfrdhqjndmnjlbctgclltmznmrqtfjsjwnztdvhnhlfwpnnqlhhsrfzglsnrdnfvrqssbtlthzfnjdvrcgzsbnpdgqhhrlwspfqfqpvzdfwgrlhwplzvbzprsqzcwvhggvzpgjztnvwvddsflgsvqljmmhhdzqsqmthwzvllqwmsnvdpdbjcgdtrsnmwhnzhbhgjssstmhrpssnhnntmrbbbjgmjqtncbdljcgtmbctpgdrnqcnrpssrdtpbsmlzlcztbrggglswnjzqgbsmgbqdzppqrwgtnlrjrvlpnqlcdwhltzzlqdwwrglldzcqrjtjtlgdqrtwzjgtdthsdccsmsrbjjsgdqcwdltvnjwtddsnpnsvzcdbfqnvsjbngqrztmbrnbvhhjzdtqrgldpvjqjpnshbjdsdgbjdjzdmrvzhwmtgcjrfnprstqgfgnwfpcjzhlnwpdbtqbspssqdrzhmmsrqtlwngvbrvgdgztnrlwcnqwvcdmhhdrmpfqbgbjpvzwbsbgcpsnpjplcrjdhflqvsdctclqqnmprngtvbmlmpqrsqdsrzgsmzmsczpsnmfmtfnjvnddjhqbjdvtgftjfvjhgpjqdhlszqjmcbnwrppzwjvmgblspjmfhjdbnmrllnfqlpcbndvqdzhhmmrpsljgdshpnrgnmwfjsdncqcwlctccrqghfdbsqqbnwctcqpvlrqqqvdjwlcnzmvdmcvlwnftjnqqldfwhmdtcpnlgfcdjdrfvmwqdzsjzctmmmrswhlwthttvcsqqscdcsmjgqfjhswlpsfjrppdmbwrthcwszqwwgnjsdqdrswmnzbrvqcwlrlwwvjmrrhsnzprggbzhhdqwvnspsmzzqdtbphzvwrzvqnbntjndrwllzwchczdwvnfjjdwfhdlgncftldzwdtjzjrmnfwwgmqdrltmgrfsjztfcvwjsggtvbnsvthflwfdtljrgqhmfqhmhfffqhtgwtlmwgzsglqnfwnrnvgvbdgqjrqtsmgsmzdpffnnzwlpbqphqmgdzspfrdqlptwmfwlgnqqdhtbbjtfhllrhhdcszjtmrprzhzzlgjqbcnhzcmhzrsnmmrzztffrldthhfvwhgjhwmjfbdvnllfmlpdsldjnpcwlpbwqzdwbgjb
diff --git a/data/day07.txt b/data/day07.txt
new file mode 100644
index 0000000..5eac444
--- /dev/null
+++ b/data/day07.txt
@@ -0,0 +1,1108 @@
+$ cd /
+$ ls
+dir fpljqj
+171526 ghtzhjwf.nls
+dir gsdsbld
+dir hbmjtb
+296801 mjfjqw.ccv
+dir nfn
+dir qmrsvfvw
+102565 qqjnqb.chd
+dir svgbqd
+$ cd fpljqj
+$ ls
+153563 ghtzhjwf.nls
+243252 gsvjgj.jsm
+154134 hghnrbqg.rzb
+$ cd ..
+$ cd gsdsbld
+$ ls
+dir npmncvhh
+dir qmrsvfvw
+dir sqtnlr
+dir vzndpc
+$ cd npmncvhh
+$ ls
+81366 dwbgr.ztr
+144577 fzjmcq
+dir mphhrqf
+dir rnmvggfd
+276454 zfl.ghv
+$ cd mphhrqf
+$ ls
+dir qlcfs
+111207 shmcrf.wlr
+dir zwsnwvnv
+$ cd qlcfs
+$ ls
+283904 fpljqj.pdw
+83520 hsclcqqt.pff
+dir htwl
+dir lqjhfdch
+5842 mdjzmbc.qtv
+dir nqfdhlcg
+120167 twgqhvft.cgw
+186998 zclhcr
+dir zfl
+dir zlqgr
+$ cd htwl
+$ ls
+268134 hmwnn.htq
+$ cd ..
+$ cd lqjhfdch
+$ ls
+21479 tpdsgf.hgd
+$ cd ..
+$ cd nqfdhlcg
+$ ls
+dir dhjfqv
+203675 ghtzhjwf.nls
+39527 qfwdmzfv.ggd
+$ cd dhjfqv
+$ ls
+135074 dqs.wht
+$ cd ..
+$ cd ..
+$ cd zfl
+$ ls
+17334 wlsd
+$ cd ..
+$ cd zlqgr
+$ ls
+dir crs
+dir whrm
+dir zfl
+$ cd crs
+$ ls
+220281 szft.bjb
+$ cd ..
+$ cd whrm
+$ ls
+279796 pcnl
+dir pjzpqs
+$ cd pjzpqs
+$ ls
+dir smz
+192921 sqtst.lcz
+21397 trst
+154861 vtgdsnmv
+$ cd smz
+$ ls
+249693 mjfjqw.ccv
+dir tdwqpg
+$ cd tdwqpg
+$ ls
+157907 wjv.rth
+$ cd ..
+$ cd ..
+$ cd ..
+$ cd ..
+$ cd zfl
+$ ls
+dir hwlhshtr
+$ cd hwlhshtr
+$ ls
+90468 srrv.jst
+$ cd ..
+$ cd ..
+$ cd ..
+$ cd ..
+$ cd zwsnwvnv
+$ ls
+209371 ctmcqlz.nwh
+154262 nqngjf
+$ cd ..
+$ cd ..
+$ cd rnmvggfd
+$ ls
+dir czzrdvc
+203540 dnwtwzd
+dir fcsjqg
+dir fwdprwpq
+74582 qlnqwnzp.ttz
+dir tvglfb
+$ cd czzrdvc
+$ ls
+dir blplbjpw
+$ cd blplbjpw
+$ ls
+2835 zfl.zvw
+$ cd ..
+$ cd ..
+$ cd fcsjqg
+$ ls
+81548 ghtzhjwf.nls
+$ cd ..
+$ cd fwdprwpq
+$ ls
+11156 gsvjgj.jsm
+75010 rgscvjq.zlw
+122327 szft.bjb
+dir zfl
+268883 zpgcwvjf
+$ cd zfl
+$ ls
+dir sphpbjt
+$ cd sphpbjt
+$ ls
+31414 qfwdmzfv.ggd
+$ cd ..
+$ cd ..
+$ cd ..
+$ cd tvglfb
+$ ls
+118050 gsvjgj.jsm
+265116 sdmldsd.hhm
+$ cd ..
+$ cd ..
+$ cd ..
+$ cd qmrsvfvw
+$ ls
+dir fpljqj
+203965 szft.bjb
+dir zcgfg
+$ cd fpljqj
+$ ls
+dir gqvmv
+$ cd gqvmv
+$ ls
+175614 mjfjqw.ccv
+$ cd ..
+$ cd ..
+$ cd zcgfg
+$ ls
+110104 ddzcbm.qtb
+dir fpglbth
+148639 nqfdhlcg.fsz
+dir pfjz
+166120 wjrmgl
+$ cd fpglbth
+$ ls
+58850 qlggch.tng
+$ cd ..
+$ cd pfjz
+$ ls
+197076 wplpj
+$ cd ..
+$ cd ..
+$ cd ..
+$ cd sqtnlr
+$ ls
+189086 gsvjgj.jsm
+dir ngr
+210016 pmprhlg.rsg
+277979 szft.bjb
+282202 tfqcnn.hlf
+$ cd ngr
+$ ls
+dir fdhd
+dir hwsqqt
+dir qmrsvfvw
+$ cd fdhd
+$ ls
+7384 fhhp
+dir fpljqj
+91732 nqfdhlcg.gwf
+69137 ptcrmc.wwr
+$ cd fpljqj
+$ ls
+282109 rtfhcbc.pqj
+$ cd ..
+$ cd ..
+$ cd hwsqqt
+$ ls
+174820 zvmgv.tcd
+$ cd ..
+$ cd qmrsvfvw
+$ ls
+228739 qfwdmzfv.ggd
+$ cd ..
+$ cd ..
+$ cd ..
+$ cd vzndpc
+$ ls
+183360 fpljqj.nbh
+$ cd ..
+$ cd ..
+$ cd hbmjtb
+$ ls
+219988 hlvjdg
+dir lndmtm
+107247 rtpvh.srl
+dir sgt
+dir tgjszvsg
+166122 zrshs.phz
+dir ztrvv
+$ cd lndmtm
+$ ls
+dir fpljqj
+dir hscwh
+dir wjv
+$ cd fpljqj
+$ ls
+102717 qmrsvfvw
+$ cd ..
+$ cd hscwh
+$ ls
+dir qgz
+dir qmrsvfvw
+$ cd qgz
+$ ls
+281901 szft.bjb
+$ cd ..
+$ cd qmrsvfvw
+$ ls
+102781 fpljqj.gtv
+197014 gsvjgj.jsm
+174895 pvz
+$ cd ..
+$ cd ..
+$ cd wjv
+$ ls
+dir fpljqj
+295195 mjfjqw.ccv
+214886 qfwdmzfv.ggd
+dir qmrsvfvw
+72164 vncjvfhh
+$ cd fpljqj
+$ ls
+dir fpljqj
+dir fzbppql
+dir jpqqr
+dir lzq
+dir pjjbmllm
+dir qmrsvfvw
+$ cd fpljqj
+$ ls
+260943 ghtzhjwf.nls
+$ cd ..
+$ cd fzbppql
+$ ls
+29399 wjv
+$ cd ..
+$ cd jpqqr
+$ ls
+45275 zcwbrvd
+$ cd ..
+$ cd lzq
+$ ls
+180833 szft.bjb
+$ cd ..
+$ cd pjjbmllm
+$ ls
+64063 mjfjqw.ccv
+183683 vrfd.wlw
+$ cd ..
+$ cd qmrsvfvw
+$ ls
+226047 szft.bjb
+$ cd ..
+$ cd ..
+$ cd qmrsvfvw
+$ ls
+dir bzcfzh
+272794 lnzpvhj
+dir vsrgqmlt
+dir zbthlb
+$ cd bzcfzh
+$ ls
+63095 mjfjqw.ccv
+45335 nqfdhlcg
+162307 vqqt.vbg
+$ cd ..
+$ cd vsrgqmlt
+$ ls
+dir nqfdhlcg
+$ cd nqfdhlcg
+$ ls
+dir wjv
+$ cd wjv
+$ ls
+81528 cslzgjtp.qzg
+$ cd ..
+$ cd ..
+$ cd ..
+$ cd zbthlb
+$ ls
+dir hjp
+dir twfw
+dir zfl
+$ cd hjp
+$ ls
+20745 pvjwrzsl.pmg
+$ cd ..
+$ cd twfw
+$ ls
+dir csmmbjhp
+$ cd csmmbjhp
+$ ls
+165998 nlsd
+109132 vbjlnqt.lsd
+$ cd ..
+$ cd ..
+$ cd zfl
+$ ls
+227633 jcs.vhj
+dir tvfhvbp
+$ cd tvfhvbp
+$ ls
+116169 lgv
+175862 qfwdmzfv.ggd
+$ cd ..
+$ cd ..
+$ cd ..
+$ cd ..
+$ cd ..
+$ cd ..
+$ cd sgt
+$ ls
+151135 nqfdhlcg
+226449 nqfdhlcg.sqp
+148179 wjv.fgc
+$ cd ..
+$ cd tgjszvsg
+$ ls
+98354 szft.bjb
+$ cd ..
+$ cd ztrvv
+$ ls
+163992 blmmm.gcf
+dir fghl
+dir fpljqj
+226325 nqfdhlcg
+dir qmrsvfvw
+284965 vhbffmcg.fwt
+$ cd fghl
+$ ls
+dir lgpwpmzp
+dir sqjqg
+$ cd lgpwpmzp
+$ ls
+dir ctr
+dir nqfdhlcg
+279439 zfl.npd
+$ cd ctr
+$ ls
+64805 jfflsd.gbc
+163058 zbvpc.znm
+$ cd ..
+$ cd nqfdhlcg
+$ ls
+40180 jsqtwpt.qtq
+87408 rmpbprz.lwr
+$ cd ..
+$ cd ..
+$ cd sqjqg
+$ ls
+140444 bsglv
+214121 crzdv.dcc
+$ cd ..
+$ cd ..
+$ cd fpljqj
+$ ls
+56575 gqw.dzr
+293957 gsvjgj.jsm
+272507 jvd
+dir tgfvcpp
+178972 vndshbth.mzw
+dir zwtz
+$ cd tgfvcpp
+$ ls
+dir bhq
+$ cd bhq
+$ ls
+111454 gvq
+$ cd ..
+$ cd ..
+$ cd zwtz
+$ ls
+39290 nqfdhlcg
+140517 qfwdmzfv.ggd
+dir tcnv
+177429 zlzsq.fph
+$ cd tcnv
+$ ls
+286997 fpljqj.phd
+$ cd ..
+$ cd ..
+$ cd ..
+$ cd qmrsvfvw
+$ ls
+252862 jbznh
+$ cd ..
+$ cd ..
+$ cd ..
+$ cd nfn
+$ ls
+dir fqw
+dir mpz
+dir qmrsvfvw
+dir zfl
+$ cd fqw
+$ ls
+144372 ghtzhjwf.nls
+100013 mqwwjbvz.scd
+95547 vspwhq.dwn
+$ cd ..
+$ cd mpz
+$ ls
+dir gntjg
+dir jfbhz
+7835 nqfdhlcg
+dir vpgpz
+dir zfl
+$ cd gntjg
+$ ls
+dir hdq
+dir hvcdpzr
+dir lth
+27002 mjfjqw.ccv
+dir qmrsvfvw
+dir scncl
+$ cd hdq
+$ ls
+dir jwhnt
+$ cd jwhnt
+$ ls
+153428 fswqv.jpf
+$ cd ..
+$ cd ..
+$ cd hvcdpzr
+$ ls
+dir fpljqj
+135000 fpljqj.smw
+275125 hrqwfjjz.rdj
+dir pmcpnqrr
+58960 qljhbczf.qfn
+222912 szft.bjb
+dir wvvzbt
+$ cd fpljqj
+$ ls
+282896 nqfdhlcg.bjm
+$ cd ..
+$ cd pmcpnqrr
+$ ls
+dir nwjzld
+dir tfdcg
+dir vwlbtgnh
+$ cd nwjzld
+$ ls
+74948 wjv.psf
+$ cd ..
+$ cd tfdcg
+$ ls
+77925 gsvjgj.jsm
+dir lcdfdmlj
+dir pthwnf
+227063 qfwdmzfv.ggd
+293860 qmwr.csp
+154426 scwd.mdc
+$ cd lcdfdmlj
+$ ls
+52503 mjfjqw.ccv
+$ cd ..
+$ cd pthwnf
+$ ls
+176935 fgcwjjz
+$ cd ..
+$ cd ..
+$ cd vwlbtgnh
+$ ls
+dir nqfdhlcg
+$ cd nqfdhlcg
+$ ls
+dir lnwtl
+$ cd lnwtl
+$ ls
+252540 cgj.pdg
+$ cd ..
+$ cd ..
+$ cd ..
+$ cd ..
+$ cd wvvzbt
+$ ls
+25603 bvhd
+24426 qzwgj.bmb
+$ cd ..
+$ cd ..
+$ cd lth
+$ ls
+dir dmbf
+60608 ghtzhjwf.nls
+dir ndbcrvw
+dir shsgqzn
+27467 zfl.tdf
+$ cd dmbf
+$ ls
+dir zpggmccr
+$ cd zpggmccr
+$ ls
+238504 hqsgz.jfh
+$ cd ..
+$ cd ..
+$ cd ndbcrvw
+$ ls
+289441 bwbdc
+dir zfl
+84967 zhwz
+$ cd zfl
+$ ls
+95245 mjfjqw.ccv
+$ cd ..
+$ cd ..
+$ cd shsgqzn
+$ ls
+184543 gqrthw.gwf
+61456 wzbbsqrp
+$ cd ..
+$ cd ..
+$ cd qmrsvfvw
+$ ls
+dir bql
+247487 szvbjdjl
+58312 wjv
+241150 wjv.ltm
+$ cd bql
+$ ls
+93199 fpljqj
+$ cd ..
+$ cd ..
+$ cd scncl
+$ ls
+13092 clgmqlfl
+dir dcldv
+dir fsrznscl
+21910 nqfdhlcg.lld
+dir prcgb
+$ cd dcldv
+$ ls
+271970 nqfdhlcg.dgv
+$ cd ..
+$ cd fsrznscl
+$ ls
+dir bcdrv
+$ cd bcdrv
+$ ls
+96252 fpljqj.cdr
+154325 tvf.vhv
+$ cd ..
+$ cd ..
+$ cd prcgb
+$ ls
+69766 lnsvgqq.psj
+$ cd ..
+$ cd ..
+$ cd ..
+$ cd jfbhz
+$ ls
+286498 ssbmgts
+$ cd ..
+$ cd vpgpz
+$ ls
+63751 gsvjgj.jsm
+220526 vvlvcs.dpc
+$ cd ..
+$ cd zfl
+$ ls
+dir fpljqj
+182996 ghtzhjwf.nls
+dir jcffb
+dir jzl
+dir nzlv
+6752 snwmlr.glp
+$ cd fpljqj
+$ ls
+dir btsdth
+dir fwdw
+dir nqfdhlcg
+dir qmrsvfvw
+203470 svsvcgj
+$ cd btsdth
+$ ls
+176953 szft.bjb
+$ cd ..
+$ cd fwdw
+$ ls
+95939 crffczjt.gsq
+dir mbgzf
+dir rqdnjfdq
+296397 zfl.fjb
+$ cd mbgzf
+$ ls
+179220 mjfjqw.ccv
+$ cd ..
+$ cd rqdnjfdq
+$ ls
+204152 qmrsvfvw
+$ cd ..
+$ cd ..
+$ cd nqfdhlcg
+$ ls
+194439 gwc.wdp
+167934 qfwdmzfv.ggd
+151571 sczw
+$ cd ..
+$ cd qmrsvfvw
+$ ls
+dir dwc
+103919 gfzgg
+6816 shpch.chl
+$ cd dwc
+$ ls
+17813 gsvjgj.jsm
+80522 hbhlv.pqh
+dir htpt
+dir hwg
+dir nslrrrfg
+dir psgw
+231148 sdfvzdwm.wlz
+102460 szft.bjb
+dir wjlfgt
+$ cd htpt
+$ ls
+162107 wjv
+$ cd ..
+$ cd hwg
+$ ls
+dir gslvrbt
+dir qmrsvfvw
+$ cd gslvrbt
+$ ls
+dir fjwn
+107757 gsvjgj.jsm
+$ cd fjwn
+$ ls
+268653 qptczjlq.prv
+$ cd ..
+$ cd ..
+$ cd qmrsvfvw
+$ ls
+10557 nqfdhlcg
+$ cd ..
+$ cd ..
+$ cd nslrrrfg
+$ ls
+112961 gsvjgj.jsm
+dir hjgbgq
+dir jctqdpq
+dir qgfb
+dir zfl
+$ cd hjgbgq
+$ ls
+124947 mjfjqw.ccv
+$ cd ..
+$ cd jctqdpq
+$ ls
+203489 vgfhrl
+$ cd ..
+$ cd qgfb
+$ ls
+33980 nqfdhlcg.pqs
+$ cd ..
+$ cd zfl
+$ ls
+193098 gsvjgj.jsm
+dir vmzghf
+26070 zfnppjsz
+$ cd vmzghf
+$ ls
+235035 szft.bjb
+$ cd ..
+$ cd ..
+$ cd ..
+$ cd psgw
+$ ls
+55808 gsvjgj.jsm
+214300 wjv
+$ cd ..
+$ cd wjlfgt
+$ ls
+201399 qfwdmzfv.ggd
+$ cd ..
+$ cd ..
+$ cd ..
+$ cd ..
+$ cd jcffb
+$ ls
+81815 szft.bjb
+$ cd ..
+$ cd jzl
+$ ls
+155651 gsvjgj.jsm
+dir shrf
+$ cd shrf
+$ ls
+57545 fpljqj.pcb
+$ cd ..
+$ cd ..
+$ cd nzlv
+$ ls
+115992 bmmnj.ghw
+100862 ghtzhjwf.nls
+dir qwjpjw
+dir rhbtbjp
+dir rlmzs
+60695 szft.bjb
+3260 vzgwmrnc
+dir wwnnj
+17546 zdstndwj.lms
+$ cd qwjpjw
+$ ls
+dir dpwp
+dir fzdcjr
+173669 gsvjgj.jsm
+dir nmnbv
+dir nqfdhlcg
+dir plzdzdnm
+135543 qfwdmzfv.ggd
+246217 qmrsvfvw
+dir sgpcqqm
+141900 wvt.rfz
+$ cd dpwp
+$ ls
+214058 wjv.zqs
+94614 zrtbln
+$ cd ..
+$ cd fzdcjr
+$ ls
+236058 jcn.fzn
+$ cd ..
+$ cd nmnbv
+$ ls
+215145 lllgsbb
+$ cd ..
+$ cd nqfdhlcg
+$ ls
+61644 ghtzhjwf.nls
+238094 qfwdmzfv.ggd
+183057 szft.bjb
+17501 wjv.pln
+$ cd ..
+$ cd plzdzdnm
+$ ls
+243979 fpljqj.lnj
+$ cd ..
+$ cd sgpcqqm
+$ ls
+262759 hjffwcls
+100893 mvs.cgz
+dir nzhlcl
+170443 szft.bjb
+dir zfl
+$ cd nzhlcl
+$ ls
+dir wcfl
+$ cd wcfl
+$ ls
+24502 mjfjqw.ccv
+145029 zfl.lpp
+$ cd ..
+$ cd ..
+$ cd zfl
+$ ls
+176653 ghtzhjwf.nls
+$ cd ..
+$ cd ..
+$ cd ..
+$ cd rhbtbjp
+$ ls
+dir nqfdhlcg
+232788 pmj.cmm
+dir zfvbc
+$ cd nqfdhlcg
+$ ls
+72379 gqpcrtpw.nsm
+$ cd ..
+$ cd zfvbc
+$ ls
+19204 dqbs.ddg
+$ cd ..
+$ cd ..
+$ cd rlmzs
+$ ls
+232862 fpljqj.rps
+5558 lmgss.dtf
+$ cd ..
+$ cd wwnnj
+$ ls
+260417 cwjsrptm.hlm
+216130 gsvjgj.jsm
+$ cd ..
+$ cd ..
+$ cd ..
+$ cd ..
+$ cd qmrsvfvw
+$ ls
+dir fpljqj
+dir hllbt
+dir nqfdhlcg
+$ cd fpljqj
+$ ls
+dir qmrsvfvw
+dir tdnp
+dir vhtwd
+dir wnlzd
+dir ztttgd
+$ cd qmrsvfvw
+$ ls
+218325 fpljqj.zhj
+220402 qfwdmzfv.ggd
+$ cd ..
+$ cd tdnp
+$ ls
+46936 fmgz
+dir gdsqdtw
+dir tpcbjc
+dir zfl
+$ cd gdsqdtw
+$ ls
+128812 cnfpsb.qjr
+185390 ghtzhjwf.nls
+147220 qfwdmzfv.ggd
+$ cd ..
+$ cd tpcbjc
+$ ls
+188075 szft.bjb
+243171 zdprcqs.qwf
+$ cd ..
+$ cd zfl
+$ ls
+dir nnschfl
+dir qmrsvfvw
+dir szlbls
+109443 wjv
+$ cd nnschfl
+$ ls
+139948 szft.bjb
+$ cd ..
+$ cd qmrsvfvw
+$ ls
+dir bdn
+dir fpljqj
+168508 fpljqj.ljd
+dir hwgbwqmm
+dir nwhl
+224059 qfwdmzfv.ggd
+$ cd bdn
+$ ls
+179118 jdrdjf.ppn
+74443 lpp
+$ cd ..
+$ cd fpljqj
+$ ls
+125033 mtfgm.pjf
+$ cd ..
+$ cd hwgbwqmm
+$ ls
+133673 vrvhgbz.ttb
+$ cd ..
+$ cd nwhl
+$ ls
+187017 fpljqj
+149238 mjfjqw.ccv
+dir mqzrmjr
+dir vdjgqfc
+dir zfzfbq
+$ cd mqzrmjr
+$ ls
+dir fpljqj
+131712 jmnsst.bmv
+289722 ppdhjswn
+dir qmrsvfvw
+30641 zfl.trb
+$ cd fpljqj
+$ ls
+286985 lwmfmsr.tln
+253325 mjfjqw.ccv
+194077 vgb.glm
+38905 wjv.vgs
+$ cd ..
+$ cd qmrsvfvw
+$ ls
+87468 nngbnwds.qcn
+$ cd ..
+$ cd ..
+$ cd vdjgqfc
+$ ls
+122025 rnvwf.mrp
+261944 wdwgml
+$ cd ..
+$ cd zfzfbq
+$ ls
+dir bwmrf
+dir zfl
+$ cd bwmrf
+$ ls
+222502 gsvjgj.jsm
+$ cd ..
+$ cd zfl
+$ ls
+10297 ghtzhjwf.nls
+$ cd ..
+$ cd ..
+$ cd ..
+$ cd ..
+$ cd szlbls
+$ ls
+10968 bqbclc.nfl
+$ cd ..
+$ cd ..
+$ cd ..
+$ cd vhtwd
+$ ls
+188024 dgz
+$ cd ..
+$ cd wnlzd
+$ ls
+201028 gsvjgj.jsm
+dir mcnnsv
+dir mctpdbs
+47879 szft.bjb
+dir tjqfts
+164406 zpdmdrw
+$ cd mcnnsv
+$ ls
+dir lclgj
+dir sjdbnbqw
+dir tlj
+dir wjv
+$ cd lclgj
+$ ls
+192605 fgpjczr.grp
+65758 hhrf.fgg
+$ cd ..
+$ cd sjdbnbqw
+$ ls
+89058 ghtzhjwf.nls
+191742 rlmwjg.dpl
+179479 zswc.snt
+$ cd ..
+$ cd tlj
+$ ls
+183447 fpljqj.fgf
+$ cd ..
+$ cd wjv
+$ ls
+1517 pbwr
+189647 szft.bjb
+$ cd ..
+$ cd ..
+$ cd mctpdbs
+$ ls
+120327 szft.bjb
+$ cd ..
+$ cd tjqfts
+$ ls
+dir crvw
+$ cd crvw
+$ ls
+289523 lcshtlgf.lrv
+169176 szft.bjb
+$ cd ..
+$ cd ..
+$ cd ..
+$ cd ztttgd
+$ ls
+247914 sqqv.cvm
+$ cd ..
+$ cd ..
+$ cd hllbt
+$ ls
+298155 cqnb.fgc
+224277 hjf
+220312 jhnpv
+7421 qmrsvfvw
+dir qsg
+$ cd qsg
+$ ls
+dir drm
+dir fpljqj
+dir wjv
+$ cd drm
+$ ls
+dir fhzr
+$ cd fhzr
+$ ls
+dir nqfdhlcg
+$ cd nqfdhlcg
+$ ls
+125578 nqfdhlcg
+$ cd ..
+$ cd ..
+$ cd ..
+$ cd fpljqj
+$ ls
+dir jmfqmdcm
+dir nqfdhlcg
+48942 qfwdmzfv.ggd
+dir swrdzl
+18483 szft.bjb
+254012 zjcnz.pls
+$ cd jmfqmdcm
+$ ls
+130015 bvrmp.vwg
+157978 gsvjgj.jsm
+54571 hmhldqr.ctt
+169263 qgccqrqs
+261388 szft.bjb
+$ cd ..
+$ cd nqfdhlcg
+$ ls
+213466 fpljqj.wbp
+31434 jhsb.lbb
+144357 qfwdmzfv.ggd
+$ cd ..
+$ cd swrdzl
+$ ls
+dir fgmtnt
+dir pnmz
+280186 qmrsvfvw.mrb
+$ cd fgmtnt
+$ ls
+95823 gsvjgj.jsm
+127258 qmrsvfvw
+$ cd ..
+$ cd pnmz
+$ ls
+110479 ghtzhjwf.nls
+$ cd ..
+$ cd ..
+$ cd ..
+$ cd wjv
+$ ls
+51754 jpwhctfd
+174007 mgqplvv.hlt
+45041 mtrfs.bhj
+153169 vhjw.vbg
+$ cd ..
+$ cd ..
+$ cd ..
+$ cd nqfdhlcg
+$ ls
+dir htnw
+280499 tdwzsgqh.zsh
+$ cd htnw
+$ ls
+203521 ggfpmb.pmz
+$ cd ..
+$ cd ..
+$ cd ..
+$ cd zfl
+$ ls
+36860 mlbcw
+dir rgvgqqd
+239962 rpv.qhp
+64500 zfl.mvw
+$ cd rgvgqqd
+$ ls
+26778 qnhpfr
+$ cd ..
+$ cd ..
+$ cd ..
+$ cd qmrsvfvw
+$ ls
+290013 gsvjgj.jsm
+$ cd ..
+$ cd svgbqd
+$ ls
+69927 bjc.vdh
diff --git a/data/day10.txt b/data/day10.txt
new file mode 100644
index 0000000..37ee8ee
--- /dev/null
+++ b/data/day10.txt
@@ -0,0 +1,146 @@
+addx 15
+addx -11
+addx 6
+addx -3
+addx 5
+addx -1
+addx -8
+addx 13
+addx 4
+noop
+addx -1
+addx 5
+addx -1
+addx 5
+addx -1
+addx 5
+addx -1
+addx 5
+addx -1
+addx -35
+addx 1
+addx 24
+addx -19
+addx 1
+addx 16
+addx -11
+noop
+noop
+addx 21
+addx -15
+noop
+noop
+addx -3
+addx 9
+addx 1
+addx -3
+addx 8
+addx 1
+addx 5
+noop
+noop
+noop
+noop
+noop
+addx -36
+noop
+addx 1
+addx 7
+noop
+noop
+noop
+addx 2
+addx 6
+noop
+noop
+noop
+noop
+noop
+addx 1
+noop
+noop
+addx 7
+addx 1
+noop
+addx -13
+addx 13
+addx 7
+noop
+addx 1
+addx -33
+noop
+noop
+noop
+addx 2
+noop
+noop
+noop
+addx 8
+noop
+addx -1
+addx 2
+addx 1
+noop
+addx 17
+addx -9
+addx 1
+addx 1
+addx -3
+addx 11
+noop
+noop
+addx 1
+noop
+addx 1
+noop
+noop
+addx -13
+addx -19
+addx 1
+addx 3
+addx 26
+addx -30
+addx 12
+addx -1
+addx 3
+addx 1
+noop
+noop
+noop
+addx -9
+addx 18
+addx 1
+addx 2
+noop
+noop
+addx 9
+noop
+noop
+noop
+addx -1
+addx 2
+addx -37
+addx 1
+addx 3
+noop
+addx 15
+addx -21
+addx 22
+addx -6
+addx 1
+noop
+addx 2
+addx 1
+noop
+addx -10
+noop
+noop
+addx 20
+addx 1
+addx 2
+addx 2
+addx -6
+addx -11
+noop
+noop
+noop
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/days/day01/mod.rs b/src/days/day01/mod.rs
new file mode 100644
index 0000000..b88af22
--- /dev/null
+++ b/src/days/day01/mod.rs
@@ -0,0 +1,41 @@
+pub struct Day01;
+use itertools::Itertools;
+use anyhow::Result;
+
+use crate::template::Solution;
+
+const DATA: &str = include_str!("../../../data/day01.txt");
+
+impl Solution for Day01 {
+ fn solve_part1(&self) -> Result {
+ let solution = DATA
+ .trim()
+ .split("\n\n")
+ .map(|elf| {
+ elf.split('\n')
+ .map(|meal| meal.trim().parse::().unwrap())
+ .sum::()
+ })
+ .max()
+ .unwrap();
+
+ Ok(solution.to_string())
+ }
+
+ fn solve_part2(&self) -> Result {
+ let solution = DATA
+ .trim()
+ .split("\n\n")
+ .map(|elf| {
+ elf.split('\n')
+ .map(|meal| meal.trim().parse::().unwrap())
+ .sum::()
+ })
+ .sorted()
+ .rev()
+ .take(3)
+ .sum::();
+
+ Ok(solution.to_string())
+ }
+}
diff --git a/src/days/day02/mod.rs b/src/days/day02/mod.rs
new file mode 100644
index 0000000..883ea12
--- /dev/null
+++ b/src/days/day02/mod.rs
@@ -0,0 +1,19 @@
+mod part1;
+mod part2;
+
+use crate::template::Solution;
+use anyhow::Result;
+
+const DATA: &str = include_str!("../../../data/day02.txt");
+
+pub struct Day02;
+
+impl Solution for Day02 {
+ fn solve_part1(&self) -> Result {
+ Ok(part1::solve(DATA))
+ }
+
+ fn solve_part2(&self) -> Result {
+ Ok(part2::solve(DATA))
+ }
+}
diff --git a/src/days/day02/part1.rs b/src/days/day02/part1.rs
new file mode 100644
index 0000000..a76feca
--- /dev/null
+++ b/src/days/day02/part1.rs
@@ -0,0 +1,47 @@
+use rayon::prelude::*;
+
+#[derive(PartialEq, Eq, Hash, Clone, Copy)]
+#[repr(u8)]
+enum Shape {
+ Rock = 1,
+ Paper = 2,
+ Scissors = 3,
+}
+
+fn str_to_shape(istr: &str) -> Shape {
+ match istr {
+ "A" | "X" => Shape::Rock,
+ "B" | "Y" => Shape::Paper,
+ "C" | "Z" => Shape::Scissors,
+ _ => panic!("INVALID SHAPE"),
+ }
+}
+
+pub fn solve(data: &str) -> String {
+ let score = data
+ .trim()
+ .par_split('\n')
+ .map(|t| t.trim())
+ .map(|shapes| shapes.split_once(' ').unwrap())
+ .map(|(p0, p1)| (str_to_shape(p0), str_to_shape(p1)))
+ .map(score)
+ .sum::();
+
+ format!("{:?}", score)
+}
+
+fn x_beats(p0: Shape) -> Shape {
+ match p0 {
+ Shape::Rock => Shape::Scissors,
+ Shape::Scissors => Shape::Paper,
+ Shape::Paper => Shape::Rock
+ }
+}
+
+fn score((p0, p1): (Shape, Shape)) -> usize {
+ match p1 {
+ _ if p1 == p0 => p1 as usize + 3,
+ _ if x_beats(p0) == p1 => p1 as usize,
+ _ => p1 as usize + 6
+ }
+}
diff --git a/src/days/day02/part2.rs b/src/days/day02/part2.rs
new file mode 100644
index 0000000..5824ca4
--- /dev/null
+++ b/src/days/day02/part2.rs
@@ -0,0 +1,64 @@
+use rayon::prelude::*;
+
+#[derive(PartialEq, Eq, Hash, Clone, Copy)]
+#[repr(u8)]
+enum Shape {
+ Rock = 1,
+ Paper = 2,
+ Scissors = 3,
+}
+
+pub fn solve(data: &str) -> String {
+ let solution = data
+ .trim()
+ .par_split('\n')
+ .map(|t| t.trim())
+ .map(|shapes| shapes.split_once(' ').unwrap())
+ .map(|(p0, outcome)| (str_to_shape(p0), decide_shape(str_to_shape(p0), outcome)))
+ .map(score)
+ .sum::();
+
+ format!("{:?}", solution)
+}
+
+fn decide_shape(p0: Shape, outcome: &str) -> Shape {
+ match outcome {
+ "X" => x_beats(p0),
+ "Y" => p0,
+ "Z" => beats_y(p0),
+ _ => panic!("INVALID OUTCOME")
+ }
+}
+
+fn str_to_shape(istr: &str) -> Shape {
+ match istr {
+ "A" => Shape::Rock,
+ "B" => Shape::Paper,
+ "C" => Shape::Scissors,
+ _ => panic!("INVALID SHAPE"),
+ }
+}
+
+fn x_beats(p0: Shape) -> Shape {
+ match p0 {
+ Shape::Rock => Shape::Scissors,
+ Shape::Scissors => Shape::Paper,
+ Shape::Paper => Shape::Rock
+ }
+}
+
+fn beats_y(p1: Shape) -> Shape {
+ match p1 {
+ Shape::Scissors => Shape::Rock,
+ Shape::Paper => Shape::Scissors,
+ Shape::Rock => Shape::Paper
+ }
+}
+
+fn score((p0, p1): (Shape, Shape)) -> usize {
+ match p1 {
+ _ if p1 == p0 => p1 as usize + 3,
+ _ if x_beats(p0) == p1 => p1 as usize,
+ _ => p1 as usize + 6
+ }
+}
diff --git a/src/days/day03/mod.rs b/src/days/day03/mod.rs
new file mode 100644
index 0000000..e80c342
--- /dev/null
+++ b/src/days/day03/mod.rs
@@ -0,0 +1,28 @@
+use anyhow::Result;
+
+use crate::template::Solution;
+
+mod part1;
+mod part2;
+
+const DATA: &str = include_str!("../../../data/day03.txt");
+
+pub struct Day03;
+
+pub fn to_priority(input: char) -> usize {
+ if input.is_uppercase() {
+ (input as usize) - 38
+ } else {
+ (input as usize) - 96
+ }
+}
+
+impl Solution for Day03 {
+ fn solve_part1(&self) -> Result {
+ Ok(part1::solve(DATA))
+ }
+
+ fn solve_part2(&self) -> Result {
+ Ok(part2::solve(DATA))
+ }
+}
diff --git a/src/days/day03/part1.rs b/src/days/day03/part1.rs
new file mode 100644
index 0000000..2fa0fe5
--- /dev/null
+++ b/src/days/day03/part1.rs
@@ -0,0 +1,18 @@
+use itertools::Itertools;
+
+fn intersection((a, b): (&[usize], &[usize])) -> usize {
+ *a.iter().find(|x| b.contains(x)).unwrap()
+}
+
+pub fn solve(data: &str) -> String {
+ let priorities_sum = data
+ .trim()
+ .split('\n')
+ .into_iter()
+ .map(|sack| sack.trim().chars())
+ .map(|sack| sack.map(super::to_priority).collect_vec())
+ .map(|x| intersection(x.split_at(x.len() / 2)))
+ .sum::();
+
+ format!("{}", priorities_sum)
+}
diff --git a/src/days/day03/part2.rs b/src/days/day03/part2.rs
new file mode 100644
index 0000000..c8310b8
--- /dev/null
+++ b/src/days/day03/part2.rs
@@ -0,0 +1,23 @@
+use itertools::Itertools;
+
+fn three_way(a: &[usize], b: &[usize], c: &[usize]) -> usize {
+ *a.iter()
+ .find(|x| b.contains(x) && c.contains(x))
+ .unwrap()
+}
+
+pub fn solve(input: &str) -> String {
+ let priorities_sum = input
+ .trim()
+ .split('\n')
+ .map(|sack| sack.trim().chars())
+ .map(|sack| sack.map(super::to_priority))
+ .map(|sack| sack.collect_vec())
+ .chunks(3)
+ .into_iter()
+ .map(|chunk| chunk.collect_vec())
+ .map(|chunk| three_way(&chunk[0], &chunk[1], &chunk[2]))
+ .sum::();
+
+ format!("{}", priorities_sum)
+}
diff --git a/src/days/day04/mod.rs b/src/days/day04/mod.rs
new file mode 100644
index 0000000..7ffc876
--- /dev/null
+++ b/src/days/day04/mod.rs
@@ -0,0 +1,19 @@
+use crate::template::Solution;
+use anyhow::Result;
+
+mod part1;
+mod part2;
+
+pub struct Day04;
+
+const DATA: &str = include_str!("../../../data/day04.txt");
+
+impl Solution for Day04 {
+ fn solve_part1(&self) -> Result {
+ Ok(part1::solve(DATA))
+ }
+
+ fn solve_part2(&self) -> Result {
+ Ok(part2::solve(DATA))
+ }
+}
diff --git a/src/days/day04/part1.rs b/src/days/day04/part1.rs
new file mode 100644
index 0000000..97e0b3e
--- /dev/null
+++ b/src/days/day04/part1.rs
@@ -0,0 +1,27 @@
+use itertools::Itertools;
+
+fn rangeize(elf: &str) -> (usize, usize) {
+ elf.split('-')
+ .map(|rawstr| rawstr.parse::().unwrap())
+ .collect_tuple()
+ .unwrap()
+}
+
+fn covers(a: (usize, usize), b: (usize, usize)) -> bool {
+ let (amin, amax) = a;
+ let (bmin, bmax) = b;
+
+ (amin <= bmin && amax >= bmax) || (bmin <= amin && bmax >= amax)
+}
+
+pub fn solve(raw: &str) -> String {
+ let solution = raw
+ .trim()
+ .split('\n')
+ .map(|elves| elves.trim().split(',').collect_tuple().unwrap())
+ .map(|(elf1, elf2)| (rangeize(elf1), rangeize(elf2)))
+ .filter(|(elf1, elf2)| covers(elf1.to_owned(), elf2.to_owned()))
+ .count();
+
+ format!("{}", solution)
+}
diff --git a/src/days/day04/part2.rs b/src/days/day04/part2.rs
new file mode 100644
index 0000000..59f94b8
--- /dev/null
+++ b/src/days/day04/part2.rs
@@ -0,0 +1,28 @@
+use itertools::Itertools;
+
+fn rangeize(elf: &str) -> (usize, usize) {
+ elf.split('-')
+ .map(|rawstr| rawstr.parse::().unwrap())
+ .collect_tuple()
+ .unwrap()
+}
+
+fn overlaps(a: (usize, usize), b: (usize, usize)) -> bool {
+ let (amin, amax) = a;
+ let (bmin, bmax) = b;
+
+ (bmin..(bmax + 1)).any(|el| (amin..(amax + 1)).contains(&el))
+ || (amin..(amax + 1)).any(|el| (bmin..(bmax + 1)).contains(&el))
+}
+
+pub fn solve(raw: &str) -> String {
+ let solution = raw
+ .trim()
+ .split('\n')
+ .map(|elves| elves.trim().split(',').collect_tuple().unwrap())
+ .map(|(elf1, elf2)| (rangeize(elf1), rangeize(elf2)))
+ .filter(|(elf1, elf2)| overlaps(elf1.to_owned(), elf2.to_owned()))
+ .count();
+
+ format!("{}", solution)
+}
diff --git a/src/days/day05/mod.rs b/src/days/day05/mod.rs
new file mode 100644
index 0000000..54abffc
--- /dev/null
+++ b/src/days/day05/mod.rs
@@ -0,0 +1,19 @@
+use crate::template::Solution;
+use anyhow::Result;
+
+mod part1;
+mod part2;
+
+pub struct Day05;
+
+const DATA: &str = include_str!("../../../data/day05.txt");
+
+impl Solution for Day05 {
+ fn solve_part1(&self) -> Result {
+ Ok(part1::solve(DATA))
+ }
+
+ fn solve_part2(&self) -> Result {
+ Ok(part2::solve(DATA))
+ }
+}
diff --git a/src/days/day05/part1.rs b/src/days/day05/part1.rs
new file mode 100644
index 0000000..693e5cf
--- /dev/null
+++ b/src/days/day05/part1.rs
@@ -0,0 +1,120 @@
+use std::str;
+
+use nom::{
+ bytes::complete::tag,
+ character::complete::{digit0, space0},
+ combinator::map,
+ sequence::tuple,
+ IResult,
+};
+use itertools::Itertools;
+
+#[derive(Debug)]
+struct Instruction {
+ pub from: usize,
+ pub to: usize,
+ pub count: usize,
+}
+
+fn lex_instruction(raw: &str) -> IResult<&str, Instruction> {
+ map(
+ tuple((
+ tag("move"),
+ space0,
+ digit0,
+ space0,
+ tag("from"),
+ space0,
+ digit0,
+ space0,
+ tag("to"),
+ space0,
+ digit0,
+ )),
+ parse_instruction,
+ )(raw)
+}
+
+fn parse_instruction(
+ (_, _, count, _, _, _, from, _, _, _, to): (
+ &str,
+ &str,
+ &str,
+ &str,
+ &str,
+ &str,
+ &str,
+ &str,
+ &str,
+ &str,
+ &str,
+ ),
+) -> Instruction {
+ Instruction {
+ from: from.parse::().unwrap(),
+ to: to.parse::().unwrap(),
+ count: count.parse::().unwrap(),
+ }
+}
+
+fn gen_instructions(raw: &str) -> Vec {
+ raw.trim()
+ .split('\n')
+ .map(|line| line.trim())
+ .map(lex_instruction)
+ .map(|result| match result {
+ Ok((_, x)) => x,
+ Err(_) => panic!("Invalid Instruction"),
+ })
+ .collect()
+}
+
+fn process_instruction(i: Instruction, crates: Vec>) -> Vec> {
+ let mut new_crates = crates.clone();
+ let (kept, removed) = crates[i.from - 1].split_at(crates[i.from - 1].len() - i.count);
+ new_crates[i.from - 1] = kept.to_vec();
+ new_crates[i.to - 1].extend(removed.to_vec().into_iter().rev());
+ new_crates
+}
+
+fn gen_crates(raw: &str) -> Vec> {
+ let columns = raw
+ .split('\n')
+ .map(|line| {
+ line.as_bytes()
+ .chunks(4)
+ .map(str::from_utf8)
+ .map(|v| v.unwrap().trim().to_string())
+ .collect_vec()
+ })
+ .collect_vec();
+
+ let (indices, boxes) = columns.split_last().unwrap();
+ (0..indices.len())
+ .map(|index| {
+ boxes
+ .into_iter()
+ .map(|bx| bx[index].clone())
+ .filter(|k| !k.is_empty())
+ .rev()
+ .collect_vec()
+ })
+ .collect_vec()
+}
+
+pub fn solve(raw: &str) -> String {
+ let (raw_crates, raw_instructions) = raw.split_once("\n\n").unwrap();
+ let result: Vec> = gen_instructions(raw_instructions)
+ .into_iter()
+ .fold(gen_crates(raw_crates), |acc, instr| {
+ process_instruction(instr, acc)
+ });
+
+ format!(
+ "{:?}",
+ result
+ .into_iter()
+ .map(|x| x.last().unwrap().clone())
+ .collect_vec()
+ )
+}
diff --git a/src/days/day05/part2.rs b/src/days/day05/part2.rs
new file mode 100644
index 0000000..1a46ab6
--- /dev/null
+++ b/src/days/day05/part2.rs
@@ -0,0 +1,127 @@
+#![allow(unused)]
+#![feature(slice_take)]
+
+use std::str;
+
+use nom::{
+ branch::alt,
+ bytes::complete::{is_a, tag, take_while},
+ character::complete::{alpha0, digit0, space0},
+ combinator::map,
+ sequence::tuple,
+ Finish, IResult,
+};
+use std::char;
+use std::io::BufRead;
+
+use itertools::Itertools;
+
+#[derive(Debug)]
+struct Instruction {
+ pub from: usize,
+ pub to: usize,
+ pub count: usize,
+}
+
+fn lex_instruction(raw: &str) -> IResult<&str, Instruction> {
+ map(
+ tuple((
+ tag("move"),
+ space0,
+ digit0,
+ space0,
+ tag("from"),
+ space0,
+ digit0,
+ space0,
+ tag("to"),
+ space0,
+ digit0,
+ )),
+ parse_instruction,
+ )(raw)
+}
+
+fn parse_instruction(
+ (_, _, count, _, _, _, from, _, _, _, to): (
+ &str,
+ &str,
+ &str,
+ &str,
+ &str,
+ &str,
+ &str,
+ &str,
+ &str,
+ &str,
+ &str,
+ ),
+) -> Instruction {
+ Instruction {
+ from: from.parse::().unwrap(),
+ to: to.parse::().unwrap(),
+ count: count.parse::().unwrap(),
+ }
+}
+
+fn gen_instructions(raw: &str) -> Vec {
+ raw.trim()
+ .split('\n')
+ .map(|line| line.trim())
+ .map(lex_instruction)
+ .map(|result| match result {
+ Ok((_, x)) => x,
+ Err(_) => panic!("Invalid Instruction"),
+ })
+ .collect()
+}
+
+fn process_instruction(i: Instruction, crates: Vec>) -> Vec> {
+ let mut new_crates = crates.clone();
+ let (kept, removed) = crates[i.from - 1].split_at(crates[i.from - 1].len() - i.count);
+ new_crates[i.from - 1] = kept.to_vec();
+ new_crates[i.to - 1].extend(removed.to_vec());
+ new_crates
+}
+
+fn gen_crates(raw: &str) -> Vec> {
+ let columns = raw
+ .split('\n')
+ .map(|line| {
+ line.as_bytes()
+ .chunks(4)
+ .map(str::from_utf8)
+ .map(|v| v.unwrap().trim().to_string())
+ .collect_vec()
+ })
+ .collect_vec();
+
+ let (indices, boxes) = columns.split_last().unwrap();
+ (0..indices.len())
+ .map(|index| {
+ boxes
+ .into_iter()
+ .map(|bx| bx[index].clone())
+ .filter(|k| !k.is_empty())
+ .rev()
+ .collect_vec()
+ })
+ .collect_vec()
+}
+
+pub fn solve(raw: &str) -> String {
+ let (raw_crates, raw_instructions) = raw.split_once("\n\n").unwrap();
+ let result: Vec> = gen_instructions(raw_instructions)
+ .into_iter()
+ .fold(gen_crates(raw_crates), |acc, instr| {
+ process_instruction(instr, acc)
+ });
+
+ format!(
+ "{:?}",
+ result
+ .into_iter()
+ .map(|x| x.last().unwrap().clone())
+ .collect_vec()
+ )
+}
diff --git a/src/days/day06/mod.rs b/src/days/day06/mod.rs
new file mode 100644
index 0000000..cc09ea9
--- /dev/null
+++ b/src/days/day06/mod.rs
@@ -0,0 +1,18 @@
+use crate::template::Solution;
+use anyhow::Result;
+
+mod part1;
+mod part2;
+pub struct Day06;
+
+const DATA: &str = include_str!("../../../data/day06.txt");
+
+impl Solution for Day06 {
+ fn solve_part1(&self) -> Result {
+ Ok(part1::solve(DATA))
+ }
+
+ fn solve_part2(&self) -> Result {
+ Ok(part2::solve(DATA))
+ }
+}
diff --git a/src/days/day06/part1.rs b/src/days/day06/part1.rs
new file mode 100644
index 0000000..8e5e22a
--- /dev/null
+++ b/src/days/day06/part1.rs
@@ -0,0 +1,18 @@
+use itertools::Itertools;
+
+fn all_unique(chrs: Vec) -> bool {
+ chrs == chrs.clone().into_iter().unique().collect_vec()
+}
+
+pub fn solve(raw: &str) -> String {
+ let init = raw.chars().collect_vec();
+ let results = init
+ .windows(4)
+ .into_iter()
+ .enumerate()
+ .take_while(|(_, chars)| !all_unique(chars.to_vec()))
+ .collect_vec();
+
+ let (result, _) = results.last().unwrap();
+ format!("{}", result + 5)
+}
diff --git a/src/days/day06/part2.rs b/src/days/day06/part2.rs
new file mode 100644
index 0000000..ea9afeb
--- /dev/null
+++ b/src/days/day06/part2.rs
@@ -0,0 +1,18 @@
+use itertools::Itertools;
+
+fn all_unique(chrs: Vec) -> bool {
+ chrs == chrs.clone().into_iter().unique().collect_vec()
+}
+
+pub fn solve(raw: &str) -> String {
+ let init = raw.chars().collect_vec();
+ let results = init
+ .windows(14)
+ .into_iter()
+ .enumerate()
+ .take_while(|(_, chars)| !all_unique(chars.to_vec()))
+ .collect_vec();
+
+ let (result, _) = results.last().unwrap();
+ format!("{}", result + 15)
+}
diff --git a/src/days/day07/mod.rs b/src/days/day07/mod.rs
new file mode 100644
index 0000000..fda6bcb
--- /dev/null
+++ b/src/days/day07/mod.rs
@@ -0,0 +1,18 @@
+use crate::template::Solution;
+use anyhow::Result;
+
+mod part1;
+mod part2;
+pub struct Day07;
+
+const DATA: &str = include_str!("../../../data/day07.txt");
+
+impl Solution for Day07 {
+ fn solve_part1(&self) -> Result {
+ Ok(part1::solve(DATA))
+ }
+
+ fn solve_part2(&self) -> Result {
+ Ok(part2::solve(DATA))
+ }
+}
diff --git a/src/days/day07/part1.rs b/src/days/day07/part1.rs
new file mode 100644
index 0000000..eb70e81
--- /dev/null
+++ b/src/days/day07/part1.rs
@@ -0,0 +1,3 @@
+pub fn solve(_raw: &str) -> String {
+ String::from("UNSOLVED")
+}
diff --git a/src/days/day07/part2.rs b/src/days/day07/part2.rs
new file mode 100644
index 0000000..eb70e81
--- /dev/null
+++ b/src/days/day07/part2.rs
@@ -0,0 +1,3 @@
+pub fn solve(_raw: &str) -> String {
+ String::from("UNSOLVED")
+}
diff --git a/src/days/day10/mod.rs b/src/days/day10/mod.rs
new file mode 100644
index 0000000..00236bf
--- /dev/null
+++ b/src/days/day10/mod.rs
@@ -0,0 +1,131 @@
+use crate::template::Solution;
+use anyhow::Result;
+
+#[derive(Debug, Clone)]
+enum Instruction {
+ Noop,
+ Addx(isize),
+}
+
+#[derive(Debug, Clone)]
+struct Program {
+ pub instructions: Vec,
+}
+
+#[derive(Debug, Clone)]
+struct Machine {
+ pub accumulator: isize,
+ pub queue: Vec<(Instruction, u8)>,
+ pub program: Program,
+}
+
+impl Machine {
+ pub fn new(program: Program) -> Self {
+ Self {
+ accumulator: 1,
+ queue: vec![],
+ program,
+ }
+ }
+
+ pub fn run(&mut self) -> Result> {
+ let mut instructions: Vec = self
+ .program
+ .instructions
+ .clone()
+ .into_iter()
+ .rev()
+ .collect();
+ let mut cycles: usize = 0;
+ let mut results: Vec<(usize, isize)> = vec![];
+ 'machine: loop {
+ if let Some(current_instruction) = instructions.pop() {
+ match current_instruction {
+ Instruction::Noop => {
+ cycles += 1;
+ results.push((cycles, self.accumulator));
+ }
+ Instruction::Addx(num) => {
+ cycles += 2;
+ results.push((cycles - 1, self.accumulator));
+ self.accumulator += num;
+ results.push((cycles, self.accumulator));
+ }
+ }
+ } else {
+ break 'machine;
+ }
+ }
+
+ Ok(results)
+ }
+}
+
+mod parser {
+ use super::{Instruction, Program};
+ use nom::{
+ branch::alt,
+ bytes::complete::tag,
+ character::complete::{digit1, line_ending, space1},
+ combinator::{eof, map_res},
+ multi::many1,
+ sequence::{preceded, tuple},
+ IResult,
+ };
+
+ pub fn parse<'a>(input: &'a str) -> IResult<&str, Program> {
+ let noop_parser = |inp: &'a str| -> IResult<&str, Instruction> {
+ map_res(tuple((tag("noop"), alt((line_ending, eof)))), |_| {
+ Ok::>(Instruction::Noop)
+ })(inp)
+ };
+
+ let number_parser = |inp: &'a str| -> IResult<&str, isize> {
+ alt((
+ map_res(preceded(tag("-"), digit1), |num: &str| {
+ Ok::>(0 - num.parse::().unwrap_or_default())
+ }),
+ map_res(digit1, |num: &str| num.parse::()),
+ ))(inp)
+ };
+
+ let addx_parser = |inp: &'a str| -> IResult<&str, Instruction> {
+ map_res(
+ tuple((tag("addx"), space1, number_parser, alt((line_ending, eof)))),
+ |(_, _, num, _)| Ok::>(Instruction::Addx(num)),
+ )(inp)
+ };
+
+ let program_paser = |inp: &'a str| -> IResult<&str, Program> {
+ map_res(many1(alt((addx_parser, noop_parser))), |result| {
+ let instructions = result.iter().map(|i| i.clone()).collect();
+ Ok::>(Program { instructions })
+ })(inp)
+ };
+
+ program_paser(input)
+ }
+}
+
+pub struct Day10;
+
+const DATA: &str = include_str!("../../../data/day10.txt");
+
+impl Solution for Day10 {
+ fn solve_part1(&self) -> Result {
+ let (_, program) = parser::parse(DATA)?;
+ let mut machine = Machine::new(program);
+ let results = machine.run()?;
+ let signal_strengths = results
+ .into_iter()
+ .map(|(cyc, acc)| (cyc as isize) * acc)
+ .collect::>();
+
+ dbg!(signal_strengths[19]);
+ Ok("".to_string())
+ }
+
+ fn solve_part2(&self) -> Result {
+ Ok("".to_string())
+ }
+}
diff --git a/src/days/mod.rs b/src/days/mod.rs
new file mode 100644
index 0000000..3a57178
--- /dev/null
+++ b/src/days/mod.rs
@@ -0,0 +1,24 @@
+pub mod day01;
+pub mod day02;
+pub mod day03;
+pub mod day04;
+pub mod day05;
+pub mod day06;
+pub mod day07;
+pub mod day10;
+
+use crate::template::Solution;
+
+pub fn fetch(day: u32) -> Box {
+ match day {
+ 1 => Box::new(day01::Day01),
+ 2 => Box::new(day02::Day02),
+ 3 => Box::new(day03::Day03),
+ 4 => Box::new(day04::Day04),
+ 5 => Box::new(day05::Day05),
+ 6 => Box::new(day06::Day06),
+ 7 => Box::new(day07::Day07),
+ 10 => Box::new(day10::Day10),
+ _ => panic!("Day {} not implemented", day),
+ }
+}
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..0670587
--- /dev/null
+++ b/src/main.rs
@@ -0,0 +1,15 @@
+mod days;
+mod template;
+
+use std::env::args;
+use anyhow::Result;
+
+fn main() -> Result<()> {
+ let day = args().nth(1).expect("[ERR] Solution Day Not Specified!").parse::()?;
+ let solver = days::fetch(day);
+
+ println!("Solution for Day {}", day);
+ println!("Part 1: {}", solver.solve_part1()?);
+ println!("Part 2: {}", solver.solve_part2()?);
+ Ok(())
+}
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/template.rs b/src/template.rs
new file mode 100644
index 0000000..5fa8390
--- /dev/null
+++ b/src/template.rs
@@ -0,0 +1,6 @@
+use anyhow::Result;
+
+pub trait Solution {
+ fn solve_part1(&self) -> Result;
+ fn solve_part2(&self) -> Result;
+}
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)
-}