mirror of
https://github.com/LeMoonStar/AoC24.git
synced 2025-07-07 10:05:31 +02:00
🎉 Initialized repository based on 2023 code
This commit is contained in:
commit
cc42c33b5d
65 changed files with 3897 additions and 0 deletions
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
/target
|
||||||
|
.aoc23_cache
|
21
Cargo.toml
Normal file
21
Cargo.toml
Normal file
|
@ -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
|
21
LICENSE
Normal file
21
LICENSE
Normal file
|
@ -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.
|
49
README.md
Normal file
49
README.md
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
# Advent of Code 2024
|
||||||
|
|
||||||
|
[](https://adventofcode.com/2024/about)
|
||||||
|
[](https://en.wikipedia.org/wiki/Rust_(programming_language))
|
||||||
|
[](https://mit-license.org/)
|
||||||
|

|
||||||
|

|
||||||
|
|
||||||
|
> ⚠️ 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:
|
||||||
|

|
||||||
|
|
||||||
|
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`:
|
||||||
|

|
||||||
|
|
||||||
|
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`:
|
||||||
|

|
||||||
|
|
||||||
|
## 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 |
|
1
aoc-macro/.gitignore
vendored
Normal file
1
aoc-macro/.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
/target
|
46
aoc-macro/Cargo.lock
generated
Normal file
46
aoc-macro/Cargo.lock
generated
Normal file
|
@ -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"
|
13
aoc-macro/Cargo.toml
Normal file
13
aoc-macro/Cargo.toml
Normal file
|
@ -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"
|
108
aoc-macro/src/lib.rs
Normal file
108
aoc-macro/src/lib.rs
Normal file
|
@ -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()
|
||||||
|
}
|
BIN
images/auto.png
Normal file
BIN
images/auto.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 18 KiB |
BIN
images/run.png
Normal file
BIN
images/run.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 19 KiB |
BIN
images/test.png
Normal file
BIN
images/test.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 18 KiB |
32
src/days/d01.rs
Normal file
32
src/days/d01.rs
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
use super::{Answer, Day, DayImpl};
|
||||||
|
|
||||||
|
const CURRENT_DAY: u8 = 1;
|
||||||
|
|
||||||
|
type Data = Vec<u64>;
|
||||||
|
impl DayImpl<Data> for Day<CURRENT_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::<u64>().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)
|
||||||
|
}
|
||||||
|
}
|
32
src/days/d02.rs
Normal file
32
src/days/d02.rs
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
use super::{Answer, Day, DayImpl};
|
||||||
|
|
||||||
|
const CURRENT_DAY: u8 = 2;
|
||||||
|
|
||||||
|
type Data = Vec<u64>;
|
||||||
|
impl DayImpl<Data> for Day<CURRENT_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::<u64>().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)
|
||||||
|
}
|
||||||
|
}
|
32
src/days/d03.rs
Normal file
32
src/days/d03.rs
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
use super::{Answer, Day, DayImpl};
|
||||||
|
|
||||||
|
const CURRENT_DAY: u8 = 3;
|
||||||
|
|
||||||
|
type Data = Vec<u64>;
|
||||||
|
impl DayImpl<Data> for Day<CURRENT_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::<u64>().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)
|
||||||
|
}
|
||||||
|
}
|
32
src/days/d04.rs
Normal file
32
src/days/d04.rs
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
use super::{Answer, Day, DayImpl};
|
||||||
|
|
||||||
|
const CURRENT_DAY: u8 = 4;
|
||||||
|
|
||||||
|
type Data = Vec<u64>;
|
||||||
|
impl DayImpl<Data> for Day<CURRENT_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::<u64>().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)
|
||||||
|
}
|
||||||
|
}
|
32
src/days/d05.rs
Normal file
32
src/days/d05.rs
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
use super::{Answer, Day, DayImpl};
|
||||||
|
|
||||||
|
const CURRENT_DAY: u8 = 5;
|
||||||
|
|
||||||
|
type Data = Vec<u64>;
|
||||||
|
impl DayImpl<Data> for Day<CURRENT_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::<u64>().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)
|
||||||
|
}
|
||||||
|
}
|
32
src/days/d06.rs
Normal file
32
src/days/d06.rs
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
use super::{Answer, Day, DayImpl};
|
||||||
|
|
||||||
|
const CURRENT_DAY: u8 = 6;
|
||||||
|
|
||||||
|
type Data = Vec<u64>;
|
||||||
|
impl DayImpl<Data> for Day<CURRENT_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::<u64>().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)
|
||||||
|
}
|
||||||
|
}
|
32
src/days/d07.rs
Normal file
32
src/days/d07.rs
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
use super::{Answer, Day, DayImpl};
|
||||||
|
|
||||||
|
const CURRENT_DAY: u8 = 7;
|
||||||
|
|
||||||
|
type Data = Vec<u64>;
|
||||||
|
impl DayImpl<Data> for Day<CURRENT_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::<u64>().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)
|
||||||
|
}
|
||||||
|
}
|
32
src/days/d08.rs
Normal file
32
src/days/d08.rs
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
use super::{Answer, Day, DayImpl};
|
||||||
|
|
||||||
|
const CURRENT_DAY: u8 = 8;
|
||||||
|
|
||||||
|
type Data = Vec<u64>;
|
||||||
|
impl DayImpl<Data> for Day<CURRENT_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::<u64>().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)
|
||||||
|
}
|
||||||
|
}
|
32
src/days/d09.rs
Normal file
32
src/days/d09.rs
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
use super::{Answer, Day, DayImpl};
|
||||||
|
|
||||||
|
const CURRENT_DAY: u8 = 9;
|
||||||
|
|
||||||
|
type Data = Vec<u64>;
|
||||||
|
impl DayImpl<Data> for Day<CURRENT_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::<u64>().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)
|
||||||
|
}
|
||||||
|
}
|
32
src/days/d10.rs
Normal file
32
src/days/d10.rs
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
use super::{Answer, Day, DayImpl};
|
||||||
|
|
||||||
|
const CURRENT_DAY: u8 = 10;
|
||||||
|
|
||||||
|
type Data = Vec<u64>;
|
||||||
|
impl DayImpl<Data> for Day<CURRENT_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::<u64>().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)
|
||||||
|
}
|
||||||
|
}
|
32
src/days/d11.rs
Normal file
32
src/days/d11.rs
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
use super::{Answer, Day, DayImpl};
|
||||||
|
|
||||||
|
const CURRENT_DAY: u8 = 11;
|
||||||
|
|
||||||
|
type Data = Vec<u64>;
|
||||||
|
impl DayImpl<Data> for Day<CURRENT_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::<u64>().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)
|
||||||
|
}
|
||||||
|
}
|
32
src/days/d12.rs
Normal file
32
src/days/d12.rs
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
use super::{Answer, Day, DayImpl};
|
||||||
|
|
||||||
|
const CURRENT_DAY: u8 = 12;
|
||||||
|
|
||||||
|
type Data = Vec<u64>;
|
||||||
|
impl DayImpl<Data> for Day<CURRENT_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::<u64>().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)
|
||||||
|
}
|
||||||
|
}
|
32
src/days/d13.rs
Normal file
32
src/days/d13.rs
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
use super::{Answer, Day, DayImpl};
|
||||||
|
|
||||||
|
const CURRENT_DAY: u8 = 13;
|
||||||
|
|
||||||
|
type Data = Vec<u64>;
|
||||||
|
impl DayImpl<Data> for Day<CURRENT_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::<u64>().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)
|
||||||
|
}
|
||||||
|
}
|
32
src/days/d14.rs
Normal file
32
src/days/d14.rs
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
use super::{Answer, Day, DayImpl};
|
||||||
|
|
||||||
|
const CURRENT_DAY: u8 = 14;
|
||||||
|
|
||||||
|
type Data = Vec<u64>;
|
||||||
|
impl DayImpl<Data> for Day<CURRENT_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::<u64>().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)
|
||||||
|
}
|
||||||
|
}
|
32
src/days/d15.rs
Normal file
32
src/days/d15.rs
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
use super::{Answer, Day, DayImpl};
|
||||||
|
|
||||||
|
const CURRENT_DAY: u8 = 15;
|
||||||
|
|
||||||
|
type Data = Vec<u64>;
|
||||||
|
impl DayImpl<Data> for Day<CURRENT_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::<u64>().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)
|
||||||
|
}
|
||||||
|
}
|
32
src/days/d16.rs
Normal file
32
src/days/d16.rs
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
use super::{Answer, Day, DayImpl};
|
||||||
|
|
||||||
|
const CURRENT_DAY: u8 = 16;
|
||||||
|
|
||||||
|
type Data = Vec<u64>;
|
||||||
|
impl DayImpl<Data> for Day<CURRENT_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::<u64>().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)
|
||||||
|
}
|
||||||
|
}
|
32
src/days/d17.rs
Normal file
32
src/days/d17.rs
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
use super::{Answer, Day, DayImpl};
|
||||||
|
|
||||||
|
const CURRENT_DAY: u8 = 17;
|
||||||
|
|
||||||
|
type Data = Vec<u64>;
|
||||||
|
impl DayImpl<Data> for Day<CURRENT_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::<u64>().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)
|
||||||
|
}
|
||||||
|
}
|
32
src/days/d18.rs
Normal file
32
src/days/d18.rs
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
use super::{Answer, Day, DayImpl};
|
||||||
|
|
||||||
|
const CURRENT_DAY: u8 = 18;
|
||||||
|
|
||||||
|
type Data = Vec<u64>;
|
||||||
|
impl DayImpl<Data> for Day<CURRENT_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::<u64>().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)
|
||||||
|
}
|
||||||
|
}
|
32
src/days/d19.rs
Normal file
32
src/days/d19.rs
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
use super::{Answer, Day, DayImpl};
|
||||||
|
|
||||||
|
const CURRENT_DAY: u8 = 19;
|
||||||
|
|
||||||
|
type Data = Vec<u64>;
|
||||||
|
impl DayImpl<Data> for Day<CURRENT_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::<u64>().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)
|
||||||
|
}
|
||||||
|
}
|
32
src/days/d20.rs
Normal file
32
src/days/d20.rs
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
use super::{Answer, Day, DayImpl};
|
||||||
|
|
||||||
|
const CURRENT_DAY: u8 = 20;
|
||||||
|
|
||||||
|
type Data = Vec<u64>;
|
||||||
|
impl DayImpl<Data> for Day<CURRENT_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::<u64>().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)
|
||||||
|
}
|
||||||
|
}
|
32
src/days/d21.rs
Normal file
32
src/days/d21.rs
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
use super::{Answer, Day, DayImpl};
|
||||||
|
|
||||||
|
const CURRENT_DAY: u8 = 21;
|
||||||
|
|
||||||
|
type Data = Vec<u64>;
|
||||||
|
impl DayImpl<Data> for Day<CURRENT_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::<u64>().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)
|
||||||
|
}
|
||||||
|
}
|
32
src/days/d22.rs
Normal file
32
src/days/d22.rs
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
use super::{Answer, Day, DayImpl};
|
||||||
|
|
||||||
|
const CURRENT_DAY: u8 = 22;
|
||||||
|
|
||||||
|
type Data = Vec<u64>;
|
||||||
|
impl DayImpl<Data> for Day<CURRENT_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::<u64>().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)
|
||||||
|
}
|
||||||
|
}
|
32
src/days/d23.rs
Normal file
32
src/days/d23.rs
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
use super::{Answer, Day, DayImpl};
|
||||||
|
|
||||||
|
const CURRENT_DAY: u8 = 23;
|
||||||
|
|
||||||
|
type Data = Vec<u64>;
|
||||||
|
impl DayImpl<Data> for Day<CURRENT_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::<u64>().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)
|
||||||
|
}
|
||||||
|
}
|
32
src/days/d24.rs
Normal file
32
src/days/d24.rs
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
use super::{Answer, Day, DayImpl};
|
||||||
|
|
||||||
|
const CURRENT_DAY: u8 = 24;
|
||||||
|
|
||||||
|
type Data = Vec<u64>;
|
||||||
|
impl DayImpl<Data> for Day<CURRENT_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::<u64>().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)
|
||||||
|
}
|
||||||
|
}
|
32
src/days/d25.rs
Normal file
32
src/days/d25.rs
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
use super::{Answer, Day, DayImpl};
|
||||||
|
|
||||||
|
const CURRENT_DAY: u8 = 25;
|
||||||
|
|
||||||
|
type Data = Vec<u64>;
|
||||||
|
impl DayImpl<Data> for Day<CURRENT_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::<u64>().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)
|
||||||
|
}
|
||||||
|
}
|
250
src/days/mod.rs
Normal file
250
src/days/mod.rs
Normal file
|
@ -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<const DAY: u8>;
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
|
pub enum Answer {
|
||||||
|
Number(u64),
|
||||||
|
String(String),
|
||||||
|
Bitmap(Vec<Vec<bool>>),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Answer {
|
||||||
|
fn append_per_line(str: String, prefix: &str) -> String {
|
||||||
|
str.lines()
|
||||||
|
.map(|v| prefix.to_owned() + v + "\n")
|
||||||
|
.collect::<String>()
|
||||||
|
.strip_suffix('\n')
|
||||||
|
.unwrap()
|
||||||
|
.to_owned()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bm_get(bm: &[Vec<bool>], 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<Vec<bool>>) -> 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<u64> for Answer {
|
||||||
|
fn from(n: u64) -> Self {
|
||||||
|
Self::Number(n)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<String> for Answer {
|
||||||
|
fn from(s: String) -> Self {
|
||||||
|
Self::String(s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait DayImpl<T>
|
||||||
|
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!();
|
1000
src/days/test_inputs/test01.txt
Normal file
1000
src/days/test_inputs/test01.txt
Normal file
File diff suppressed because it is too large
Load diff
5
src/days/test_inputs/test02.txt
Normal file
5
src/days/test_inputs/test02.txt
Normal file
|
@ -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
|
10
src/days/test_inputs/test03.txt
Normal file
10
src/days/test_inputs/test03.txt
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
467..114..
|
||||||
|
...*......
|
||||||
|
..35..633.
|
||||||
|
......#...
|
||||||
|
617*......
|
||||||
|
.....+.58.
|
||||||
|
..592.....
|
||||||
|
......755.
|
||||||
|
...$.*....
|
||||||
|
.664.598..
|
6
src/days/test_inputs/test04.txt
Normal file
6
src/days/test_inputs/test04.txt
Normal file
|
@ -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
|
33
src/days/test_inputs/test05.txt
Normal file
33
src/days/test_inputs/test05.txt
Normal file
|
@ -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
|
2
src/days/test_inputs/test06.txt
Normal file
2
src/days/test_inputs/test06.txt
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
Time: 7 15 30
|
||||||
|
Distance: 9 40 200
|
5
src/days/test_inputs/test07.txt
Normal file
5
src/days/test_inputs/test07.txt
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
32T3K 765
|
||||||
|
T55J5 684
|
||||||
|
KK677 28
|
||||||
|
KTJJT 220
|
||||||
|
QQQJA 483
|
752
src/days/test_inputs/test08.txt
Normal file
752
src/days/test_inputs/test08.txt
Normal file
|
@ -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)
|
3
src/days/test_inputs/test09.txt
Normal file
3
src/days/test_inputs/test09.txt
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
0 3 6 9 12 15
|
||||||
|
1 3 6 10 15 21
|
||||||
|
10 13 16 21 30 45
|
10
src/days/test_inputs/test10.txt
Normal file
10
src/days/test_inputs/test10.txt
Normal file
|
@ -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
|
10
src/days/test_inputs/test11.txt
Normal file
10
src/days/test_inputs/test11.txt
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
...#......
|
||||||
|
.......#..
|
||||||
|
#.........
|
||||||
|
..........
|
||||||
|
......#...
|
||||||
|
.#........
|
||||||
|
.........#
|
||||||
|
..........
|
||||||
|
.......#..
|
||||||
|
#...#.....
|
6
src/days/test_inputs/test12.txt
Normal file
6
src/days/test_inputs/test12.txt
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
???.### 1,1,3
|
||||||
|
.??..??...?##. 1,1,3
|
||||||
|
?#?#?#?#?#?#?#? 1,3,1,6
|
||||||
|
????.#...#... 4,1,1
|
||||||
|
????.######..#####. 1,6,5
|
||||||
|
?###???????? 3,2,1
|
15
src/days/test_inputs/test13.txt
Normal file
15
src/days/test_inputs/test13.txt
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
#.##..##.
|
||||||
|
..#.##.#.
|
||||||
|
##......#
|
||||||
|
##......#
|
||||||
|
..#.##.#.
|
||||||
|
..##..##.
|
||||||
|
#.#.##.#.
|
||||||
|
|
||||||
|
#...##..#
|
||||||
|
#....#..#
|
||||||
|
..##..###
|
||||||
|
#####.##.
|
||||||
|
#####.##.
|
||||||
|
..##..###
|
||||||
|
#....#..#
|
10
src/days/test_inputs/test14.txt
Normal file
10
src/days/test_inputs/test14.txt
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
O....#....
|
||||||
|
O.OO#....#
|
||||||
|
.....##...
|
||||||
|
OO.#O....O
|
||||||
|
.O.....O#.
|
||||||
|
O.#..O.#.#
|
||||||
|
..O..#O..O
|
||||||
|
.......O..
|
||||||
|
#....###..
|
||||||
|
#OO..#....
|
1
src/days/test_inputs/test15.txt
Normal file
1
src/days/test_inputs/test15.txt
Normal file
|
@ -0,0 +1 @@
|
||||||
|
rn=1,cm-,qp=3,cm=2,qp-,pc=4,ot=9,ab=5,pc-,pc=6,ot=7
|
10
src/days/test_inputs/test16.txt
Normal file
10
src/days/test_inputs/test16.txt
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
.|...\....
|
||||||
|
|.-.\.....
|
||||||
|
.....|-...
|
||||||
|
........|.
|
||||||
|
..........
|
||||||
|
.........\
|
||||||
|
..../.\\..
|
||||||
|
.-.-/..|..
|
||||||
|
.|....-|.\
|
||||||
|
..//.|....
|
13
src/days/test_inputs/test17.txt
Normal file
13
src/days/test_inputs/test17.txt
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
2413432311323
|
||||||
|
3215453535623
|
||||||
|
3255245654254
|
||||||
|
3446585845452
|
||||||
|
4546657867536
|
||||||
|
1438598798454
|
||||||
|
4457876987766
|
||||||
|
3637877979653
|
||||||
|
4654967986887
|
||||||
|
4564679986453
|
||||||
|
1224686865563
|
||||||
|
2546548887735
|
||||||
|
4322674655533
|
14
src/days/test_inputs/test18.txt
Normal file
14
src/days/test_inputs/test18.txt
Normal file
|
@ -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)
|
0
src/days/test_inputs/test19.txt
Normal file
0
src/days/test_inputs/test19.txt
Normal file
0
src/days/test_inputs/test20.txt
Normal file
0
src/days/test_inputs/test20.txt
Normal file
0
src/days/test_inputs/test21.txt
Normal file
0
src/days/test_inputs/test21.txt
Normal file
0
src/days/test_inputs/test22.txt
Normal file
0
src/days/test_inputs/test22.txt
Normal file
0
src/days/test_inputs/test23.txt
Normal file
0
src/days/test_inputs/test23.txt
Normal file
0
src/days/test_inputs/test24.txt
Normal file
0
src/days/test_inputs/test24.txt
Normal file
0
src/days/test_inputs/test25.txt
Normal file
0
src/days/test_inputs/test25.txt
Normal file
161
src/days/utils.rs
Normal file
161
src/days/utils.rs
Normal file
|
@ -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<char>`](std::convert::From).
|
||||||
|
#[derive(Debug, Clone, Hash)]
|
||||||
|
pub struct Map<T> {
|
||||||
|
tiles: Vec<Vec<T>>,
|
||||||
|
dim: (usize, usize),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
impl<T> Map<T> {
|
||||||
|
/// 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<Vec<T>> {
|
||||||
|
&self.tiles
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the internally stored tile data as mutable reference.
|
||||||
|
pub fn get_raw_tiles_mut(&mut self) -> &mut Vec<Vec<T>> {
|
||||||
|
&mut self.tiles
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> From<Vec<Vec<T>>> for Map<T> {
|
||||||
|
/// Creates a Map from a `Vec<Vec<T>>`.
|
||||||
|
/// The dimensions are derived from the length of the y-Axis and first x line.
|
||||||
|
fn from(value: Vec<Vec<T>>) -> Self {
|
||||||
|
Self {
|
||||||
|
dim: (value[0].len(), value.len()),
|
||||||
|
tiles: value,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> From<&str> for Map<T>
|
||||||
|
where
|
||||||
|
T: From<char>,
|
||||||
|
{
|
||||||
|
fn from(value: &str) -> Self {
|
||||||
|
let tiles: Vec<Vec<T>> = 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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
261
src/lib.rs
Normal file
261
src/lib.rs
Normal file
|
@ -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<Settings> = 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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
259
src/main.rs
Normal file
259
src/main.rs
Normal file
|
@ -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 <webmaster@unitcore.de>")
|
||||||
|
.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::<u8>() {
|
||||||
|
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::<u8>()
|
||||||
|
.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<String> = 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<String, reqwest::Error> {
|
||||||
|
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::<reqwest::Url>().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.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue