commit cc42c33b5db5d8cb286dcffb95286550b17ffa25 Author: LeMoonStar Date: Sat Nov 30 13:39:19 2024 +0100 ๐ŸŽ‰ Initialized repository based on 2023 code diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a8a44e6 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +/target +.aoc23_cache \ No newline at end of file diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..3609d01 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,21 @@ +[package] +name = "aoc24" +version = "0.1.0" +edition = "2024" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +clap = { version = "2.34", features = ["suggestions", "color", "wrap_help"] } +colored = "2.0" +aoc-macro = {path="aoc-macro"} +reqwest = { version = "0.11", features=["cookies", "blocking"] } +mut_static="5.0" +lazy_static="1.4" + +[profile.release] +opt-level = 3 +lto = true +codegen-units = 1 +panic = 'abort' +strip = true diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..ef476cc --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2024 LeMoonStar + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..d321dcf --- /dev/null +++ b/README.md @@ -0,0 +1,49 @@ +# Advent of Code 2024 + +[![About](https://img.shields.io/badge/Advent%20of%20Code-2024-brightgreen?style=flat-square)](https://adventofcode.com/2024/about) +[![Language: Rust](https://img.shields.io/badge/Language-Rust-orange.svg?style=flat-square)](https://en.wikipedia.org/wiki/Rust_(programming_language)) +[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg?style=flat-square)](https://mit-license.org/) +![Days completed](https://img.shields.io/badge/Days%20completed-0-red?style=flat-square) +![Stars](https://img.shields.io/badge/Stars-0-yellow?style=flat-square) + +> โš ๏ธ This README is copied from my previous years solution. It is not fully adopted to 2024 yet. + +Last Years README: +> This is the third year in a row I (plan to) use rust to solve Advent of Code. But I must warn you: I haven't programmed a lot over the past year, so I am likely not in the best shape (School has been rough - I need a break) - expect the worst. +> Just like last year, I am lazy and currently setting this project up in a hurry (In class, actually) just so I have the basic framework once the event starts. So this project is literally a cleaned-up copy of my [solutions for the previous year](https://github.com/LeMoonStar/AoC22), which in term are a cleaned up version of my [Advent of Code 2021 solutions](https://github.com/LeMoonStar/AoC21). +> **The Following therefore still contains screenshots of the 2021 binary. The usage is the same, but the name is `aoc24` instead of `aoc21`** +> +> Later on, maybe even before AoC starts, I'll clean this up more, maybe create a crate out of the framework so I don't have to copy each year over and over again. + +Well, not much changed. This is now the fourth year I'll use Rust - after not using Rust in a while and likely with a lot less time at hand. We'll see how it goes. I am finally out of school tough - that's a relief! + +## Usage + +There are multiple ways to run my solutions, the easiest and most comfortable one is the `auto` command: +It automatically downloads your input. For this it requires you to provide your Advent of Code session id, which you can find in the websites cookies after logging in. +Simply provide the session token by setting the `AOC_SESSION` environment variable or using the -s argument: +`AOC_SESSION=XXXMYSESSION ./aoc24 [DAY] auto` or `./aoc24 [DAY] auto -s XXXMYSESSION`. +In this example, the environment variable for the AoC session is set using `export AOC_SESSION=XXXMYSESSION`, so I can run the command without specifying the session token again: +![auto command in action](./images/auto.png) + +If you don't want to automatically download the input, you can also use the `run` command, which uses a locally stored file or the stdin input: +`./aoc24 [DAY] run -f my_input.txt`: +![run command in action](./images/run.png) + +If you just want to run the day's example, simply use the `test` command, as this project already includes the examples: +`./aoc24 [DAY] test`: +![test command in action](./images/test.png) + +## Compiling + +This project uses `Cargo`, so compiling is pretty easy: +`cargo build --release` +The resulting binary can be found at `./targets/release/aoc22`. You can also directly run the project using `cargo run --release [arguments for aoc24]` +the `--release` option is not required, but it results in better performance. + +## Check out other AoC24 solutions + +| Repository | Language | +|----------------------------------------------------------------------------------|----------| +| [Trojaner's AdventofCode2024](https://github.com/TrojanerHD/AdventofCode2024) | Rust | +| [Niklas' Advent-of-Code-2024](https://github.com/derNiklaas/Advent-of-Code-2024) | Kotlin | diff --git a/aoc-macro/.gitignore b/aoc-macro/.gitignore new file mode 100644 index 0000000..ea8c4bf --- /dev/null +++ b/aoc-macro/.gitignore @@ -0,0 +1 @@ +/target diff --git a/aoc-macro/Cargo.lock b/aoc-macro/Cargo.lock new file mode 100644 index 0000000..264c9d7 --- /dev/null +++ b/aoc-macro/Cargo.lock @@ -0,0 +1,46 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "aoc-macro" +version = "0.1.0" +dependencies = [ + "quote", + "syn", +] + +[[package]] +name = "proc-macro2" +version = "1.0.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba508cc11742c0dc5c1659771673afbab7a0efab23aa17e854cbab0837ed0b43" +dependencies = [ + "unicode-xid", +] + +[[package]] +name = "quote" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38bc8cc6a5f2e3655e0899c1b848643b2562f853f114bfec7be120678e3ace05" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "syn" +version = "1.0.82" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8daf5dd0bb60cbd4137b1b587d2fc0ae729bc07cf01cd70b36a1ed5ade3b9d59" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + +[[package]] +name = "unicode-xid" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" diff --git a/aoc-macro/Cargo.toml b/aoc-macro/Cargo.toml new file mode 100644 index 0000000..9d3a4f5 --- /dev/null +++ b/aoc-macro/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "aoc-macro" +version = "0.1.0" +edition = "2021" + +[lib] +proc-macro=true + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +quote = "^1.0" +syn = "^1.0" diff --git a/aoc-macro/src/lib.rs b/aoc-macro/src/lib.rs new file mode 100644 index 0000000..672cf04 --- /dev/null +++ b/aoc-macro/src/lib.rs @@ -0,0 +1,108 @@ +use proc_macro::TokenStream; +use quote::quote; + +// Again, huge thanks to andi_makes +// this is basically a copy of his macros, with very slight modifications. + +#[proc_macro] +pub fn mod_days(_input: TokenStream) -> TokenStream { + let mut res = String::new(); + for i in 1..26 { + res += &format!("mod d{:02};", i); + } + res.parse().unwrap() +} + +/*#[proc_macro] +pub fn match_and_run_day(_input: TokenStream) -> TokenStream { + let mut res = "match day {".to_string(); + for i in 1..26 { + res += &format!("{} => Day::<{}>::run_timed(input),", i, i); + } + res += "_ => panic!(\"Days out of Bounds! No presents for you!\")};"; + res.parse().unwrap() +}*/ + +#[proc_macro] +pub fn match_and_run_day_both(_input: TokenStream) -> TokenStream { + let r = 1_u8..26; // == [1,25] + let res = quote! { + match day { + #(#r => { + Day::<#r>::run_timed(input.trim_end()) + })* + _ => panic!("Days out of Bounds! No presents for you!"), + } + }; + res.into() +} + +#[proc_macro] +pub fn match_and_run_day_one(_input: TokenStream) -> TokenStream { + let r = 1_u8..26; // == [1,25] + let res = quote! { + match day { + #(#r => { + Day::<#r>::run_one_timed(input.trim_end()) + })* + _ => panic!("Days out of Bounds! No presents for you!"), + } + }; + res.into() +} + +#[proc_macro] +pub fn match_and_run_day_two(_input: TokenStream) -> TokenStream { + let r = 1_u8..26; // == [1,25] + let res = quote! { + match day { + #(#r => { + Day::<#r>::run_two_timed(input.trim_end()) + })* + _ => panic!("Days out of Bounds! No presents for you!"), + } + }; + res.into() +} + +#[proc_macro] +pub fn match_and_test_day_both(_input: TokenStream) -> TokenStream { + let r = 1_u8..26; // == [1,25] + let res = quote! { + match day { + #(#r => { + Day::<#r>::test() + })* + _ => panic!("Days out of Bounds! No presents for you!"), + } + }; + res.into() +} + +#[proc_macro] +pub fn match_and_test_day_one(_input: TokenStream) -> TokenStream { + let r = 1_u8..26; // == [1,25] + let res = quote! { + match day { + #(#r => { + Day::<#r>::test_one() + })* + _ => panic!("Days out of Bounds! No presents for you!"), + } + }; + res.into() +} + +#[proc_macro] +pub fn match_and_test_day_two(_input: TokenStream) -> TokenStream { + let r = 1_u8..26; // == [1,25] + let res = quote! { + match day { + #(#r => { + Day::<#r>::test_two() + })* + _ => panic!("Days out of Bounds! No presents for you!"), + } + }; + res.into() +} diff --git a/images/auto.png b/images/auto.png new file mode 100644 index 0000000..79c7676 Binary files /dev/null and b/images/auto.png differ diff --git a/images/run.png b/images/run.png new file mode 100644 index 0000000..4c93c40 Binary files /dev/null and b/images/run.png differ diff --git a/images/test.png b/images/test.png new file mode 100644 index 0000000..60ece3e Binary files /dev/null and b/images/test.png differ diff --git a/src/days/d01.rs b/src/days/d01.rs new file mode 100644 index 0000000..f857a01 --- /dev/null +++ b/src/days/d01.rs @@ -0,0 +1,32 @@ +use super::{Answer, Day, DayImpl}; + +const CURRENT_DAY: u8 = 1; + +type Data = Vec; +impl DayImpl for Day { + fn init_test() -> (Self, Data) { + Self::init(include_str!("test_inputs/test01.txt")) + } + + fn expected_results() -> (Answer, Answer) { + (Answer::Number(0), Answer::Number(0)) + } + + fn init(input: &str) -> (Self, Data) { + ( + Self {}, + input + .lines() + .map(|v| v.parse::().expect("error while parsing input.")) + .collect(), + ) + } + + fn one(&self, data: &mut Data) -> Answer { + Answer::Number(data.len() as u64) + } + + fn two(&self, data: &mut Data) -> Answer { + Answer::Number(data.len() as u64) + } +} diff --git a/src/days/d02.rs b/src/days/d02.rs new file mode 100644 index 0000000..bc6dd3d --- /dev/null +++ b/src/days/d02.rs @@ -0,0 +1,32 @@ +use super::{Answer, Day, DayImpl}; + +const CURRENT_DAY: u8 = 2; + +type Data = Vec; +impl DayImpl for Day { + fn init_test() -> (Self, Data) { + Self::init(include_str!("test_inputs/test02.txt")) + } + + fn expected_results() -> (Answer, Answer) { + (Answer::Number(0), Answer::Number(0)) + } + + fn init(input: &str) -> (Self, Data) { + ( + Self {}, + input + .lines() + .map(|v| v.parse::().expect("error while parsing input.")) + .collect(), + ) + } + + fn one(&self, data: &mut Data) -> Answer { + Answer::Number(data.len() as u64) + } + + fn two(&self, data: &mut Data) -> Answer { + Answer::Number(data.len() as u64) + } +} diff --git a/src/days/d03.rs b/src/days/d03.rs new file mode 100644 index 0000000..59c0ad7 --- /dev/null +++ b/src/days/d03.rs @@ -0,0 +1,32 @@ +use super::{Answer, Day, DayImpl}; + +const CURRENT_DAY: u8 = 3; + +type Data = Vec; +impl DayImpl for Day { + fn init_test() -> (Self, Data) { + Self::init(include_str!("test_inputs/test03.txt")) + } + + fn expected_results() -> (Answer, Answer) { + (Answer::Number(0), Answer::Number(0)) + } + + fn init(input: &str) -> (Self, Data) { + ( + Self {}, + input + .lines() + .map(|v| v.parse::().expect("error while parsing input.")) + .collect(), + ) + } + + fn one(&self, data: &mut Data) -> Answer { + Answer::Number(data.len() as u64) + } + + fn two(&self, data: &mut Data) -> Answer { + Answer::Number(data.len() as u64) + } +} diff --git a/src/days/d04.rs b/src/days/d04.rs new file mode 100644 index 0000000..0cda657 --- /dev/null +++ b/src/days/d04.rs @@ -0,0 +1,32 @@ +use super::{Answer, Day, DayImpl}; + +const CURRENT_DAY: u8 = 4; + +type Data = Vec; +impl DayImpl for Day { + fn init_test() -> (Self, Data) { + Self::init(include_str!("test_inputs/test04.txt")) + } + + fn expected_results() -> (Answer, Answer) { + (Answer::Number(0), Answer::Number(0)) + } + + fn init(input: &str) -> (Self, Data) { + ( + Self {}, + input + .lines() + .map(|v| v.parse::().expect("error while parsing input.")) + .collect(), + ) + } + + fn one(&self, data: &mut Data) -> Answer { + Answer::Number(data.len() as u64) + } + + fn two(&self, data: &mut Data) -> Answer { + Answer::Number(data.len() as u64) + } +} diff --git a/src/days/d05.rs b/src/days/d05.rs new file mode 100644 index 0000000..c0f3fc9 --- /dev/null +++ b/src/days/d05.rs @@ -0,0 +1,32 @@ +use super::{Answer, Day, DayImpl}; + +const CURRENT_DAY: u8 = 5; + +type Data = Vec; +impl DayImpl for Day { + fn init_test() -> (Self, Data) { + Self::init(include_str!("test_inputs/test05.txt")) + } + + fn expected_results() -> (Answer, Answer) { + (Answer::Number(0), Answer::Number(0)) + } + + fn init(input: &str) -> (Self, Data) { + ( + Self {}, + input + .lines() + .map(|v| v.parse::().expect("error while parsing input.")) + .collect(), + ) + } + + fn one(&self, data: &mut Data) -> Answer { + Answer::Number(data.len() as u64) + } + + fn two(&self, data: &mut Data) -> Answer { + Answer::Number(data.len() as u64) + } +} diff --git a/src/days/d06.rs b/src/days/d06.rs new file mode 100644 index 0000000..86d4a69 --- /dev/null +++ b/src/days/d06.rs @@ -0,0 +1,32 @@ +use super::{Answer, Day, DayImpl}; + +const CURRENT_DAY: u8 = 6; + +type Data = Vec; +impl DayImpl for Day { + fn init_test() -> (Self, Data) { + Self::init(include_str!("test_inputs/test06.txt")) + } + + fn expected_results() -> (Answer, Answer) { + (Answer::Number(0), Answer::Number(0)) + } + + fn init(input: &str) -> (Self, Data) { + ( + Self {}, + input + .lines() + .map(|v| v.parse::().expect("error while parsing input.")) + .collect(), + ) + } + + fn one(&self, data: &mut Data) -> Answer { + Answer::Number(data.len() as u64) + } + + fn two(&self, data: &mut Data) -> Answer { + Answer::Number(data.len() as u64) + } +} diff --git a/src/days/d07.rs b/src/days/d07.rs new file mode 100644 index 0000000..f8e20e3 --- /dev/null +++ b/src/days/d07.rs @@ -0,0 +1,32 @@ +use super::{Answer, Day, DayImpl}; + +const CURRENT_DAY: u8 = 7; + +type Data = Vec; +impl DayImpl for Day { + fn init_test() -> (Self, Data) { + Self::init(include_str!("test_inputs/test07.txt")) + } + + fn expected_results() -> (Answer, Answer) { + (Answer::Number(0), Answer::Number(0)) + } + + fn init(input: &str) -> (Self, Data) { + ( + Self {}, + input + .lines() + .map(|v| v.parse::().expect("error while parsing input.")) + .collect(), + ) + } + + fn one(&self, data: &mut Data) -> Answer { + Answer::Number(data.len() as u64) + } + + fn two(&self, data: &mut Data) -> Answer { + Answer::Number(data.len() as u64) + } +} diff --git a/src/days/d08.rs b/src/days/d08.rs new file mode 100644 index 0000000..e504bf8 --- /dev/null +++ b/src/days/d08.rs @@ -0,0 +1,32 @@ +use super::{Answer, Day, DayImpl}; + +const CURRENT_DAY: u8 = 8; + +type Data = Vec; +impl DayImpl for Day { + fn init_test() -> (Self, Data) { + Self::init(include_str!("test_inputs/test08.txt")) + } + + fn expected_results() -> (Answer, Answer) { + (Answer::Number(0), Answer::Number(0)) + } + + fn init(input: &str) -> (Self, Data) { + ( + Self {}, + input + .lines() + .map(|v| v.parse::().expect("error while parsing input.")) + .collect(), + ) + } + + fn one(&self, data: &mut Data) -> Answer { + Answer::Number(data.len() as u64) + } + + fn two(&self, data: &mut Data) -> Answer { + Answer::Number(data.len() as u64) + } +} diff --git a/src/days/d09.rs b/src/days/d09.rs new file mode 100644 index 0000000..116e3a8 --- /dev/null +++ b/src/days/d09.rs @@ -0,0 +1,32 @@ +use super::{Answer, Day, DayImpl}; + +const CURRENT_DAY: u8 = 9; + +type Data = Vec; +impl DayImpl for Day { + fn init_test() -> (Self, Data) { + Self::init(include_str!("test_inputs/test09.txt")) + } + + fn expected_results() -> (Answer, Answer) { + (Answer::Number(0), Answer::Number(0)) + } + + fn init(input: &str) -> (Self, Data) { + ( + Self {}, + input + .lines() + .map(|v| v.parse::().expect("error while parsing input.")) + .collect(), + ) + } + + fn one(&self, data: &mut Data) -> Answer { + Answer::Number(data.len() as u64) + } + + fn two(&self, data: &mut Data) -> Answer { + Answer::Number(data.len() as u64) + } +} diff --git a/src/days/d10.rs b/src/days/d10.rs new file mode 100644 index 0000000..d01bcab --- /dev/null +++ b/src/days/d10.rs @@ -0,0 +1,32 @@ +use super::{Answer, Day, DayImpl}; + +const CURRENT_DAY: u8 = 10; + +type Data = Vec; +impl DayImpl for Day { + fn init_test() -> (Self, Data) { + Self::init(include_str!("test_inputs/test10.txt")) + } + + fn expected_results() -> (Answer, Answer) { + (Answer::Number(0), Answer::Number(0)) + } + + fn init(input: &str) -> (Self, Data) { + ( + Self {}, + input + .lines() + .map(|v| v.parse::().expect("error while parsing input.")) + .collect(), + ) + } + + fn one(&self, data: &mut Data) -> Answer { + Answer::Number(data.len() as u64) + } + + fn two(&self, data: &mut Data) -> Answer { + Answer::Number(data.len() as u64) + } +} diff --git a/src/days/d11.rs b/src/days/d11.rs new file mode 100644 index 0000000..0f737b0 --- /dev/null +++ b/src/days/d11.rs @@ -0,0 +1,32 @@ +use super::{Answer, Day, DayImpl}; + +const CURRENT_DAY: u8 = 11; + +type Data = Vec; +impl DayImpl for Day { + fn init_test() -> (Self, Data) { + Self::init(include_str!("test_inputs/test11.txt")) + } + + fn expected_results() -> (Answer, Answer) { + (Answer::Number(0), Answer::Number(0)) + } + + fn init(input: &str) -> (Self, Data) { + ( + Self {}, + input + .lines() + .map(|v| v.parse::().expect("error while parsing input.")) + .collect(), + ) + } + + fn one(&self, data: &mut Data) -> Answer { + Answer::Number(data.len() as u64) + } + + fn two(&self, data: &mut Data) -> Answer { + Answer::Number(data.len() as u64) + } +} diff --git a/src/days/d12.rs b/src/days/d12.rs new file mode 100644 index 0000000..9f26cd5 --- /dev/null +++ b/src/days/d12.rs @@ -0,0 +1,32 @@ +use super::{Answer, Day, DayImpl}; + +const CURRENT_DAY: u8 = 12; + +type Data = Vec; +impl DayImpl for Day { + fn init_test() -> (Self, Data) { + Self::init(include_str!("test_inputs/test12.txt")) + } + + fn expected_results() -> (Answer, Answer) { + (Answer::Number(0), Answer::Number(0)) + } + + fn init(input: &str) -> (Self, Data) { + ( + Self {}, + input + .lines() + .map(|v| v.parse::().expect("error while parsing input.")) + .collect(), + ) + } + + fn one(&self, data: &mut Data) -> Answer { + Answer::Number(data.len() as u64) + } + + fn two(&self, data: &mut Data) -> Answer { + Answer::Number(data.len() as u64) + } +} diff --git a/src/days/d13.rs b/src/days/d13.rs new file mode 100644 index 0000000..5d38c35 --- /dev/null +++ b/src/days/d13.rs @@ -0,0 +1,32 @@ +use super::{Answer, Day, DayImpl}; + +const CURRENT_DAY: u8 = 13; + +type Data = Vec; +impl DayImpl for Day { + fn init_test() -> (Self, Data) { + Self::init(include_str!("test_inputs/test13.txt")) + } + + fn expected_results() -> (Answer, Answer) { + (Answer::Number(0), Answer::Number(0)) + } + + fn init(input: &str) -> (Self, Data) { + ( + Self {}, + input + .lines() + .map(|v| v.parse::().expect("error while parsing input.")) + .collect(), + ) + } + + fn one(&self, data: &mut Data) -> Answer { + Answer::Number(data.len() as u64) + } + + fn two(&self, data: &mut Data) -> Answer { + Answer::Number(data.len() as u64) + } +} diff --git a/src/days/d14.rs b/src/days/d14.rs new file mode 100644 index 0000000..052771b --- /dev/null +++ b/src/days/d14.rs @@ -0,0 +1,32 @@ +use super::{Answer, Day, DayImpl}; + +const CURRENT_DAY: u8 = 14; + +type Data = Vec; +impl DayImpl for Day { + fn init_test() -> (Self, Data) { + Self::init(include_str!("test_inputs/test14.txt")) + } + + fn expected_results() -> (Answer, Answer) { + (Answer::Number(0), Answer::Number(0)) + } + + fn init(input: &str) -> (Self, Data) { + ( + Self {}, + input + .lines() + .map(|v| v.parse::().expect("error while parsing input.")) + .collect(), + ) + } + + fn one(&self, data: &mut Data) -> Answer { + Answer::Number(data.len() as u64) + } + + fn two(&self, data: &mut Data) -> Answer { + Answer::Number(data.len() as u64) + } +} diff --git a/src/days/d15.rs b/src/days/d15.rs new file mode 100644 index 0000000..c854d98 --- /dev/null +++ b/src/days/d15.rs @@ -0,0 +1,32 @@ +use super::{Answer, Day, DayImpl}; + +const CURRENT_DAY: u8 = 15; + +type Data = Vec; +impl DayImpl for Day { + fn init_test() -> (Self, Data) { + Self::init(include_str!("test_inputs/test15.txt")) + } + + fn expected_results() -> (Answer, Answer) { + (Answer::Number(0), Answer::Number(0)) + } + + fn init(input: &str) -> (Self, Data) { + ( + Self {}, + input + .lines() + .map(|v| v.parse::().expect("error while parsing input.")) + .collect(), + ) + } + + fn one(&self, data: &mut Data) -> Answer { + Answer::Number(data.len() as u64) + } + + fn two(&self, data: &mut Data) -> Answer { + Answer::Number(data.len() as u64) + } +} diff --git a/src/days/d16.rs b/src/days/d16.rs new file mode 100644 index 0000000..ff2ca9f --- /dev/null +++ b/src/days/d16.rs @@ -0,0 +1,32 @@ +use super::{Answer, Day, DayImpl}; + +const CURRENT_DAY: u8 = 16; + +type Data = Vec; +impl DayImpl for Day { + fn init_test() -> (Self, Data) { + Self::init(include_str!("test_inputs/test16.txt")) + } + + fn expected_results() -> (Answer, Answer) { + (Answer::Number(0), Answer::Number(0)) + } + + fn init(input: &str) -> (Self, Data) { + ( + Self {}, + input + .lines() + .map(|v| v.parse::().expect("error while parsing input.")) + .collect(), + ) + } + + fn one(&self, data: &mut Data) -> Answer { + Answer::Number(data.len() as u64) + } + + fn two(&self, data: &mut Data) -> Answer { + Answer::Number(data.len() as u64) + } +} diff --git a/src/days/d17.rs b/src/days/d17.rs new file mode 100644 index 0000000..a560223 --- /dev/null +++ b/src/days/d17.rs @@ -0,0 +1,32 @@ +use super::{Answer, Day, DayImpl}; + +const CURRENT_DAY: u8 = 17; + +type Data = Vec; +impl DayImpl for Day { + fn init_test() -> (Self, Data) { + Self::init(include_str!("test_inputs/test17.txt")) + } + + fn expected_results() -> (Answer, Answer) { + (Answer::Number(0), Answer::Number(0)) + } + + fn init(input: &str) -> (Self, Data) { + ( + Self {}, + input + .lines() + .map(|v| v.parse::().expect("error while parsing input.")) + .collect(), + ) + } + + fn one(&self, data: &mut Data) -> Answer { + Answer::Number(data.len() as u64) + } + + fn two(&self, data: &mut Data) -> Answer { + Answer::Number(data.len() as u64) + } +} diff --git a/src/days/d18.rs b/src/days/d18.rs new file mode 100644 index 0000000..b20618d --- /dev/null +++ b/src/days/d18.rs @@ -0,0 +1,32 @@ +use super::{Answer, Day, DayImpl}; + +const CURRENT_DAY: u8 = 18; + +type Data = Vec; +impl DayImpl for Day { + fn init_test() -> (Self, Data) { + Self::init(include_str!("test_inputs/test18.txt")) + } + + fn expected_results() -> (Answer, Answer) { + (Answer::Number(0), Answer::Number(0)) + } + + fn init(input: &str) -> (Self, Data) { + ( + Self {}, + input + .lines() + .map(|v| v.parse::().expect("error while parsing input.")) + .collect(), + ) + } + + fn one(&self, data: &mut Data) -> Answer { + Answer::Number(data.len() as u64) + } + + fn two(&self, data: &mut Data) -> Answer { + Answer::Number(data.len() as u64) + } +} diff --git a/src/days/d19.rs b/src/days/d19.rs new file mode 100644 index 0000000..a135609 --- /dev/null +++ b/src/days/d19.rs @@ -0,0 +1,32 @@ +use super::{Answer, Day, DayImpl}; + +const CURRENT_DAY: u8 = 19; + +type Data = Vec; +impl DayImpl for Day { + fn init_test() -> (Self, Data) { + Self::init(include_str!("test_inputs/test19.txt")) + } + + fn expected_results() -> (Answer, Answer) { + (Answer::Number(0), Answer::Number(0)) + } + + fn init(input: &str) -> (Self, Data) { + ( + Self {}, + input + .lines() + .map(|v| v.parse::().expect("error while parsing input.")) + .collect(), + ) + } + + fn one(&self, data: &mut Data) -> Answer { + Answer::Number(data.len() as u64) + } + + fn two(&self, data: &mut Data) -> Answer { + Answer::Number(data.len() as u64) + } +} diff --git a/src/days/d20.rs b/src/days/d20.rs new file mode 100644 index 0000000..cacc372 --- /dev/null +++ b/src/days/d20.rs @@ -0,0 +1,32 @@ +use super::{Answer, Day, DayImpl}; + +const CURRENT_DAY: u8 = 20; + +type Data = Vec; +impl DayImpl for Day { + fn init_test() -> (Self, Data) { + Self::init(include_str!("test_inputs/test20.txt")) + } + + fn expected_results() -> (Answer, Answer) { + (Answer::Number(0), Answer::Number(0)) + } + + fn init(input: &str) -> (Self, Data) { + ( + Self {}, + input + .lines() + .map(|v| v.parse::().expect("error while parsing input.")) + .collect(), + ) + } + + fn one(&self, data: &mut Data) -> Answer { + Answer::Number(data.len() as u64) + } + + fn two(&self, data: &mut Data) -> Answer { + Answer::Number(data.len() as u64) + } +} diff --git a/src/days/d21.rs b/src/days/d21.rs new file mode 100644 index 0000000..96be39b --- /dev/null +++ b/src/days/d21.rs @@ -0,0 +1,32 @@ +use super::{Answer, Day, DayImpl}; + +const CURRENT_DAY: u8 = 21; + +type Data = Vec; +impl DayImpl for Day { + fn init_test() -> (Self, Data) { + Self::init(include_str!("test_inputs/test21.txt")) + } + + fn expected_results() -> (Answer, Answer) { + (Answer::Number(0), Answer::Number(0)) + } + + fn init(input: &str) -> (Self, Data) { + ( + Self {}, + input + .lines() + .map(|v| v.parse::().expect("error while parsing input.")) + .collect(), + ) + } + + fn one(&self, data: &mut Data) -> Answer { + Answer::Number(data.len() as u64) + } + + fn two(&self, data: &mut Data) -> Answer { + Answer::Number(data.len() as u64) + } +} diff --git a/src/days/d22.rs b/src/days/d22.rs new file mode 100644 index 0000000..99a17bc --- /dev/null +++ b/src/days/d22.rs @@ -0,0 +1,32 @@ +use super::{Answer, Day, DayImpl}; + +const CURRENT_DAY: u8 = 22; + +type Data = Vec; +impl DayImpl for Day { + fn init_test() -> (Self, Data) { + Self::init(include_str!("test_inputs/test22.txt")) + } + + fn expected_results() -> (Answer, Answer) { + (Answer::Number(0), Answer::Number(0)) + } + + fn init(input: &str) -> (Self, Data) { + ( + Self {}, + input + .lines() + .map(|v| v.parse::().expect("error while parsing input.")) + .collect(), + ) + } + + fn one(&self, data: &mut Data) -> Answer { + Answer::Number(data.len() as u64) + } + + fn two(&self, data: &mut Data) -> Answer { + Answer::Number(data.len() as u64) + } +} diff --git a/src/days/d23.rs b/src/days/d23.rs new file mode 100644 index 0000000..505505a --- /dev/null +++ b/src/days/d23.rs @@ -0,0 +1,32 @@ +use super::{Answer, Day, DayImpl}; + +const CURRENT_DAY: u8 = 23; + +type Data = Vec; +impl DayImpl for Day { + fn init_test() -> (Self, Data) { + Self::init(include_str!("test_inputs/test23.txt")) + } + + fn expected_results() -> (Answer, Answer) { + (Answer::Number(0), Answer::Number(0)) + } + + fn init(input: &str) -> (Self, Data) { + ( + Self {}, + input + .lines() + .map(|v| v.parse::().expect("error while parsing input.")) + .collect(), + ) + } + + fn one(&self, data: &mut Data) -> Answer { + Answer::Number(data.len() as u64) + } + + fn two(&self, data: &mut Data) -> Answer { + Answer::Number(data.len() as u64) + } +} diff --git a/src/days/d24.rs b/src/days/d24.rs new file mode 100644 index 0000000..b892460 --- /dev/null +++ b/src/days/d24.rs @@ -0,0 +1,32 @@ +use super::{Answer, Day, DayImpl}; + +const CURRENT_DAY: u8 = 24; + +type Data = Vec; +impl DayImpl for Day { + fn init_test() -> (Self, Data) { + Self::init(include_str!("test_inputs/test24.txt")) + } + + fn expected_results() -> (Answer, Answer) { + (Answer::Number(0), Answer::Number(0)) + } + + fn init(input: &str) -> (Self, Data) { + ( + Self {}, + input + .lines() + .map(|v| v.parse::().expect("error while parsing input.")) + .collect(), + ) + } + + fn one(&self, data: &mut Data) -> Answer { + Answer::Number(data.len() as u64) + } + + fn two(&self, data: &mut Data) -> Answer { + Answer::Number(data.len() as u64) + } +} diff --git a/src/days/d25.rs b/src/days/d25.rs new file mode 100644 index 0000000..dc2783a --- /dev/null +++ b/src/days/d25.rs @@ -0,0 +1,32 @@ +use super::{Answer, Day, DayImpl}; + +const CURRENT_DAY: u8 = 25; + +type Data = Vec; +impl DayImpl for Day { + fn init_test() -> (Self, Data) { + Self::init(include_str!("test_inputs/test25.txt")) + } + + fn expected_results() -> (Answer, Answer) { + (Answer::Number(0), Answer::Number(0)) + } + + fn init(input: &str) -> (Self, Data) { + ( + Self {}, + input + .lines() + .map(|v| v.parse::().expect("error while parsing input.")) + .collect(), + ) + } + + fn one(&self, data: &mut Data) -> Answer { + Answer::Number(data.len() as u64) + } + + fn two(&self, data: &mut Data) -> Answer { + Answer::Number(data.len() as u64) + } +} diff --git a/src/days/mod.rs b/src/days/mod.rs new file mode 100644 index 0000000..59268e1 --- /dev/null +++ b/src/days/mod.rs @@ -0,0 +1,250 @@ +use aoc_macro::mod_days; +use std::time::{Duration, Instant}; + +pub mod utils; + +// Thanks to andi-makes with his AoC project https://github.com/andi-makes/aoc2021, +// this system is heavily inspired by his system. + +pub struct Day; + +#[allow(dead_code)] +#[derive(Debug, Clone, PartialEq)] +pub enum Answer { + Number(u64), + String(String), + Bitmap(Vec>), +} + +impl Answer { + fn append_per_line(str: String, prefix: &str) -> String { + str.lines() + .map(|v| prefix.to_owned() + v + "\n") + .collect::() + .strip_suffix('\n') + .unwrap() + .to_owned() + } + + fn bm_get(bm: &[Vec], x: usize, y: usize) -> bool { + if let Some(line) = bm.get(y) { + if let Some(v) = line.get(x) { + return *v; + } + return false; + } + false + } + + fn minify_bitmap(bm: &Vec>) -> String { + let height = bm.len(); + let width = bm[0].len(); + + let mut out = String::new(); + + for y in (0..height).step_by(2) { + if y != 0 { + out += "\n" + } + for x in (0..width).step_by(2) { + let m = ( + Self::bm_get(bm, x, y), + Self::bm_get(bm, x + 1, y), + Self::bm_get(bm, x, y + 1), + Self::bm_get(bm, x + 1, y + 1), + ); + + out += match m { + (false, false, false, false) => " ", + (true, false, false, false) => "โ–˜", + (false, true, false, false) => "โ–", + (true, true, false, false) => "โ–€", + (false, false, true, false) => "โ––", + (true, false, true, false) => "โ–Œ", + (false, true, true, false) => "โ–ž", + (true, true, true, false) => "โ–›", + (false, false, false, true) => "โ–—", + (true, false, false, true) => "โ–š", + (false, true, false, true) => "โ–", + (true, true, false, true) => "โ–œ", + (false, false, true, true) => "โ–„", + (true, false, true, true) => "โ–™", + (false, true, true, true) => "โ–Ÿ", + (true, true, true, true) => "โ–ˆ", + } + } + } + + Self::append_per_line(out, "\t\t") + } +} + +impl std::fmt::Display for Answer { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + match self { + Self::Number(n) => write!(f, "{}", n), + Self::String(s) => write!(f, "{}", s), + Self::Bitmap(bm) => { + writeln!(f).unwrap(); + write!(f, "{}", Self::minify_bitmap(bm)) + } + } + } +} + +impl From for Answer { + fn from(n: u64) -> Self { + Self::Number(n) + } +} + +impl From for Answer { + fn from(s: String) -> Self { + Self::String(s) + } +} + +pub trait DayImpl +where + T: Clone, +{ + /// Parses the test input. + fn init_test() -> (Self, T) + where + Self: Sized; + + fn expected_results() -> (Answer, Answer); + + /// Parse input + fn init(input: &str) -> (Self, T) + where + Self: Sized; + + /// Compute part 1 + fn one(&self, data: &mut T) -> Answer; + + /// Compute part 2 + fn two(&self, data: &mut T) -> Answer; + + /// Parse input and measure the time it took + fn init_timed(input: &str) -> ((Self, T), Duration) + where + Self: Sized, + { + let s = Instant::now(); + (Self::init(input), s.elapsed()) + } + + /// Compute part 1 and measure the time it took + fn one_timed(&self, data: &mut T) -> (Answer, Duration) { + let s = Instant::now(); + (self.one(data), s.elapsed()) + } + + /// Compute part 2 and measure the time it took + fn two_timed(&self, data: &mut T) -> (Answer, Duration) { + let s = Instant::now(); + (self.two(data), s.elapsed()) + } + + /// Compute both parts + fn run(input: &str) -> (Answer, Answer) + where + Self: Sized, + { + let (day, mut data) = Self::init(input); + (day.one(&mut data.clone()), day.two(&mut data)) + } + + /// Init and compute part 1 + fn run_one(input: &str) -> Answer + where + Self: Sized, + { + let (day, mut data) = Self::init(input); + day.one(&mut data) + } + + /// Init and compute part 1 + fn run_two(input: &str) -> Answer + where + Self: Sized, + { + let (day, mut data) = Self::init(input); + day.two(&mut data) + } + + /// Init and compute part 1 + fn run_one_timed(input: &str) -> (Answer, Duration, Duration) + where + Self: Sized, + { + let ((day, mut data), init_t) = Self::init_timed(input); + let (one, one_t) = day.one_timed(&mut data); + (one, init_t, one_t) + } + + /// Init and compute part 1 + fn run_two_timed(input: &str) -> (Answer, Duration, Duration) + where + Self: Sized, + { + let ((day, mut data), init_t) = Self::init_timed(input); + let (two, two_t) = day.two_timed(&mut data); + (two, init_t, two_t) + } + + /// Compute both parts, and measure the time each step took + fn run_timed(input: &str) -> (Answer, Answer, Duration, Duration, Duration) + where + Self: Sized, + { + let ((day, mut data), i_t) = Self::init_timed(input); + let (one, one_t) = day.one_timed(&mut data.clone()); + let (two, two_t) = day.two_timed(&mut data); + + (one, two, i_t, one_t, two_t) + } + + /// Test part one + fn test_one() -> (bool, Answer, Answer) + where + Self: Sized, + { + let (day, mut data) = Self::init_test(); + let one = day.one(&mut data); + + let (one_e, _) = Self::expected_results(); + + (one_e == one, one, one_e) + } + + /// Test part two + fn test_two() -> (bool, Answer, Answer) + where + Self: Sized, + { + let (day, mut data) = Self::init_test(); + let two = day.two(&mut data); + + let (_, two_e) = Self::expected_results(); + + (two_e == two, two, two_e) + } + + /// Run both tests + fn test() -> ((bool, Answer, Answer), (bool, Answer, Answer)) + where + Self: Sized, + { + let (day, mut data) = Self::init_test(); + let one = day.one(&mut data.clone()); + let two = day.two(&mut data); + + let (one_e, two_e) = Self::expected_results(); + + ((one_e == one, one, one_e), (two_e == two, two, two_e)) + } +} + +mod_days!(); diff --git a/src/days/test_inputs/test01.txt b/src/days/test_inputs/test01.txt new file mode 100644 index 0000000..8a2eb54 --- /dev/null +++ b/src/days/test_inputs/test01.txt @@ -0,0 +1,1000 @@ +51591twosix4dhsxvgghxq +425nine +llvmhjtr8nbbhrfone +lpbjvpbtdfvtxtdvkpjs7qrvddkzmjtlqtg +3sixnineseven +rfmsqbkms7three +33291six +oneonevstpxxrjpnine7six +75sevennine14mzqljsjfbb7two +three6two9jckvk +zprj8394threehczfkncntk +mkqtlrzmzfsix2ccqsnnxtwo4sevenxp9 +tdszrfzspthree2ttzseven5seven +two3fiveckrsjr +four14three7 +4fdkcclmxmxsevenfiver +5sjnnfivefourzxxfpfivenine7five +77sixfive +twofivecrkvmpcpvzddvzcmjhjlthree8fcrrninefive +fivetwo562five +2ninekvdbfnmjmd6ninentpktmgseven92 +2twonine +5fivesprm4ndqzbqnjqx +7jfq9 +1hgnkmx91 +2jcrmhfvntc3lqnine4five4 +zvqmpjrpninejhqrnineggghcrjfd3onefive +11three64qjjhqdnonetwo +rmvzjnbonetwo6 +eightfive698threenine9 +8eighttrfngsklrkfivefourninefourqhclfcp +1z +fivegfslvcvtvs4 +sfq1twosevendbjq2nine4rzmdpmgcx +seven816one8jmcqqhfnthree +twor4325rsl5 +four2vqhninexqqhlfhfouronejks1 +7hjmmxhdnine8 +1eight3hqgshtb147 +four6sixeightone +twomvkjxbqxzhnnmjxstkgfhzzdsc1fivefivesix +3slhhsfnkhhlxtvqfrhvdzzkvlzcnlxgd4ninechp +meightseven8onegghfsfeight84 +kmxckzqdfeightsqfivefivetfg77 +dc8 +mktwonecvqsxhqrjfninethreethreedkllgfxrxrffzvdbqdj2c3 +8shsxjmqmb3kpvj485nd +rbdlrxsmjvnkttnpfour6twoseven +bkt1seven +threehkjhm9 +threeeight8sevennine7nlx +jmvj4ctqpccsixseven +4fourmtwoxcsvlvlhctdpxns +eight7three4729eightbslrgrhs +26seven1 +7ffseven +9rsgmlgcsevenxkmsd17three +snzn6htcqxqj7bf +ppr7six73znmtmgrzrp9 +61mj7dvddfseveneight +threevfive3fourseven3 +xznsxcxsbggvctqqb82two +five4none +foursevenrl12threegpbvdsspkrfour +9sevensixthreerftbxgthree +6fph +996three +64pkndfphqrglbgcpseven +72749twoeightcpqfzqcrns +xnzzhvssixtrlfftrjr5two9threenine +four8hzkkrpb71glpqsnkvcb +sixsix1 +9lfdtwo4sevenjhv911 +chxjljdh8jztwo61three +twothree11 +hft2dmntjgzg1 +rtfckbnqxfdldgttbltdr33kqhxhkeight4 +ninefourseven4nine5 +25fsmkbsevenpzhgdhnxnbsix3 +bd1frglljngg8one1 +34six +96cpcmztffqdrfrfslfour4lpnbmrfm +psxrlseven2zmkvrhckqcxdl91 +ninexkfjcjkjb8three4xeighttqsrgbmfdt +2threesixeight1 +ggxzf3gkdvsqxggltxdhdbhm5 +sixtwo89six +eightnine3 +threemdrhqpone6 +sncpmhtwozsfpcpxgq9three +rtwone37three7xhzlckfclbltdkrgqbcrhpqzg +68sixbgsz35 +kdeightwo69 +four7bfq3four +sixone3fivedgmrrvjqrr7three7seven +sixthree6 +onethree3onevdtlkrfour4 +eight4seven5cszgblfseven +two8ddmjtg +fivejnvrdmghnvrmrjeightnnxpv8 +2threezvklqkpml +two76cdfrmfckbjc +zqxpg42sixeightfour76 +3eightvqpxzsn2bnbkrfb49 +eight85five +sixngs8xjseight4 +296pfsgnlpbmngzlrrldznmrj1mjgvtxkr +six4bvrdgxh +34eight56eightsixhphnbgscfb +two4twosixthreeggfdzlbkxxqmtxtczdfj +four4tqrjxxcrztwoeight +one73zpfhjvjh2 +7eight35phcfcdzhhpzn49eight +zqcmlcqfneightsixrpmmhcrssk6dclcpmhzqhrbcnkxjdfjvrf +1threegkhpq7nfrksvm69nxpvgvthfzoneighttc +gtjsevensixsixb9 +nine73nine +cbhsddcmzmdv2bnnffour +85hhqkqmv +six2jfxfgpg9 +fiveeightskrn1 +khvcf3five8qj5 +sevenfive7ptb +tscc9psz3gtnsnksn +xzlh7zfivefivejgr +one4nine8three3 +2kjkbbvftktkvpbp8gkcnrrkr6r +565three718five +twojjgcfz3fiveoneftvnldxdhr2 +13three +phbvxsnnineksttklfljm85 +tvzpbgzhmbnine1eightbpjtkflllg +7five3 +2623four +nvfchhrbcone1nine +mjv5vtmlmsfcfmt65five1 +7one2 +4six4 +dlbzctlxpjxxqk96pmdgdfblbfjnsxjmkoneqgeight +seven4nzvxldvzvjpzlzxb4eightnine6 +2vzblzhrxnc8qtgvxxzgkeightblqfftjtnxrbpvlsgvd +thfdzxfqcthqfcnrt2 +qxfpbbnfczfourh4twodjrhp +4m2fivelklgfgr6three +4tsbs74 +one6twomzfncms2lrgzgsspkjmcgqxp +six5fourgzrhbvdnzzllh +9seventwothree8sevenfive4two +7eightdprzmjvsevenfourfiveeight +twosjzhsb29lqzkjbtshp5 +8four6two +bklkfctjb84one +sevensevenfive7seven6 +vklhzsjz5fiveeight5 +fourmlthreecjspnchzrthree8tb +7gsfvptnpcl2n82 +58mdllbtjkkzcmdgzbeightbzqmfour +2vtlzkzlsfive92vbpnq +jbcgqvr28ksbphtfourfourfksnxjhtb +21ljfcmgtmdqfive +threejhhstcxfive64sixeightthree +7tqpqngnrmnnxt3pjbcqjmktvj +fmqqc9twoone15four +5six13dnkxtqrxrh +8xxpnpfivethreeh5ktnpctlqrgtl +9hgmlnzsbmbsbjbg9 +8mnlsqkpqp18jkftxzfcklsgkvjr4threergdbrrzbb +eightglhhjsfl819lkzlxjvcshdtjhxvjs8 +gshmsmzfbcrhvnfnpppmmfmngcv2snrponeqgxvtx +9sprkdkk3cpjzlzphfdbhczbpssix +nine8954five +oneonettsixckhgprszjckhx2 +seveneightgnhzhm9pkthree3three +5mjkpk +sevenfour832five +fivellhglxm2twoneq +fqtfqdgeight2lfklmhrnfive +flqdfkmlfthdvzncvbfour7gq +793 +fourninetwojrfp4three5three5 +snnnjlhcnine84eightjthbkgtslhp4skglpzhz +mnxfgpg862ninefive26 +bmdtbfjonegprzlxqlkb4mcscbqnv +nine9fourfourfive1fivethree2 +eightfqrqz8 +fourpkd1bpxczlzthreecptvjlgzfmtqnr +25onejrksrlccgrqtkcsmzccnine +5nine26three88 +25four299fourfour +hlrbll8vnhjlfjrkd +ffourthreefourkgjbsnbc6 +eight8mpqpsgxthreegmxrhqkqbhgstcz +three82five1 +4dxvzg29fourdsh +ffgdlggchpcq7four34lfive +seveneight9eightnpjmh9eightfive +bnjrnsdfjg6 +76five +five4nine6six +q339eightkhnjsixttvqzlbchleight +koneightonenine2nftlzxnkbctmjvzk98 +511 +4cghqsix3bqr +958three +seven2vmrkjqgrlb5 +9three6one5jdrnlfour6nine +four2xdrqqsktone +1sevendxkhzglzxgcmonesixrplhlplhnone +6threefourhshvnszlqrzb +7hctfsqf2jzjkxbljg +sevencxncnc68 +49lfdkv2zbhddmbfive +sevenfdsmsmmgzv29two6rpxsgpdsjxljcthree +hgfqhdfb4mninesevenzngfljcvpvvkmghqxoneseven +gtlqcggrp6lzjfive3rtrqvszcrsevennine +qvhztzsfddxbbxsr88 +nine5kfnninelknrbf5bjrrthv +pfnmdzksjcjcbvlvgcbheight47 +sixfour8 +cdbxkcqseven1 +onefive65mdbrnlg +vlcxxcxhfkjhm6two5 +bfpnhlzq3tgcmhd4 +6three69eightgmxsseven +three1six +fourgqqgvltwofkxzmcfdmz4 +24four68nxs84spjnpfsdv +m1threesvlhmgsbn +three7jcvclg84sixfjvvtkfk7 +hznlsixjqnlvpmninejrvfpplbm5 +mgfrn6 +xb9469 +48713fivefour6 +sevenfiverzlhdzr59lbtvltccgbstzxksb +rxkppsh771 +dldhcgdvtwosix3 +one4phkrftwo +rrdrpfddtphv88jldqht +vgcpcmrj6 +9zdqnzlthreelxzmlhsgdc1pddz +669onesix +5eighthlbhzlpms7qvbftcrone +8mttfjqjnsf528hzvljcx +eight9tseven25csfeight1 +7threethreetcdxnhnnftwosevennine +54tsrjthq831sixcmxzqg +61eight9kb5 +qlxmg4zhcpfxvrhlgjlcbxvxsix +95two +four75eight +6fbrnsflmxstwo +25 +eightcdl979gxzv97eightwogdv +eightgbx85sevenseven +3rfvzeightsjcctzxvtcrsix +fivevqgm14 +dbfkfnfbckncvseven83drnkzt1 +11ninesevenxlxfr +4ptvstqt7fivebznine +5qmcnfour9 +four5mndpqsmxninethree56ctnlcpbtzmthree +four2bqnbcbninemccbzhrfourbgrccrsznskjn +rjdfqd24seveneightwom +9ztmbftvvzlqlr4 +qprftkd3vkfhtwofour33five +fourdtmjbtvvdxdhj5 +jpttch9 +9jkngffbxhg +one79twoonesix +2eight528nine2 +psncczvbeight3 +4seven7nlgrlzsqjsdb51 +five98lqc8 +nine377rcgvvhdghrg5scmff1 +8fvcxpr6kx5cpcrjdpnjcsj +ltlbphmcc7six2 +4threek +8hzmfhrnvt +tbmzgpgkkxc89z4sqpd +fivefourdjpdgfournine37eightzqbpgcnfrq +sqh6llxn9z +five1sixrqqclkhx334sixone +289 +nqcspsixone822five +bq19 +mxdqptgg99982vpthreesgdgsf +vp334fourhdtjvlgtwo9seven +3five157sixgzgxxfive2 +dvmtwone3sixfivetwo6ninezpjv +9trtrdkldqj429hsrtd8 +6three3sxsbbhpgsix1 +3gccsixcghh +six4nnbg +ppvljnh5 +sevenmghppptnrtrzh7 +4sevenszkgbpldhklrtclm +9qjsxmrmdm +twoskbhlqhnkmgzkpvtft9five2qrkeight +1v +988fkxgkbonerglfsknxr5eight6 +xkdklvjbhv977lvlnmrj3gnfjrnttm +1fourthreesevensevenxfdmtdone +fourmg4xtvjbfmqkhtbslq1onehmtrtvsslrjdfncr +twosgdlxsixfive1 +bscpkcfp8mhpvzn7threefqgcpfpmftsrmktwo +sixeight4vthcxd48two +1ninehclngfzbktvpjone +one2sixmzxdqxvg4oneoneztbmplctc +5tkhrmfrvonetwo +lfgveightnqdmrv9six +zzgmcr1jgzjjljhqmtnbrnbt +one3vfour7eight +fourseven3ninenine5four +92kpdtggsb +onecsfdhsn3gqmtfhc +bhflvgdfkhprqqdgs6one +1five93pmrhdvmgp7onesix +56mgkt +rksixfourfourthreefive3fdrbtgmdt2 +8one7 +rgvccbsrphxkmdgjkrjjztdzzmkgqbcdkseven69 +three4eightsixjgbnthfxvltwosevenxjkd +5cffmxhdbtgtlffdb +8fivetwoneb +5trtgsgkvplfvqccknine +two4gjjmptwo +two845lltssr6 +six8xngnhbctl +nhbxglqfjrhmhneightqmvlnqtwo53 +7nsr +one2seven +8eight2jphsz9 +9fivebv7kmxqtdvxq +ninec4four +vrtczjzbzg8bgf +pvhnfhvsixbppv4oneshhqp8jprm +tnxqmfive1khnmb +onefivechd69nine8 +sxeightwoeightkpjxbkrvtbllbxfshseven4threemkbx7 +twofgcfp7ddjqvhrbvmkjdsltfps9bttz6 +sixninezpsbrvhvlz4 +four6sbtdldjcjrn7 +79drd742 +mmccvnldbhxcfnpxrftqc1sixlncsqs +jjdpbsm2 +9fnhthreefourtftrmqhkmxrpnnhbxvk +five168sixs4 +65fourkpzbhhgsghxvhlvlftfmck62 +8fivesixsvmzjhdmdqsixntzrckdk +gfzjxptdqnineonepqqsldlvjrg5pdgthrslpfcfive +38mmkcseven2four +vghjzfchxsqq8fivefourone1 +tttjzcm3 +jpn764tsmrfvtjp7four +onelhbhkmf7 +5ssfzvfrrvgleight71 +52lkxkxdjch5 +3eighttffhffht4 +832 +2gbhzrgchz +threessdmstrhchfq73ftcfbrtrvf +8xqs9scc +xglmdxq24two28kcckrsqpzone +16mkcl +ldhmz3 +xzvttst5 +drkkc3 +8zhbplhvcr4 +one1xzbrkd59 +xzzbsnktjhjltsfrrrz3four +8vlfgxgzsnfljbnnmlpz5nine3three +99onehzdqm +5zdtrvccn +75sixsixkxldjnxslnvggnvvjbzcrqveight +9sixztkk +three9sevenone +zxsgxfxpkpp45 +9hkshgthreekkvrplztccvb +sixbvdxrhrc16 +1jbjbqhnqgg5shmgfm9seven99fvpnrrpks +sixstsxgbmcx12qhhdr +9trfxqzkdstwo2dzone5three +one3drbrbtsevenonekmfdlffive +nsnchfkxttwo2zgpbvkvktwofour +cnzgzdvfm9 +8fst5jsgmxhbgklninebkkrs577 +xskvpkzcx2twoninebslrbdmqseven +qlbpjqmptkseven9lqmcdvjcxqsix4 +eight7six2 +33h8rxmtlctrz67dz +3rmkrn83seven4bxthree +mmznine55 +1onefour +two4fivenine +fivesevenpp2onexcxjvllseight +onehtfzdtjxskmzsbc4sixfourz +mfkttfxqvtdqdrl93 +567 +qqpnrfninetwo55eight +4qqmlrfbfrvpxvphjpbc +nltblqfourbxxrrgvgkcbb5hzzgfour5dmdxl +three2526ngfzssixsixseven +1tffj2fcddnfxrzx34 +59jd +sevenr8sevenvxltmxcssttwo9 +svklhbtwoxbbmk6ninekptrln7sixjqbjgxdhzr +krbmcxpnxfrn4 +pnkfournjgpggxzjd97two +cplfrzbgbleight2z7six +ninep8xxxnine +xqlrnzlz92ninehblgkztwonerc +1nine7 +one8three361two98 +nine367qqslvgcxftwo +3fournine3twofkcdmx6 +1b2ninethree +6one4sevencnlsqzzmcxkxfnqjone9csmkx +oneeightgh44eight66 +6x527threethreerggpfcfqlf +eight1tnine7gjvtpvmqb1seven6 +six45six7fourmnhbskfthree4 +ltf4 +3hgqgdsmnsnine +hjqneight5threeeight +onekxbrlhkxgxbmbn6eightfourltspzkqdnone +llfphldmghqrcnineeightonefive9vldfskjbhl1 +sixpjf5gjkdqkvvqhj +2five685kvh17four +pgslffcdvsix7oneightcs +lznbhzonefivezgj45crzfl +twosjggnvbxcmtwo8four5 +fourhtstxbkcz6fclrvgfrgbv +nine4ninefourfdkdmjvlvzgsnjsfseven +three318lmzcfive57 +5pmcnc +861 +qbbhpjsg5r2 +jtxcphmrjnscfhqhk6seven2threefive +qd1sixninefour +four7fivethree65 +7dlzrddgrgfour3hxsttlnkbm29 +four4twonine8 +5zblkgmxninesevenbrhntxm +xfvl9589 +five2seventhree6gbzb2 +cvmqqtskxlthree1 +sevenseventwo9xthreevzfdmfqvdf6 +six72sixeightnine9 +xrjnqqtlxz8bbgsqrseven6two9 +29seven153eightzl7 +sevengntsfmzkfb8 +1fiveseveneightdbvbtszptqlnineseventhree +four6rks1v +52eightninez +5jspztgxrpt +bq8jpttmm2 +fourctnlpkbrsfive9qd +85twothreebbpsjcfh12oneeightwov +xhxgfrcljq7six +zh9 +9sixfiveseveneight +rgqzbrldqrhtzjbsbzggktnc4nine8one1 +xcmfbrprxr72qqtnine +tjphvghjfthree1one +twosixeight9fourone +eight48xronebc +t6two34nkmfgmsnnvlbq3 +eighteightkx86 +82b6fcvvxpsx84 +threeeight66two +six4pkbhtxlteighteightsix +three7snrrdfb8sixninetwo4mltj +5jqbgnqthreemjzgbvpdeighteight8tvf +nine6zrbpsfrfqnsixlkmxrkxln +2fivedvkt2998 +j2eightzqspbs +mmp694eighteight +3chzvrsrhzrcrtwoone2 +qqqzxcqmbb8nine +sixsone7onesix1vvrqszvmnrh +8threegtfnmkgthreesixthreeglhzqq +threefiveone2three6seven4 +sixzkqbcg1 +two7seven85five +cfhg3zmpfd644 +btsrthdbkt6242dhl +hqlgnine5two +2zgftzs8twovt +mmpcgngmjjvbnsix35threezxjjxsqnlv +lmmqsevenvjcvcqj55fiveninernmn9 +two7rgsbxnmddtjd +36foursixsevencjffhxrsq +4jxzfhxrphtgbjqfivefive +99pqtnvtwo9crsbvsnrmtpltthree +threedhk3hgvkp8nvbk6 +fivelkxdgvsq6twofive9hzjkdz +ps7two9pqnnnvqpdbcpttjgrjl +jjcfkvqdcl4twothreetwosix +47one525 +23three2 +eight9four7gddxxfxcm9gdmmnfvbxr1 +745 +gkblgnrzsblklpb5bc8ftrnineoneseven +jghbzdlmqbjm5glsqfffvzksc +eightsix1five +nznrzbdsv4 +16vdxm2hlrgtvgtdrbsix +txk26eightnrjxrrlvffour2 +threesevenddmrsghzsjk2bdcqx +eightthree9blrfjvrpfnjcfqrxcnine1 +two7three81htcdvdnxg +seven1three6 +kplnzdjmkcrthreefour38 +bvf1sevenmcdfnv9lpnnh +6eightqcznninesix +two3sevensnpf6v +eightthreeeight4986 +9seven7nine6nineseven6 +3two91 +six97three26hlxczxp +65twopggttdksmtsblfpjbcphzc8eightwopx +mbxtfmkfourrkspbkvbrnljsjhzpqsgtvrr2 +sixseven9one5 +three7twob98 +6c +5797xjtwo83 +chrbcms6vpmrpctssbvqmvreight76 +mthgpstgchone6two +597 +1799gjjdgzhg9eight +vzqkgj27zpvxltzvrfcl47 +381lmxkxrfhbxqeight89tdhpbpqnx +sevennine4 +29ninetwo1tvhpr6three +dlbqfsdmdxhszmcpzshdthree3hvc2csbtfthree +19khmsnhone +twofourbtlsl1 +3sevenssevenfivefour +8seventhreesevenseven +three27rseven +1jbdtfcdvvbzhgfsixrzqxkfktjmhkhfive5 +onetnznrrcthreefmmfivesbsvg4twothreetwoneqq +sbjfxeight2tzbdkvqmmdd2 +vc4xfsjmt +bfive9dmqgfnzvtngkbvthlrfjmsjtclbzbszfour +31nbzfqvckd +26kcdkzbjnpkpljxhgnhjgmtbrvkntjbqtwo +3eightthree +eighteight88 +five6bsix3rkchjzlfour94 +one9rrrbx3eightone +6fourkxpdmt852eight +8xhfbqqklnfive2one +4ninetwoone6 +seven5seven +1vzprkvk +mczkrcdx7rzvgdd6ktcnktpfkpp +sixnine988one +68shx +jqfoneight4sevensevenhmcrqjlzhnl6vcsqgmgnnxqhvchx8 +1fourgqbjvjhzdppdq +lcxjghp2 +sevenone8nlh5 +nine94krdvjv5seven3 +ninenineseven8threentgtlzfnrfbhxxzn8jt +nine37 +hbzztninexrrktrlktwohr1765 +5sixjdvfxdxslhthreethree +2eighteight +dfnbf65 +4onenineqjnlpninekgk +oneoneeight974 +4nqqm83ninezkmbcblh +7tpjhbeight1 +fiveninefdcnfourvdjcnsshnine3fivefive +344 +crnqzpztstxvcgjdmkp6 +hgcvbscglp63tpfive +seven5fivesixcbtblmlsixgvfbqttzonedld +43threep +zshzcplxth4nine2zcgsbzdlxtzbxggnine +cqtwoneone9ckhnzmzfsevenfour8j3 +fiveshs8ttpcsznh +hdpqds3seventwokbzlhxpj +joneight9 +hmxxnxhqfivefiveseventtgxqcxc3 +59sixoneonezjgbshzpfg +1gqqz +8two38fourjm7 +1fiveeight1four69 +88eightwoffg +threenine3threegqvtvtxgninerdprd +7sixthreesixsixmgzlqlbsslseven7 +threegmrbgmsfourfourbvmhzpctkd5rzx98 +five193146mmqmf +41fourxone +2jhgqrkmmgbthreeeighttxg +5xxbgpmm3 +5twonineffsevenfivetwonine +seven98 +one7532rcc +8djrctpqvpcd +eightqqnhfnn2pjsevensixx7nine +jkzjrbhsevenseven1 +4tnkqxkl69nrktzz +six88five9nplcm +xngrktpqclsmkqggj935oneeight +8fourgbns +eight47nine1two147 +vpshrqvfkjctpmhcfc22eightmqdxlsngbfn +rfive1kxfbcpq +twompnqfvqxqninevgvhqlpfqc15seven5eight +9fournine4ntvhbkbhqn48mqhqhltbjpzrrgb +ninesix2four937 +6cxpmgqnchk33mfdxfqdhxbfiveonethree +9mqmldz3kjnsgfoureight +4dmxtdvqvrvdrbfour5q +8eightmcsbfive11four2thqxmbktdl +zddeightwosixlmhrzfksevensevenfive3seven7four +lvgfftzceightsevensevennineseven5twobkd +nine7three +zlmfvjfrxrrdmtxg965msd4 +two9five4sevennmrvdgzrf1bjdzbtrdlb1 +tjbnzrpzrflpfsrprsg9 +fourzcqfonesix279 +75fxlvc +ldvmnfqpll7fourqxzpfctfxp1nhrhpvkbtmone +seven4ninebpbdfjsxxmbqvtwo6one8 +fivefive47seven +rxeightwomgzhcbnlmj72 +eight34xhbcmeightfour3 +nxszsbltqhthree4 +7threefiveninecqzfdjpdcg +kdfour2 +ktworhdsfhhfqcrbzdslthmt2 +dpjbqmd7689 +threesix8 +61113threenine +ninenine77fhtvsmfh23onefour +bccdxg5three +2eight1bnrx +eight7sixdvvrqgt46874 +35onekpnthreeprznkpfvlneightwom +52five6 +one3foursjnngjznqkfqklhjn +eighttwomzrxzfqgtdthree3scbjdnq +9fivecjgdnkxrt +5nine442fb8 +nine6one +241fouronenrlb6 +97sstjznxfcpccngfl7cxmzzcvptfive +gvtsxbqzcone52 +5845836fourfgrvrchv +7247zxfkqhvd +fourxtwonine2eightfive +znjxhfour229three +fiveone8qjfmjbnnc +1sqdjlfiveh +fivegxfj9pfbxf5 +cnxmvmcrm4cfivedcnrnneightwosd +four3oneone +hbtfjlnplcsrxkt6rcqpfdseveneightwoh +jqknine9xfour43sevenbgznxhh +pvtztgjv47 +one9oneeight +3npsq +ninekmzdninejk7 +6threeninefhcpbb +266 +pvtwocthreeeight1 +lpmshscqztgsgsb2zfcddqnvkseven +dmoneighteight78oneeight9zqszseven +eight8eight +fcdlflbtfiverxfx9 +five7six5 +hhvmsspr4four8hhcjdhnthree +three8qfzjpdztwodrkg5cg +919lhzrx1 +foursevenfourfive6lvfour57 +crzmt7 +two71pzxnxtjkngfzm +sixbmzlvcnine9 +hfbeightwo3eightfoursixfive +j5twotwo57nine +rmqq3sbjqnqmdjhmbp91hp +3threezr +fivesixfour81jqxx +2bfeight7nine7 +fourfiveqjfkzsdxmgjmpmtone3hbgcvq +7nrshoneninetwocpphnrfprz2five +twoseven1bqjgdz2 +one7qonevmvb4sixhsbqgp +fivethreethreegmdh1 +lv7d89 +2tbrnmflxfhhsixddn +6sevennlhxsevensixt +pd2kkfvtjbbgvfrcts +djfoursevenflp2three6 +bppkvmxcrvffssdxgrr6mtlthree9six +4szvlsixsevenxttwo +ppggtqx8 +two3three6five +threegplsmsjzjfcctwo6tkrkzmnk +srtj2tsnxthreeonethreep +szhnzblxslqthreejveightfvrrhbcqjqmmvczh1 +five2five25 +btvlzjhrxxdqdmbbcrmbffpmlmr9four +1jdrpjpvkmmseven +85bbbht +2onel2p +hdsfftwotpqcgdbdjbgnvfone3eight +fourdgtccrxdnvfszgkjsj38 +twonine6twotvqxpskhonejsnpmtpctjfive6 +29eightcgskgdnmnhkpp63seventwo +2seventwofhktwo9 +8kx +32zxdzvfzjvtwofive9sevenfive +2seven8pmdnnthreehnvltl7 +33sevenfournvnjp24 +two3m9kcsppfour +hjfb9six5gtbppmzlfmfourtwodqzppcldd2 +4qlkz3 +4ninejzgpnkvq +fbcpkspbcgrn6dmclmnqldeight +sixtwodphp833 +sevenonesix5eightsrzpjzpj45rczn +9fiveltfqjmkzbrm8oneightbq +mxfqsrs5fpeightfive7mvclrlqhhkptpbqq +438rktthreegvhltmsv +dcl9xnntwosixthreesix7 +csxhsvkkkhfour4slkvjk1eight89 +three2eightfiveone +17kqnstzmbthree9seventpld35 +ztxjhftwo1f +ccfvc3three9five +fmngmbkjppkxjnzqbqldmspbrrrhhrkrsix4 +9fivejthreepjtmtfive455 +4ncdvqfiveonefive5zxgjpptbnbsmbrfdpqrjnx +ljctvztrxncpxsdtttwo2tnkkt +five544mlzkztsblt17fivesix +9five35bkbpjc +6fourtwo +nine5hqlbjp1onenvvnvsseven +5qbvsbxtktqhgqxfgprsgsrrpdtpcmr8 +hhsgjxlz3gzxhz14fourtwofq +6three8rmtrbnhvr +9bhxvmhldnm6 +vkjjpkgdmxrzzfour7 +rhvrsrthsevenfour3eight5one73 +msqdzmfzfeight6qhrvzcdxfourrleight84 +pjtfflgfhqnpdk6three63five9six +1sixcpcvbnnine9eightonenlnjfdfdmxcmcb +zpgrbsevenmqskhgtrm6 +8hnqmmgrnsxhrxjjc2qjbbvpknh82 +5six7threepx +bmlxvnqrxtqzkdlnnine5two9bpphfdhqj +mtxrblghxrsbxhmgnbvgvffivenine49ztktxvfvseven +tnqclrllq9fivebddnv +56seven222pkmqk +74eight9pfqghssgk +nhmzdpbnlreightqgljp6 +nf3three2 +eight9glknfltsqsfdsixfour2tcfnzfmf +four1ninetwo4sckcbgzrx663 +eightbcfsevennqznfmfivetwo7qgdjtwo +64three +8vgggxllsrhqjh2 +7jhthmpmlxlptgbnscxcthreeeighttwo3seven +ktqlfveight1eightjnfxvvjk +99qjcxgnpdvnbjqprbqnsjone3ninenmxkslmdsx +9gn2 +qtlztwo7eight2 +nvzhsjsdp4sgrbmx36 +fldvmnlkq52nqtsccgfgtwolm7mmb +tzvgkfx6ssnxfeightwov +rrl8pxjj6onefour +3hzhqbrdspfrn2eight8 +jcrcxtqh8three4 +ttwone449cxvvljcpzpqmngtzslnq +3gnkgbjnsmxv2fourd8 +9zt +kckeightsix8oneeightsix36 +vjcg4p +jkzr3 +twofiveone1four9seven5cnhzm +6one6 +s2twosixfvgrglfive2mtkrxznllj1 +cnhbzthlzllgghkxjgtrph45 +six5two +nine5threefournine +1rkbvrk8threevfkdbvxgj +28six7dvone8 +74seven +6threeseven92rvpg1 +hxvthvgk8vhn6kmljfnl +fourztpprfkonemnjbsfdjlj8 +djnhxfxxl1five2threezgthn7 +vmhmlgljrpsix93sssixsevensix +dqk8nrsrk +jjtdjkfivegpfspqqjthreedkntgjslqreight7n8 +8four12 +8vlcfsixthreelvvdv +zsjqvmghp6seventwo +6tnjfl2cfzcbgqp5 +vgjxleightzqfklqdx4vlpvp2gqxdxpzk4 +12mshtkbgsndrdx7three +htckznt2threeninej4fhmrtthreeeight +four8hdbrmptjnine +2xbk +ljgcscxxjgdbpdpzfcchrqnmqqthree8 +three7six51 +four5five92ftqhjhx +eightfthreebzbhk4tceight +2fivethreefiveeight9fbk +9four613two8cnpzgcrnmc3 +fqfive38 +nine88mkthree99lkvzgvpjk7 +784dxxcpszbzkdlsrgnnqfsixone7twonemvh +onetwo5tzggnsix2 +xsclx3twojhslqrnc32pxfqsjxctnb4 +zrdbcccznzlfgz8jfpgllczxtnpmp58one +four21one925rntdr +38six +seven3nfttdgkjhklmdqbkv8threefour +75kblsbqhonevsx +fourztseven8twothtwo +gmktvrd44twonine4pnbrkhhzpl8five +nineslj1six8two +one98mxnkrbv +9zmfour +8dkfmthstlqvs9r +cjmcjjjvmceight9rslcctdslsxthreexsjbffnine +5eight677 +4twothree +cvqbrkmgthree4tbmzrhqtpx +24twoone +nphprsbcfhcfrggktgzgvrninesixdnchjd2 +9sevennmxzpjbhct +sbchgzqgdk8twosix667 +hkjlpqgtmglv3eighttwo7two +gflktjvlfivetbgmbsxzdpdxjdgkzvn851sixfour +five2ffivefiveonekldfpcfjg +mlnvqltfsixnxqxsgfpxrpsxmmlnzsnineeight5 +six1z +sevenpvhgctkcvgtjstwoeightzgqlcgq1gxzj +fivenine13rbbxfs1zpvrstlkceight +6zmcggdqbfptwofourfphdbdg99four +one65ninetljqcfive8 +six57fourthree4fzctnjzcdm +181one +3one315gftsbtnggrq +gcdvnzbvv55onemgcftkmzrxf +697cnzql8eightvdsngsglkfour +fourfiveqjptdn6 +pq83six7fprdbzvmgrhkzmjmxgnkcr +nineeightfivesix8 +fiveseven931xhtnvrtr9three +seven9ninetkhldts +6threehlzfbppqmhrtxnfoursix2cxn9 +mphgdnggjt3flmdz14ninejjskfivenine +boneight7one19179 +npdjlhskrdmvsvhtldsthree5tpt +6rvpnvdqqpkkfvgclctqcmpdfvftt68 +91four3twoones +seven793 +8h2four6cdsevencsjvcgdlrj +4bzxqvp74mmdvjfdvq4fivec +31tlvlrb75 +nndfct5ninesix +ncqsnf6six +fiveonefour8 +sixtwo6zjhvhkoneeighttbfv +three5dcpmcsnmfhtwo5 +eightnqqkpnine4ninegb +lgnsrbbtkgtwo7eightthree +rlpcrnscknpjpqm2qqpllrzk8p9 +tvpqncpmffpmv9nineninesixnjbhbhgdlf2 +lzrhjdkfhn1 +jgjfckbrpvc3fouronefourfive3eight +twozhkpzcdkjfour8eight +5sevenfourtwo4 +1sevenfivehvppxvxvcnsnhdrflonefour +4pshnstwo46fivetwoone +three1onemdlc8pcqkzsrnhqone +qvgfvfxnrp5bqdrlqd +jzgcnslrfxxc72bqqqrzltqm18four +nmjlnxktmvzzrgkbrffourdddbbt7eight +3two9twothreerlztqftcgkznfour +8fivefive5tkv +4vtsnlclbb37eight2xprhpnddzj9 +8hbmfjxmqckxqrdjqxrnhg +onef6 +8fivezcjtworgbxrfkjkbk5mdkdgfbnkkkljlv +5six6prgqhbvcrr1msjcct +mvzdrmdlrsdz9nqmbkb6286 +367 +94vjktbt +twofivefour7three454 +2n +six224 +z841dzxcthdx +fourvnlj7twocchdcn976four +threexmxq5five +dscbqrjqmssnzbbdtx34 +8sevenhrvzqskpczsfhzrhrfch +4qx +6eightnine +cnbxjrbsseven8hbdfmjvk6sevendrglnfq3six +82threengstmq +19f +cvjrhrnxnfiveksrjgh8 +2six1dlpdds +5xzhhnqpnsix8qthckdhggfdfour7 +9threetwoqznvtb4 +one8dseven +3fivefourjzbk4seven8tvqgvh +9kffjzvfxtwofive3seventhree5 +5onerxdcrrlgvfbrvrphnine5eight +614pnrbdp +eightfour1cvxjbztxgzznlpr8qbzkz35 +four5seventwo3 +9fourzzjfdqdkmxbeight41eightwopr +eight6rfdhz793twonevkf +vmrkgjgthreethree8ninesevend6hmjmkfdqz +vqstkklpj4j8 +72jglrpp57nine7vcr +sevenfbbgpxlvk7tmlvtjsixdtrnseven3d +5jlb4 +jhkslf976fpseven +jpfive1 +two2jpfztkeightssfsevennine56 +seven6rjchpgvmqgrxdddq +four7eight +zqoneight9mqmjtjcb +ljcmvjf1ngrgzmttttqprks2kphjtgqvmeightvfmzqhdhgj +77ninejjxxgbffive6zzgd +4pthree5zp3one +mhdzcmmsseven4three3bngxxqzclpkmcppxtwo +bneightwo33ptmpcbfournine4five +sevenfrzffbklg4dmdngxmsixnzjgpkngsfivetwo6 +six2onethreethree +xhx4gvkbtcjbqvrhtwo6 +1mdfvninevchtrqthree +onecrnninedjchhzkmzthree4qjnclshjlbn +threeccgbz6sixlhnkcpfdzk119 +61dtwo +ncsbdxnp43jlrxfhgzlrfzqjkzbkd +nxfztwo9lhcc +mds9vkninehzcdk +twofive4jdcndg +374 +threedrsh9eightcqkrslljl5tthree +fourtwotwo8kl1bvplqfrc7 +threekldmmjkmc92sixsixonenine6 +bllccpcksq59zznr +n35lxtnq3 +25hmzzxv +38sevenkqgtfcpnj +ntfceightmvhvnzjvv37bsj +4sixfvrtgdsjvxsevenfouronefiveddns2 +eight29lnznht2oneonekgjkq +4lthkrtj1onesevenninerfplsixfhxdvlhoneighth +1seven8eightgxzvgmnqj +7qfqvxcjttwoeighteightqqsgbsftseight +slfqkljnine1oneeightlgskmlqgstwo +sppqhlxqzkdtdqc6qtxsssdcf41 +tnggpjrnmrrgzpssptpk32 +6pcjglgdknjoneightssb +ninefivefrglbccjmrchvbpsgxrq15fourfive +7five1lmndzphnj4fouronesj +jvhkb24htseven7 +7sevensjnrvxmsixthreesevengrh +9h5xbdgpdjjkt1 +c14vbjvcv +ninetwohfbm6fourjpgz676 +gqdtlzqvkplj48cxvtvjjlkmbstcfxd5hkbfdgtf +ninelpxd8eightvmmbvgmhs3six1 +9mmlj4vvcxlnbsfoureight +nzrjlxqhnffour1 +hl5fzsxdbvklx4five +182ninedghflcgrqz4ns +eightdmbqddsqmfive7qshcvdjx +vdfzsevenoneone4ninemhclrkjspkxt +2three1qzqhscbvmpnine86three +1ninevvlzft +1ghfnrvkn97sixqzgtm32 +sixnine4rsjghcsznfvs +ph5mzknlknp5 +3eight3twotchnsqdtbkh +63threerjlgv6three +fivevvcmvrqfkdfshxjnfgsevensix3seven8 +21onebcsgvhtm6two +bnjpqcqdzmeight2gtjhqeight +1rsjbbhtkbbfourqzdhlone4eighttwo +6jpnnlbstgjfjdrdgnthreepgh49hdxqghr +five3oneonefrvnbnnlz +gbseven9five6 +nine2hdltdjdp73phzrjnonegx +3two3eightjszbfourkxbh5twonepr +5cfprzgxtf3465five diff --git a/src/days/test_inputs/test02.txt b/src/days/test_inputs/test02.txt new file mode 100644 index 0000000..1cd7d33 --- /dev/null +++ b/src/days/test_inputs/test02.txt @@ -0,0 +1,5 @@ +Game 1: 3 blue, 4 red; 1 red, 2 green, 6 blue; 2 green +Game 2: 1 blue, 2 green; 3 green, 4 blue, 1 red; 1 green, 1 blue +Game 3: 8 green, 6 blue, 20 red; 5 blue, 4 red, 13 green; 5 green, 1 red +Game 4: 1 green, 3 red, 6 blue; 3 green, 6 red; 3 green, 15 blue, 14 red +Game 5: 6 red, 1 blue, 3 green; 2 blue, 1 red, 2 green \ No newline at end of file diff --git a/src/days/test_inputs/test03.txt b/src/days/test_inputs/test03.txt new file mode 100644 index 0000000..624ea4f --- /dev/null +++ b/src/days/test_inputs/test03.txt @@ -0,0 +1,10 @@ +467..114.. +...*...... +..35..633. +......#... +617*...... +.....+.58. +..592..... +......755. +...$.*.... +.664.598.. \ No newline at end of file diff --git a/src/days/test_inputs/test04.txt b/src/days/test_inputs/test04.txt new file mode 100644 index 0000000..71f208a --- /dev/null +++ b/src/days/test_inputs/test04.txt @@ -0,0 +1,6 @@ +Card 1: 41 48 83 86 17 | 83 86 6 31 17 9 48 53 +Card 2: 13 32 20 16 61 | 61 30 68 82 17 32 24 19 +Card 3: 1 21 53 59 44 | 69 82 63 72 16 21 14 1 +Card 4: 41 92 73 84 69 | 59 84 76 51 58 5 54 83 +Card 5: 87 83 26 28 32 | 88 30 70 12 93 22 82 36 +Card 6: 31 18 13 56 72 | 74 77 10 23 35 67 36 11 \ No newline at end of file diff --git a/src/days/test_inputs/test05.txt b/src/days/test_inputs/test05.txt new file mode 100644 index 0000000..f756727 --- /dev/null +++ b/src/days/test_inputs/test05.txt @@ -0,0 +1,33 @@ +seeds: 79 14 55 13 + +seed-to-soil map: +50 98 2 +52 50 48 + +soil-to-fertilizer map: +0 15 37 +37 52 2 +39 0 15 + +fertilizer-to-water map: +49 53 8 +0 11 42 +42 0 7 +57 7 4 + +water-to-light map: +88 18 7 +18 25 70 + +light-to-temperature map: +45 77 23 +81 45 19 +68 64 13 + +temperature-to-humidity map: +0 69 1 +1 0 69 + +humidity-to-location map: +60 56 37 +56 93 4 diff --git a/src/days/test_inputs/test06.txt b/src/days/test_inputs/test06.txt new file mode 100644 index 0000000..28f5ae9 --- /dev/null +++ b/src/days/test_inputs/test06.txt @@ -0,0 +1,2 @@ +Time: 7 15 30 +Distance: 9 40 200 diff --git a/src/days/test_inputs/test07.txt b/src/days/test_inputs/test07.txt new file mode 100644 index 0000000..e3500c3 --- /dev/null +++ b/src/days/test_inputs/test07.txt @@ -0,0 +1,5 @@ +32T3K 765 +T55J5 684 +KK677 28 +KTJJT 220 +QQQJA 483 diff --git a/src/days/test_inputs/test08.txt b/src/days/test_inputs/test08.txt new file mode 100644 index 0000000..bc44497 --- /dev/null +++ b/src/days/test_inputs/test08.txt @@ -0,0 +1,752 @@ +LLRRLRRRLLRLRRLLLLRLRRLRRRLRLRRRLLRRLRRRLLRRLRRLRRLLRRRLRRLRRLRRRLRRLRLRLRRLRRLRRRLLRRLLLRRLRRRLRRRLRRRLRRLRRRLRLLRLRRRLRLRRLLRLRRRLRRRLRLRRRLRRRLRLRLRRLRRLRLRRLLRRRLRRRLRRRLLRRRLRLRLRLRLLRRRLRRRLRRLRRRLLRLRRLRRLRRRLRRRLRRLRLRLRRRLRRLRRLRRRLLRRLRLRLRRRLRLRLRRLRRLLRRLRRRLLRLLRLRLRRRR + +FGF = (HTC, DTX) +PTP = (MCL, BDN) +LHL = (LJF, BDX) +XMM = (KCX, JHL) +GLD = (RNN, MXG) +HSR = (JPX, CXF) +CRF = (BMJ, FHT) +QSS = (KPH, FVD) +RHV = (LRD, XDS) +KTT = (XPS, VCX) +LQK = (TLF, VJX) +MMK = (VJV, HQV) +RKX = (RKG, XJB) +HDM = (NFK, JNB) +PFJ = (QDJ, NDH) +JKB = (MDK, MRJ) +BSP = (QBQ, JPM) +FQH = (HJD, VHF) +QQL = (VDB, KGM) +TRB = (KTC, RGN) +VXC = (NDK, MVK) +BCS = (PSX, PLK) +FHK = (MLK, RDP) +TVB = (JXV, SSR) +GXD = (KSF, BRK) +MNJ = (MHG, CRF) +RLC = (TGD, CHV) +LBQ = (NQK, MHP) +JLH = (FGB, KNM) +PCN = (CQF, NDF) +FVP = (NKS, RCB) +GHL = (TTB, KLQ) +MTB = (VDM, FKT) +LLB = (VXL, TRT) +RSS = (GDP, TKD) +SFH = (FCM, GKF) +KSF = (VQB, JXJ) +LJH = (PNS, DGC) +TJC = (KQM, BVL) +PRL = (TCG, GCQ) +NBG = (GNR, SRM) +CST = (FXL, BDF) +XXH = (KVH, KSM) +FJP = (PKX, DSF) +DTS = (FFF, DQM) +CMG = (VBJ, DBF) +NHD = (TCJ, DHF) +KKF = (RVP, FVR) +LDS = (VPJ, MPN) +GHC = (DBK, SCS) +KVK = (NFV, MXJ) +NTN = (TDC, VNC) +FCR = (DCR, FQH) +PLK = (GHT, PBT) +VJF = (VJN, PVB) +TKR = (GHS, TTP) +PQJ = (VGB, SGP) +TGM = (JQM, PPK) +LFQ = (QGB, QXB) +RDP = (HSF, MQV) +SGP = (HVK, XMV) +FTB = (RFV, MLT) +LCX = (RSB, RSB) +VGD = (XJB, RKG) +PFD = (RGK, JGB) +DBK = (RMP, RSH) +TTC = (NDH, QDJ) +PVF = (QRG, QCV) +BGV = (TDS, DRK) +VHF = (XTB, TGM) +DBF = (GGT, BRQ) +TFG = (SVV, FCV) +MDK = (THF, PLQ) +NDF = (BSP, STC) +SMZ = (KHB, TST) +SLC = (BKM, BCS) +NSV = (VVM, VQG) +GCA = (XQT, RCD) +FVD = (NXJ, MBJ) +HCH = (MRF, RQJ) +PLN = (BNK, CLF) +TTP = (BCP, SLC) +BRF = (SHR, CTK) +KCX = (PDR, HHQ) +GMG = (NFV, MXJ) +SNN = (XDS, LRD) +SBB = (JXL, BFK) +NCV = (KVH, KSM) +DQQ = (FFF, DQM) +THT = (MFP, VSD) +GVH = (KHF, TKB) +HPC = (MKX, SVS) +KSS = (QQQ, HSR) +NCP = (FCV, SVV) +FGB = (LGN, LKJ) +TST = (DFV, GND) +PJR = (VMQ, HPB) +BHB = (VMQ, HPB) +LMG = (SHS, XJC) +GGT = (TQQ, XQK) +PKR = (QQR, JGG) +FLR = (LJP, VQT) +NFK = (HKG, BPJ) +MGG = (SST, MCT) +BVD = (SNV, TTH) +GHX = (GMK, JXG) +PDR = (HCD, HNG) +XJN = (NHR, CBN) +XRG = (LBQ, MTV) +VFM = (MMS, VXT) +PPP = (LHR, HJH) +FJG = (NLS, CCF) +NDK = (RHD, BVD) +VSB = (LKB, CCX) +NJG = (PTK, MCD) +MLS = (XCQ, FCR) +QSM = (CBJ, GRG) +PTC = (NJG, FLT) +MRJ = (PLQ, THF) +HJD = (XTB, TGM) +XCQ = (DCR, FQH) +HPN = (CQD, CTP) +BDJ = (JND, JRB) +PXL = (VXT, MMS) +NFV = (SFX, BDQ) +SNQ = (PQJ, TNG) +LSL = (KFN, JFL) +SMK = (FQS, FJJ) +QDV = (BDX, LJF) +GMK = (TSJ, SVF) +GDP = (MML, MML) +GRG = (PVF, CKG) +CXF = (MNJ, TBZ) +LKM = (HJH, LHR) +GHS = (BCP, SLC) +XBH = (BDS, NDQ) +NLL = (NJT, QCJ) +MXJ = (BDQ, SFX) +FCF = (QQQ, QQQ) +SXG = (LFQ, TTZ) +PLP = (MJL, FPL) +FSV = (SBB, JFC) +NLH = (TDS, DRK) +QDM = (GHX, GGM) +JJB = (MSQ, MMK) +TRS = (BXN, RLM) +DMP = (RTP, CHG) +XGG = (PCC, XKH) +MCT = (NLK, DTM) +DLC = (JTQ, BLF) +VBJ = (GGT, BRQ) +XQD = (NTN, XRC) +FKM = (QKK, JBQ) +PNN = (RGN, KTC) +LCM = (DTG, GHC) +LKJ = (LFV, RNG) +HRR = (JND, JRB) +BDN = (SNQ, NVC) +RSH = (PJS, LHG) +CTP = (DJM, NHF) +XMV = (CFJ, MDV) +HXM = (PTP, XVQ) +CKG = (QCV, QRG) +GKK = (CRG, MPJ) +LNS = (VSB, GNQ) +RVP = (JJB, LCN) +DVH = (QLD, QGV) +CPH = (PMN, QSC) +BXQ = (CPH, DSQ) +SDM = (DSB, CNV) +RNN = (SHM, LSL) +VQC = (GKH, DMP) +KXV = (GKN, PTC) +TNK = (NMK, PKR) +TSL = (MTV, LBQ) +VSD = (LGH, HNM) +QRQ = (QXH, GRQ) +NKS = (NSL, HPN) +TQC = (JQK, TXF) +THF = (TVM, KKF) +VSL = (PLN, GDS) +SSN = (FTB, NXF) +NHF = (BFG, XTZ) +HSP = (QRQ, DFC) +JQM = (BNP, PMD) +GDV = (RVK, MQF) +MTK = (TGD, CHV) +FFX = (DSN, XXJ) +HKG = (THT, KNJ) +RCN = (DCB, XFN) +HCD = (TDF, BQM) +TKJ = (JPV, GRR) +RVK = (HXX, PRL) +HDN = (TRT, VXL) +KHQ = (DQQ, DTS) +MPJ = (PLP, KBG) +SFX = (KTT, NTG) +NMJ = (BGV, NLH) +LXK = (CRB, GXD) +KBG = (FPL, MJL) +GNQ = (LKB, CCX) +MRV = (RVK, MQF) +PKH = (NPN, MHQ) +NLK = (LTJ, RXP) +LBH = (VTP, SGG) +NTG = (VCX, XPS) +CCD = (GVF, SSJ) +BBB = (SSR, JXV) +NSL = (CQD, CQD) +BNK = (SGS, JQD) +TTB = (KVK, GMG) +FDR = (RBS, TXD) +PJG = (RTV, JQS) +LGV = (LSB, NPF) +XVQ = (MCL, BDN) +BMJ = (KRT, XXN) +XCM = (LXK, VKJ) +CCF = (SDR, PTQ) +GSS = (PJR, BHB) +CJL = (QKK, JBQ) +FBT = (VJF, SGL) +DSB = (QKQ, RBK) +SGS = (MLQ, PXT) +PKX = (KPF, CNQ) +JND = (SDG, SND) +DJM = (BFG, BFG) +LHK = (SBB, JFC) +QLD = (SGX, KDP) +NPF = (VDC, KHQ) +BRQ = (XQK, TQQ) +NGQ = (JNB, NFK) +NFH = (MPN, VPJ) +KHF = (LKG, GLD) +XKC = (XTX, XTX) +DJG = (XGL, BTF) +LGN = (RNG, LFV) +HQV = (CJL, FKM) +JPV = (SVD, XJN) +TSJ = (NMD, MGG) +QRG = (HBD, CST) +FXL = (PFX, HVV) +TNG = (VGB, SGP) +HXX = (GCQ, TCG) +RTP = (CDD, QJR) +RXN = (LFQ, LFQ) +MVK = (BVD, RHD) +PLR = (FVP, DHP) +GRR = (XJN, SVD) +DHJ = (VRN, DTR) +HSF = (TSS, JSQ) +TXN = (FGF, NMV) +CBJ = (CKG, PVF) +GHT = (RCN, NTR) +SMH = (FJG, LQD) +CVN = (PLR, DDF) +SJK = (TTF, SLQ) +LMN = (XHT, CFF) +KLQ = (GMG, KVK) +KXC = (CHP, NLL) +KNM = (LKJ, LGN) +QHK = (LNV, GKK) +BTH = (KVR, FNQ) +QFV = (PRK, LTV) +DBH = (HND, HFC) +CRG = (KBG, PLP) +TCG = (DVF, BXQ) +SJQ = (KPR, QKP) +JMJ = (TTB, KLQ) +RFV = (XBH, CGX) +AAA = (QDM, GMV) +JTQ = (HRR, BDJ) +MHQ = (HPQ, KXC) +SDG = (HGR, RJN) +PNS = (FMC, JKB) +KHB = (DFV, GND) +NXJ = (MLS, HLT) +HND = (LVF, BBJ) +FCZ = (RCD, XQT) +NFP = (FVD, KPH) +NTH = (FVH, DJG) +GMV = (GHX, GGM) +FKT = (CLC, BTH) +LTV = (BKP, HVT) +VLF = (DLX, FMB) +NNP = (NFH, LDS) +GQV = (RTR, NMJ) +MCD = (PFK, HPC) +XML = (RNR, GJF) +TXD = (LGT, QSM) +DKG = (RTV, JQS) +MQF = (PRL, HXX) +XJB = (HKV, FLR) +SHS = (VVH, CHN) +PMD = (NSV, BMQ) +TLJ = (DMP, GKH) +CMA = (TST, KHB) +CRB = (KSF, BRK) +XQT = (TXN, LNN) +QHF = (XKH, PCC) +FQM = (PKR, NMK) +DHP = (NKS, RCB) +KSM = (DKP, SDM) +LKB = (RQV, BRF) +BVL = (TRB, PNN) +GJF = (NTH, JRX) +HTC = (HRL, HXM) +JGB = (QVX, GMR) +VJV = (CJL, FKM) +RGK = (QVX, GMR) +KPF = (JCK, XDV) +LNV = (CRG, MPJ) +QNP = (LXK, VKJ) +MFT = (NJK, VVL) +PBT = (RCN, NTR) +CKV = (XHT, CFF) +RCD = (TXN, LNN) +MBJ = (HLT, MLS) +QDC = (NMJ, RTR) +SVV = (FJC, MJR) +STN = (LQC, HFR) +QXB = (RPJ, MHL) +VJN = (TVB, BBB) +GKH = (RTP, CHG) +XGL = (PMX, FFX) +KNH = (FGB, KNM) +TVN = (QKP, KPR) +JFC = (BFK, JXL) +LHG = (TFG, NCP) +HFT = (HND, HFC) +DKP = (DSB, CNV) +LGH = (DCG, QPN) +LGC = (VVL, NJK) +HSC = (NTJ, QQL) +CFF = (JMJ, GHL) +PFH = (SGL, VJF) +LGT = (GRG, CBJ) +JSQ = (SFH, RVQ) +VDM = (CLC, BTH) +NTR = (DCB, XFN) +KVH = (DKP, SDM) +BVQ = (LSH, SDX) +NRC = (QCH, TRS) +DCB = (KBT, TSR) +DGC = (FMC, JKB) +VMQ = (LJR, LJR) +MXG = (LSL, SHM) +CPM = (TRS, QCH) +DLX = (LQN, TJC) +GDS = (BNK, CLF) +JRK = (PGJ, NHD) +JXV = (DRH, CVN) +SVD = (CBN, NHR) +LCN = (MSQ, MMK) +MJL = (RQL, RGF) +JLT = (QRQ, DFC) +BGP = (DPV, VXC) +PSQ = (PJR, BHB) +NTJ = (KGM, VDB) +SGX = (VFM, PXL) +QBQ = (MCM, VNV) +CHV = (QJN, CMG) +DRK = (BKT, LBH) +SVS = (NPV, HCH) +BCP = (BKM, BCS) +BXN = (PSQ, GSS) +GQJ = (SMH, XHX) +NPV = (RQJ, MRF) +NMV = (HTC, DTX) +LKR = (SPG, SJK) +HLT = (XCQ, FCR) +SKX = (HSC, CFR) +SDR = (BLQ, FKV) +FCN = (FKT, VDM) +VPB = (CJR, FHK) +MHL = (PFJ, TTC) +XQK = (BBK, PBQ) +MDV = (SCJ, BKF) +VDC = (DQQ, DTS) +RTV = (LDP, PCN) +GRQ = (FDR, DHG) +NDH = (JGX, SSN) +NCG = (GNR, SRM) +LQN = (BVL, KQM) +NHR = (FQM, TNK) +LJR = (GDP, GDP) +JXL = (VKV, MJQ) +QCH = (BXN, RLM) +QGB = (MHL, RPJ) +DDN = (GLT, DHJ) +SHR = (BGP, FCX) +DPV = (MVK, NDK) +XHT = (GHL, JMJ) +QKK = (LCX, LCX) +TRT = (QFV, NHT) +PBQ = (DPX, LNS) +JHL = (HHQ, PDR) +DCG = (JLX, VSL) +SST = (NLK, DTM) +QPN = (JLX, VSL) +GXS = (FJP, DCM) +VJX = (DKB, FCZ) +XXJ = (HDN, LLB) +JPM = (VNV, MCM) +QGV = (SGX, KDP) +QNA = (QGB, QXB) +CQD = (DJM, DJM) +TTF = (TVN, SJQ) +CHP = (QCJ, NJT) +BBJ = (LVT, TKJ) +VKJ = (CRB, GXD) +LJF = (FFL, KXV) +TKD = (MML, ZZZ) +QKP = (CKV, LMN) +CQF = (STC, BSP) +PHM = (FHK, CJR) +BTF = (PMX, FFX) +JRX = (FVH, DJG) +PMN = (NBG, NCG) +LKG = (RNN, MXG) +NXB = (JLH, KNH) +MLQ = (FBT, PFH) +JML = (XKC, GLX) +NHT = (PRK, LTV) +BLQ = (SKX, HGL) +BDX = (FFL, KXV) +DVN = (SCR, JML) +FPL = (RQL, RGF) +MMS = (SVR, KSV) +FLT = (PTK, MCD) +PTQ = (BLQ, FKV) +DHG = (RBS, TXD) +QSC = (NCG, NBG) +LFV = (NXP, GMF) +XDS = (KQP, STN) +PVB = (BBB, TVB) +JGX = (NXF, FTB) +CNB = (PRR, JRK) +TQQ = (PBQ, BBK) +GMF = (MKH, CRH) +SDP = (KCQ, PKV) +MHP = (HMR, LCM) +RRS = (QGV, QLD) +PKV = (XKG, HTH) +JLX = (GDS, PLN) +RJN = (VGD, RKX) +NMK = (QQR, JGG) +PFK = (SVS, MKX) +NXF = (MLT, RFV) +VVM = (HDM, NGQ) +VSJ = (QDG, VKM) +RBS = (QSM, LGT) +KFN = (RRS, DVH) +XXN = (XMM, SKM) +TXF = (LKM, PPP) +DFV = (VLF, GPC) +RMP = (PJS, LHG) +LVP = (QDG, VKM) +DFC = (QXH, GRQ) +GPC = (DLX, FMB) +LJP = (CCD, FSM) +MPN = (PFD, RSN) +SGG = (RHV, SNN) +BDF = (HVV, PFX) +QQR = (GVH, QSB) +RPJ = (TTC, PFJ) +NDQ = (NXV, XQD) +RGF = (BVQ, GMB) +TXM = (DCM, FJP) +VRN = (XFV, MFG) +FCX = (VXC, DPV) +RQJ = (HFT, DBH) +MLT = (CGX, XBH) +TSR = (QSS, NFP) +BCD = (VQC, TLJ) +JQK = (PPP, LKM) +DSF = (CNQ, KPF) +CVS = (LDS, NFH) +VTP = (SNN, RHV) +FTA = (MHG, CRF) +RNR = (NTH, JRX) +DRH = (PLR, DDF) +KSV = (SMK, NHC) +VKM = (HFV, LMG) +DTR = (XFV, MFG) +MML = (QDM, GMV) +HPQ = (CHP, NLL) +GKF = (QHK, TDM) +TDF = (DHX, LPT) +PXT = (FBT, PFH) +BRK = (VQB, JXJ) +VXT = (KSV, SVR) +HNM = (QPN, DCG) +HHQ = (HNG, HCD) +MPG = (JJS, SMZ) +CGS = (QDC, GQV) +GMR = (GQJ, RMH) +BKF = (CNB, NKP) +VDB = (VPB, PHM) +DSQ = (PMN, QSC) +DTX = (HRL, HXM) +QXH = (FDR, DHG) +LPT = (QDV, LHL) +DKB = (XQT, RCD) +QJN = (VBJ, DBF) +FVR = (JJB, LCN) +MFG = (CPM, NRC) +FMC = (MDK, MRJ) +JLL = (RXN, SXG) +NQK = (LCM, HMR) +KBT = (QSS, NFP) +DHX = (QDV, LHL) +SKM = (JHL, KCX) +FSM = (SSJ, GVF) +NVC = (TNG, PQJ) +SRM = (HSP, JLT) +FCM = (TDM, QHK) +NPN = (HPQ, KXC) +JGG = (QSB, GVH) +DCM = (DSF, PKX) +BLF = (BDJ, HRR) +JXJ = (JCC, LGV) +PSX = (PBT, GHT) +CRH = (NXX, BCD) +SCS = (RSH, RMP) +LTJ = (FSV, LHK) +PSV = (PKV, KCQ) +TVM = (FVR, RVP) +LSH = (DDN, HNX) +XTX = (RXN, RXN) +RKG = (FLR, HKV) +JNB = (BPJ, HKG) +GKN = (NJG, FLT) +RLM = (PSQ, GSS) +CNQ = (XDV, JCK) +HFR = (TQC, KLB) +RQV = (SHR, CTK) +DSN = (HDN, LLB) +FFF = (KSR, KSR) +FJJ = (FCF, KSS) +KPH = (NXJ, MBJ) +KCQ = (XKG, HTH) +PPK = (BNP, PMD) +TKB = (LKG, GLD) +JQD = (MLQ, PXT) +BPJ = (THT, KNJ) +RBK = (FCN, MTB) +PDK = (GHS, TTP) +SDX = (DDN, HNX) +BQM = (DHX, LPT) +KNJ = (MFP, VSD) +CLC = (FNQ, KVR) +XPS = (NXB, SXK) +CLF = (JQD, SGS) +DQM = (KSR, LQK) +XKG = (MRV, GDV) +RHD = (TTH, SNV) +RTR = (BGV, NLH) +QSB = (TKB, KHF) +BKP = (PJG, DKG) +RMH = (XHX, SMH) +PGR = (PNS, DGC) +GND = (VLF, GPC) +PCC = (QNP, XCM) +KDP = (PXL, VFM) +SPG = (TTF, SLQ) +SXK = (KNH, JLH) +PFX = (MFT, LGC) +BKM = (PLK, PSX) +TGD = (CMG, QJN) +NXV = (NTN, XRC) +MFP = (HNM, LGH) +MQQ = (RSB, MPG) +TBZ = (CRF, MHG) +XDV = (TKR, PDK) +DVF = (CPH, DSQ) +SNV = (GXS, TXM) +DCR = (HJD, VHF) +QDG = (LMG, HFV) +MHG = (FHT, BMJ) +NKP = (PRR, JRK) +XRC = (VNC, TDC) +JFL = (RRS, DVH) +KRT = (SKM, XMM) +CDD = (DVN, PDM) +NXP = (MKH, CRH) +LVT = (GRR, JPV) +NJT = (RLC, MTK) +HVV = (MFT, LGC) +RNG = (GMF, NXP) +SVR = (SMK, NHC) +QDJ = (SSN, JGX) +RQL = (BVQ, GMB) +HMR = (GHC, DTG) +CGX = (BDS, NDQ) +MJQ = (LVP, VSJ) +XJC = (CHN, VVH) +FFL = (GKN, PTC) +XJS = (SJK, SPG) +JQS = (PCN, LDP) +SHM = (JFL, KFN) +HPB = (LJR, RSS) +JXG = (SVF, TSJ) +STC = (QBQ, JPM) +FHT = (XXN, KRT) +LRD = (KQP, STN) +VCX = (SXK, NXB) +KSR = (TLF, TLF) +KQM = (PNN, TRB) +KTC = (TSL, XRG) +VKV = (VSJ, LVP) +XTB = (PPK, JQM) +BFK = (MJQ, VKV) +GLT = (VRN, DTR) +VPJ = (PFD, RSN) +BKT = (SGG, VTP) +BMQ = (VVM, VQG) +KVR = (QHF, XGG) +LNH = (QDC, GQV) +SLQ = (SJQ, TVN) +CJR = (RDP, MLK) +JCK = (TKR, PDK) +GVF = (XXH, NCV) +LQC = (TQC, KLB) +TSS = (SFH, RVQ) +HRL = (XVQ, PTP) +TDM = (GKK, LNV) +BNP = (BMQ, NSV) +BFG = (RNQ, PKH) +CFJ = (BKF, SCJ) +QQQ = (JPX, JPX) +MQV = (JSQ, TSS) +XHX = (LQD, FJG) +PMX = (XXJ, DSN) +KGM = (VPB, PHM) +GNR = (JLT, HSP) +NLS = (PTQ, SDR) +MSQ = (VJV, HQV) +FMB = (TJC, LQN) +XFV = (NRC, CPM) +RSN = (JGB, RGK) +PRK = (HVT, BKP) +HFV = (XJC, SHS) +SVF = (NMD, MGG) +QVX = (GQJ, RMH) +TCF = (BLF, JTQ) +MLK = (HSF, MQV) +RVQ = (FCM, GKF) +GLX = (XTX, JLL) +PDM = (SCR, JML) +HGR = (RKX, VGD) +JRB = (SND, SDG) +FKV = (SKX, HGL) +TDC = (LNH, CGS) +FVH = (XGL, BTF) +NHC = (FQS, FJJ) +BBK = (LNS, DPX) +VVH = (NNP, CVS) +NJK = (DLC, TCF) +SGL = (VJN, PVB) +MTV = (NQK, MHP) +PJS = (TFG, NCP) +DTG = (SCS, DBK) +TCJ = (SDP, PSV) +VGB = (HVK, XMV) +MCL = (SNQ, NVC) +NXX = (TLJ, VQC) +HVK = (MDV, CFJ) +NMD = (MCT, SST) +TTZ = (QXB, QGB) +VNC = (LNH, CGS) +GMB = (LSH, SDX) +CHN = (NNP, CVS) +FCV = (MJR, FJC) +HNG = (TDF, BQM) +SCR = (XKC, GLX) +DDF = (DHP, FVP) +CTK = (BGP, FCX) +CHG = (QJR, CDD) +VXL = (QFV, NHT) +SSJ = (XXH, NCV) +RNQ = (NPN, MHQ) +FJC = (XJF, XML) +XTZ = (PKH, RNQ) +CBN = (TNK, FQM) +RSB = (JJS, JJS) +TTH = (GXS, TXM) +HJH = (LKR, XJS) +VQB = (JCC, LGV) +HKV = (LJP, VQT) +RGN = (XRG, TSL) +MKX = (NPV, HCH) +JJS = (TST, KHB) +JPX = (MNJ, MNJ) +HTH = (MRV, GDV) +VQT = (CCD, FSM) +PGJ = (DHF, TCJ) +DHF = (SDP, PSV) +XJF = (GJF, RNR) +LQD = (CCF, NLS) +MRF = (DBH, HFT) +FNQ = (XGG, QHF) +GGM = (JXG, GMK) +BDS = (NXV, XQD) +MCM = (PGR, LJH) +LDP = (NDF, CQF) +QCJ = (RLC, MTK) +CCX = (RQV, BRF) +HBD = (BDF, FXL) +CBA = (RNQ, PKH) +MJR = (XJF, XML) +JCC = (LSB, NPF) +VQG = (NGQ, HDM) +RCB = (NSL, HPN) +QCV = (HBD, CST) +TDS = (LBH, BKT) +CNV = (QKQ, RBK) +KLB = (JQK, TXF) +XKH = (QNP, XCM) +SCJ = (CNB, NKP) +HGL = (CFR, HSC) +BDQ = (NTG, KTT) +PRR = (PGJ, NHD) +KPR = (CKV, LMN) +HFC = (LVF, BBJ) +TLF = (DKB, DKB) +SND = (HGR, RJN) +VNV = (PGR, LJH) +PLQ = (KKF, TVM) +LVF = (LVT, TKJ) +QJR = (PDM, DVN) +HVT = (DKG, PJG) +CFR = (QQL, NTJ) +DTM = (LTJ, RXP) +HNX = (GLT, DHJ) +QKQ = (FCN, MTB) +PTK = (HPC, PFK) +FQS = (FCF, KSS) +JBQ = (LCX, MQQ) +RXP = (LHK, FSV) +SSR = (DRH, CVN) +LSB = (VDC, KHQ) +DPX = (GNQ, VSB) +ZZZ = (GMV, QDM) +XFN = (TSR, KBT) +LNN = (NMV, FGF) +KQP = (LQC, HFR) +LHR = (XJS, LKR) +GCQ = (DVF, BXQ) +VVL = (TCF, DLC) +MKH = (NXX, BCD) diff --git a/src/days/test_inputs/test09.txt b/src/days/test_inputs/test09.txt new file mode 100644 index 0000000..539a763 --- /dev/null +++ b/src/days/test_inputs/test09.txt @@ -0,0 +1,3 @@ +0 3 6 9 12 15 +1 3 6 10 15 21 +10 13 16 21 30 45 diff --git a/src/days/test_inputs/test10.txt b/src/days/test_inputs/test10.txt new file mode 100644 index 0000000..8f950ae --- /dev/null +++ b/src/days/test_inputs/test10.txt @@ -0,0 +1,10 @@ +FF7FSF7F7F7F7F7F---7 +L|LJ||||||||||||F--J +FL-7LJLJ||||||LJL-77 +F--JF--7||LJLJ7F7FJ- +L---JF-JLJ.||-FJLJJ7 +|F|F-JF---7F7-L7L|7| +|FFJF7L7F-JF7|JL---7 +7-L-JL7||F7|L7F-7F7| +L.L7LFJ|||||FJL7||LJ +L7JLJL-JLJLJL--JLJ.L diff --git a/src/days/test_inputs/test11.txt b/src/days/test_inputs/test11.txt new file mode 100644 index 0000000..986aad4 --- /dev/null +++ b/src/days/test_inputs/test11.txt @@ -0,0 +1,10 @@ +...#...... +.......#.. +#......... +.......... +......#... +.#........ +.........# +.......... +.......#.. +#...#..... diff --git a/src/days/test_inputs/test12.txt b/src/days/test_inputs/test12.txt new file mode 100644 index 0000000..e925935 --- /dev/null +++ b/src/days/test_inputs/test12.txt @@ -0,0 +1,6 @@ +???.### 1,1,3 +.??..??...?##. 1,1,3 +?#?#?#?#?#?#?#? 1,3,1,6 +????.#...#... 4,1,1 +????.######..#####. 1,6,5 +?###???????? 3,2,1 diff --git a/src/days/test_inputs/test13.txt b/src/days/test_inputs/test13.txt new file mode 100644 index 0000000..3b6b5cc --- /dev/null +++ b/src/days/test_inputs/test13.txt @@ -0,0 +1,15 @@ +#.##..##. +..#.##.#. +##......# +##......# +..#.##.#. +..##..##. +#.#.##.#. + +#...##..# +#....#..# +..##..### +#####.##. +#####.##. +..##..### +#....#..# diff --git a/src/days/test_inputs/test14.txt b/src/days/test_inputs/test14.txt new file mode 100644 index 0000000..5a24dce --- /dev/null +++ b/src/days/test_inputs/test14.txt @@ -0,0 +1,10 @@ +O....#.... +O.OO#....# +.....##... +OO.#O....O +.O.....O#. +O.#..O.#.# +..O..#O..O +.......O.. +#....###.. +#OO..#.... diff --git a/src/days/test_inputs/test15.txt b/src/days/test_inputs/test15.txt new file mode 100644 index 0000000..4f58f74 --- /dev/null +++ b/src/days/test_inputs/test15.txt @@ -0,0 +1 @@ +rn=1,cm-,qp=3,cm=2,qp-,pc=4,ot=9,ab=5,pc-,pc=6,ot=7 diff --git a/src/days/test_inputs/test16.txt b/src/days/test_inputs/test16.txt new file mode 100644 index 0000000..d6805ce --- /dev/null +++ b/src/days/test_inputs/test16.txt @@ -0,0 +1,10 @@ +.|...\.... +|.-.\..... +.....|-... +........|. +.......... +.........\ +..../.\\.. +.-.-/..|.. +.|....-|.\ +..//.|.... diff --git a/src/days/test_inputs/test17.txt b/src/days/test_inputs/test17.txt new file mode 100644 index 0000000..f400d6e --- /dev/null +++ b/src/days/test_inputs/test17.txt @@ -0,0 +1,13 @@ +2413432311323 +3215453535623 +3255245654254 +3446585845452 +4546657867536 +1438598798454 +4457876987766 +3637877979653 +4654967986887 +4564679986453 +1224686865563 +2546548887735 +4322674655533 diff --git a/src/days/test_inputs/test18.txt b/src/days/test_inputs/test18.txt new file mode 100644 index 0000000..fc7612e --- /dev/null +++ b/src/days/test_inputs/test18.txt @@ -0,0 +1,14 @@ +R 6 (#70c710) +D 5 (#0dc571) +L 2 (#5713f0) +D 2 (#d2c081) +R 2 (#59c680) +D 2 (#411b91) +L 5 (#8ceee2) +U 2 (#caa173) +L 1 (#1b58a2) +U 2 (#caa171) +R 2 (#7807d2) +U 3 (#a77fa3) +L 2 (#015232) +U 2 (#7a21e3) diff --git a/src/days/test_inputs/test19.txt b/src/days/test_inputs/test19.txt new file mode 100644 index 0000000..e69de29 diff --git a/src/days/test_inputs/test20.txt b/src/days/test_inputs/test20.txt new file mode 100644 index 0000000..e69de29 diff --git a/src/days/test_inputs/test21.txt b/src/days/test_inputs/test21.txt new file mode 100644 index 0000000..e69de29 diff --git a/src/days/test_inputs/test22.txt b/src/days/test_inputs/test22.txt new file mode 100644 index 0000000..e69de29 diff --git a/src/days/test_inputs/test23.txt b/src/days/test_inputs/test23.txt new file mode 100644 index 0000000..e69de29 diff --git a/src/days/test_inputs/test24.txt b/src/days/test_inputs/test24.txt new file mode 100644 index 0000000..e69de29 diff --git a/src/days/test_inputs/test25.txt b/src/days/test_inputs/test25.txt new file mode 100644 index 0000000..e69de29 diff --git a/src/days/utils.rs b/src/days/utils.rs new file mode 100644 index 0000000..4c100e8 --- /dev/null +++ b/src/days/utils.rs @@ -0,0 +1,161 @@ +/// A general purpose struct able to store 2-Dimensional maps of Tiles. +/// +/// Can be parsed from a multi-line &str, if the T type implements [`From`](std::convert::From). +#[derive(Debug, Clone, Hash)] +pub struct Map { + tiles: Vec>, + dim: (usize, usize), +} + +#[allow(dead_code)] +impl Map { + /// Returns the dimensions of the map as a tuple `(x: usize, y: usize)` + pub fn dimensions(&self) -> (usize, usize) { + self.dim + } + + /// Gets the tile of a specified position. + /// + /// May return None, if the position is outside the dimensions. + pub fn get(&self, x: usize, y: usize) -> Option<&T> { + self.tiles.get(y)?.get(x) + } + + /// Sets the tile of a specified position. + pub fn set(&mut self, x: usize, y: usize, value: T) { + self.tiles[y][x] = value; + } + + /// Get the internally stored tile data. + pub fn get_raw_tiles(&self) -> &Vec> { + &self.tiles + } + + /// Get the internally stored tile data as mutable reference. + pub fn get_raw_tiles_mut(&mut self) -> &mut Vec> { + &mut self.tiles + } +} + +impl From>> for Map { + /// Creates a Map from a `Vec>`. + /// The dimensions are derived from the length of the y-Axis and first x line. + fn from(value: Vec>) -> Self { + Self { + dim: (value[0].len(), value.len()), + tiles: value, + } + } +} + +impl From<&str> for Map +where + T: From, +{ + fn from(value: &str) -> Self { + let tiles: Vec> = value + .lines() + .map(|v| v.chars().map(|v| v.into()).collect()) + .collect(); + + Self { + dim: (tiles[0].len(), tiles.len()), + tiles, + } + } +} + +#[allow(dead_code)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub enum Direction { + North, + East, + South, + West, +} + +impl Direction { + pub fn opposite(&self) -> Direction { + match self { + Self::North => Self::South, + Self::South => Self::North, + Self::West => Self::East, + Self::East => Self::West, + } + } + + pub fn walk_pos( + &self, + pos: (usize, usize), + upper_limit: (usize, usize), + ) -> Option<(usize, usize)> { + match self { + Self::North => { + if pos.1 != 0 { + Some((pos.0, pos.1 - 1)) + } else { + None + } + } + Self::South => { + if pos.1 < upper_limit.1 { + Some((pos.0, pos.1 + 1)) + } else { + None + } + } + Self::West => { + if pos.0 != 0 { + Some((pos.0 - 1, pos.1)) + } else { + None + } + } + Self::East => { + if pos.0 < upper_limit.0 { + Some((pos.0 + 1, pos.1)) + } else { + None + } + } + } + } + + pub fn walk_pos_signed( + &self, + pos: (isize, isize), + lower_limit: (isize, isize), + upper_limit: (isize, isize), + ) -> Option<(isize, isize)> { + match self { + Self::North => { + if pos.1 > lower_limit.1 { + Some((pos.0, pos.1 - 1)) + } else { + None + } + } + Self::South => { + if pos.1 < upper_limit.1 { + Some((pos.0, pos.1 + 1)) + } else { + None + } + } + Self::West => { + if pos.0 > lower_limit.0 { + Some((pos.0 - 1, pos.1)) + } else { + None + } + } + Self::East => { + if pos.0 < upper_limit.0 { + Some((pos.0 + 1, pos.1)) + } else { + None + } + } + } + } +} diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..0ced62d --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,261 @@ +use crate::days::Answer; +use crate::days::Day; +use crate::days::DayImpl; +use aoc_macro::*; +use colored::*; +use lazy_static::lazy_static; +use mut_static::MutStatic; +use std::time::Duration; + +mod days; + +#[derive(Debug, Clone, PartialEq)] +pub enum Verbosity { + None, + Verbose, + Development, +} + +#[derive(Debug, Clone, PartialEq)] +pub enum Part { + One, + Two, + Both, +} + +#[derive(Debug, Clone)] +pub struct Settings { + verbosity: Verbosity, +} + +impl Settings { + fn set_verbosity(&mut self, new: Verbosity) { + self.verbosity = new; + } +} + +lazy_static! { + static ref VERBOSITY: MutStatic = MutStatic::from(Settings { + verbosity: Verbosity::None + }); +} + +pub fn set_verbosity(new_verbosity: Verbosity) { + let mut handle = VERBOSITY.write().unwrap(); + handle.set_verbosity(new_verbosity); +} + +pub fn get_verbosity() -> Verbosity { + VERBOSITY.read().unwrap().verbosity.clone() +} + +#[macro_export] +macro_rules! vprintln { + ($($arg:tt)*) => { + #[cfg(debug_assertions)] + if $crate::get_verbosity() == $crate::Verbosity::Verbose || $crate::get_verbosity() == $crate::Verbosity::Development { + println!( + $($arg)* + ) + } + }; +} + +#[macro_export] +macro_rules! vprint { + ($($arg:tt)*) => { + #[cfg(debug_assertions)] + if $crate::get_verbosity() == $crate::Verbosity::Verbose || $crate::get_verbosity() == $crate::Verbosity::Development { + print!( + $($arg)* + ) + } + }; +} + +#[macro_export] +macro_rules! dprintln { + ($($arg:tt)*) => { + #[cfg(debug_assertions)] + if $crate::get_verbosity() == $crate::Verbosity::Development { + println!( + $($arg)* + ) + } + }; +} + +#[macro_export] +macro_rules! dprint { + ($($arg:tt)*) => { + #[cfg(debug_assertions)] + if $crate::get_verbosity() == $crate::Verbosity::Development { + print!( + $($arg)* + ) + } + }; +} + +fn dynamic_range_time_format(d: &Duration) -> String { + let nanos = d.as_nanos(); + + if nanos < 1000 { + // less than one microsecond + format!("{} ns", nanos) + } else if nanos < 100000 { + // less than 10 microseconds + format!("{:.3} ยตs", nanos as f64 / 1000.0) + } else if nanos < 1000000 { + // less than one millisecond + format!("{} ยตs", nanos / 1000) + } else if nanos < 10000000 { + // less than 10 milliseconds + format!("{:.3} ms", nanos as f64 / 1000000.0) + } else if nanos < 1000000000 { + // less than a second + format!("{} ms", nanos / 1000000) + } else if nanos < 10000000000 { + // less than 10 seconds + format!("{:.3} s", nanos as f64 / 1000000000.0) + } else { + // more than 10 seconds + format!("{} s", nanos / 1000000000) + } +} + +pub fn run_day(day: u8, part: Part, input: &str) { + println!("{} Day {}", "Starting".green().bold(), day); + println!("{}", "-----------------------".green().bold()); + let (one, two, init_t, one_t, two_t) = match part { + Part::Both => match_and_run_day_both!(), + Part::One => { + let (one, init_t, one_t) = match_and_run_day_one!(); + (one, Answer::Number(0), init_t, one_t, Duration::ZERO) + } + Part::Two => { + let (two, init_t, two_t) = match_and_run_day_two!(); + (Answer::Number(0), two, init_t, Duration::ZERO, two_t) + } + }; + + println!("{}:", "Results".green().bold()); + println!( + "\t{}: {}", + "Parsing time".green(), + dynamic_range_time_format(&init_t).bold().blue() + ); + if part == Part::Both || part == Part::One { + println!("\t{}:", "Part 1".green()); + println!("\t\tSolution: {}", format!("{}", one).bold().blue()); + println!( + "\t\tTook: {}", + if cfg!(debug_assertions) { + (dynamic_range_time_format(&one_t) + " (DEBUG)") + .bold() + .red() + } else { + dynamic_range_time_format(&one_t).bold().blue() + } + ); + } + if part == Part::Both || part == Part::Two { + println!("\t{}:", "Part 2".green()); + println!("\t\tSolution: {}", format!("{}", two).bold().blue()); + println!( + "\t\tTook: {}", + if cfg!(debug_assertions) { + (dynamic_range_time_format(&two_t) + " (DEBUG)") + .bold() + .red() + } else { + dynamic_range_time_format(&two_t).bold().blue() + } + ); + } +} + +pub fn test_day(day: u8, part: Part) -> bool { + println!("{} Day {}", "Testing".green().bold(), day); + println!("{}", "-----------------------".green().bold()); + match part { + Part::Both => { + let ((one_p, one_r, one_e), (two_p, two_r, two_e)) = match_and_test_day_both!(); + + println!("{}:", "Results".green().bold()); + println!( + "\t{}: {}", + "Part 1".green(), + match one_p { + true => { + "PASSED".green().bold() + } + false => { + "FAILED".red().bold() + } + } + ); + println!("\t\tResult: {}", format!("{}", one_r).bold().blue()); + println!("\t\tExpected: {}", format!("{}", one_e).bold().blue()); + + println!( + "\t{}: {}", + "Part 2".green(), + match two_p { + true => { + "PASSED".green().bold() + } + false => { + "FAILED".red().bold() + } + } + ); + println!("\t\tResult: {}", format!("{}", two_r).bold().blue()); + println!("\t\tExpected: {}", format!("{}", two_e).bold().blue()); + + !(!two_p || !one_p) + } + Part::One => { + let (one_p, one_r, one_e) = match_and_test_day_one!(); + + println!("{}:", "Results".green().bold()); + println!( + "\t{}: {}", + "Part 1".green(), + match one_p { + true => { + "PASSED".green().bold() + } + false => { + "FAILED".red().bold() + } + } + ); + println!("\t\tResult: {}", format!("{}", one_r).bold().blue()); + println!("\t\tExpected: {}", format!("{}", one_e).bold().blue()); + + !one_p + } + Part::Two => { + let (two_p, two_r, two_e) = match_and_test_day_two!(); + + println!("{}:", "Results".green().bold()); + println!( + "\t{}: {}", + "Part 2".green(), + match two_p { + true => { + "PASSED".green().bold() + } + false => { + "FAILED".red().bold() + } + } + ); + println!("\t\tResult: {}", format!("{}", two_r).bold().blue()); + println!("\t\tExpected: {}", format!("{}", two_e).bold().blue()); + + !two_p + } + } +} diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..a377111 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,259 @@ +use aoc23::{run_day, set_verbosity, test_day, Part, Verbosity}; +use clap::{App, AppSettings, Arg, SubCommand}; +use colored::*; +use reqwest::blocking::Client; +use reqwest::cookie::Jar; +use reqwest::header::USER_AGENT; +use std::env; +use std::fs; +use std::path::Path; +use std::sync::Arc; + +// NOTE: Since this CLI was coded using clap in december of 2021, there seem to +// have been huge breaking changes, requiring me to rewrite the CLI completely +// to be able to update Clap. As I am on a limited time schedule RN, I will +// probably do this later on. +// 2023-11-29: still haven't done this, maybe I'll do is this year. +// TODO: Rewrite CLI and update Clap + +fn main() { + let matches = App::new("Advent Of Code 2023") + .author("LeMoonStar ") + .about("My Advent Of Code 2023 solutions.") + .setting(AppSettings::SubcommandRequiredElseHelp) + .arg( + Arg::with_name("day") + .help("The number of the day to execute") + .required(true) + .takes_value(true) + .validator(|v| match v.parse::() { + Ok(day) => { + if 0 < day && day <= 25 { + Ok(()) + } else { + Err("The day must be between 1 and 25.".to_string()) + } + } + Err(_) => Err("The day must be a number between 1 and 25.".to_string()), + }), + ) + .arg( + Arg::with_name("part") + .help("Specifies the part of the day to compute.") + .long("part") + .short("p") + .default_value("b") + .possible_values(&["1", "2", "b"]) + .takes_value(true), + ) + .arg( + Arg::with_name("verbose") + .help("Print verbose information") + .long("verbose") + .short("v") + .conflicts_with("development")) + .arg( + Arg::with_name("development") + .help("Print development information") + .long("dev") + .short("d") + .conflicts_with("verbose")) + .subcommand( + SubCommand::with_name("test").about("Test the day with the example input data."), + ) + .subcommand( + SubCommand::with_name("auto") + .about("Automatically download input from AoC using the provided session and run the solution.") + .arg(Arg::with_name("session") + .help("The AoC browser session string. If not provided, uses the AOC_SESSION environment variable.") + .short("s") + .long("session") + .takes_value(true)) + .arg(Arg::with_name("no_cache") + .help("Don't cache the input, and delete any current cache for this day.") + .short("N") + .long("no-cache"))) + .subcommand( + SubCommand::with_name("run") + .about("Use either a file or stdin as input and run the solution.") + .arg(Arg::with_name("file") + .help("Specify a file to be used as input, otherwise use stdin.") + .short("f") + .long("file") + .takes_value(true) + ) + ) + .get_matches(); + + if cfg!(debug_assertions) { + println!( + "{}", + "This binary was built in debug mode. To improve performance, please add --release to the build command." + .red() + .bold() + ); + } + + let day = matches + .value_of("day") + .unwrap() + .parse::() + .expect("Failed to parse day argument."); + + let part: Part = match matches.value_of("part") { + Some("1") => Part::One, + Some("2") => Part::Two, + Some("b") => Part::Both, + _ => panic!("unexpected part argument."), + }; + + if matches.args.contains_key("verbose") { + #[cfg(not(debug_assertions))] + println!("{}", "verbosity and development prints are only available in unoptimized builds (compiled without --release).".red().bold()); + set_verbosity(Verbosity::Verbose); + } + + if matches.args.contains_key("development") { + #[cfg(not(debug_assertions))] + println!("{}", "verbosity and development prints are only available in unoptimized builds (compiled without --release).".red().bold()); + set_verbosity(Verbosity::Development); + } + + match matches.subcommand() { + ("run", c_matches) => { + let input = match c_matches { + Some(c_matches) => { + if let Some(f) = c_matches.value_of("file") { + fs::read_to_string(Path::new(f)).expect("Error while reading input file") + } else { + get_stdin_day_input(day) + } + } + None => get_stdin_day_input(day), + }; + run_day(day, part, &input); + } + ("auto", c_matches) => { + let session: Option = match c_matches { + Some(c_matches) => match c_matches.value_of("session") { + Some(v) => Some(v.to_owned()), + None => env::var("AOC_SESSION").ok(), + }, + None => env::var("AOC_SESSION").ok(), + }; + let cache = if let Some(c_matches) = c_matches { + !c_matches.args.contains_key("no_cache") + } else { + true + }; + + let input = get_auto_input(day, session.as_ref(), cache); + run_day(day, part, &input); + } + ("test", _) => { + if !test_day(day, part) { + std::process::exit(1); + } + } + _ => panic!("Unexpected Subcommand."), + } +} + +fn get_stdin_day_input(day: u8) -> String { + let mut input = String::new(); + let stdin = std::io::stdin(); + + println!( + "Please paste your input for day {}, and then press {}", + day, + match cfg!(windows) { + true => "CTRL-Z", + _ => "CTRL-D", + } + ); + + loop { + match stdin.read_line(&mut input) { + Ok(l) => { + if l == 0 { + break; + } + } + Err(err) => panic!("Error encountered while trying to read stdin: {}", err), + } + } + + input +} + +fn download_input(day: u8, session: &String) -> Result { + println!("Downloading input for day {}", day); + + let cookie_jar = Jar::default(); + cookie_jar.add_cookie_str( + format!("session={}; Domain=adventofcode.com", session).as_ref(), + &"https://adventofcode.com/".parse::().unwrap(), + ); + let client = Client::builder() + .https_only(true) + .cookie_provider(Arc::new(cookie_jar)) + .build()?; + + let response = client + .get(format!("https://adventofcode.com/2023/day/{}/input", day)) + .header( + USER_AGENT, + "https://github.com/LeMoonStar/AoC23 aoc23@unitcore.de", + ) + .send()?; + + if !response.status().is_success() { + panic!("Server error or invalid session."); + } + + response.text() +} + +fn get_auto_input(day: u8, session: Option<&String>, cache: bool) -> String { + let cache_str = &format!("./.aoc23_cache/input{:02}.txt", day); + let cache_path: &Path = Path::new(cache_str); + match cache { + true => match fs::read_to_string(cache_path) { + Ok(input) => input, + Err(_) => { + if let Some(session) = session { + match download_input(day, session) { + Ok(input) => { + let _ = fs::create_dir(Path::new("./.aoc23_cache")); + match fs::write(cache_path, &input) { + Ok(_) => {} + Err(err) => { + println!("Warning! couldn't save input cache!{:?}", err) + } + } + input + } + Err(err) => { + panic!("Error while downloading input: {:?}", err); + } + } + } else { + panic!("Neither a session argument nor the AOC_SESSION environment variable were provided, and there is no cache of the day's input."); + } + } + }, + false => { + let _ = fs::remove_file(cache_path); + if let Some(session) = session { + match download_input(day, session) { + Ok(input) => input, + Err(err) => { + panic!("Error while downloading input: {:?}", err); + } + } + } else { + panic!("Neither a session argument nor the AOC_SESSION environment variable were provided, and there is no cache of the day's input."); + } + } + } +}