🎉 Initialized repository based on 2023 code

This commit is contained in:
LeMoonStar 2024-11-30 13:39:19 +01:00
commit cc42c33b5d
65 changed files with 3897 additions and 0 deletions

2
.gitignore vendored Normal file
View file

@ -0,0 +1,2 @@
/target
.aoc23_cache

21
Cargo.toml Normal file
View 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
View 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
View file

@ -0,0 +1,49 @@
# Advent of Code 2024
[![About](https://img.shields.io/badge/Advent%20of%20Code-2024-brightgreen?style=flat-square)](https://adventofcode.com/2024/about)
[![Language: Rust](https://img.shields.io/badge/Language-Rust-orange.svg?style=flat-square)](https://en.wikipedia.org/wiki/Rust_(programming_language))
[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg?style=flat-square)](https://mit-license.org/)
![Days completed](https://img.shields.io/badge/Days%20completed-0-red?style=flat-square)
![Stars](https://img.shields.io/badge/Stars-0-yellow?style=flat-square)
> ⚠️ This README is copied from my previous years solution. It is not fully adopted to 2024 yet.
Last Years README:
> This is the third year in a row I (plan to) use rust to solve Advent of Code. But I must warn you: I haven't programmed a lot over the past year, so I am likely not in the best shape (School has been rough - I need a break) - expect the worst.
> Just like last year, I am lazy and currently setting this project up in a hurry (In class, actually) just so I have the basic framework once the event starts. So this project is literally a cleaned-up copy of my [solutions for the previous year](https://github.com/LeMoonStar/AoC22), which in term are a cleaned up version of my [Advent of Code 2021 solutions](https://github.com/LeMoonStar/AoC21).
> **The Following therefore still contains screenshots of the 2021 binary. The usage is the same, but the name is `aoc24` instead of `aoc21`**
>
> Later on, maybe even before AoC starts, I'll clean this up more, maybe create a crate out of the framework so I don't have to copy each year over and over again.
Well, not much changed. This is now the fourth year I'll use Rust - after not using Rust in a while and likely with a lot less time at hand. We'll see how it goes. I am finally out of school tough - that's a relief!
## Usage
There are multiple ways to run my solutions, the easiest and most comfortable one is the `auto` command:
It automatically downloads your input. For this it requires you to provide your Advent of Code session id, which you can find in the websites cookies after logging in.
Simply provide the session token by setting the `AOC_SESSION` environment variable or using the -s argument:
`AOC_SESSION=XXXMYSESSION ./aoc24 [DAY] auto` or `./aoc24 [DAY] auto -s XXXMYSESSION`.
In this example, the environment variable for the AoC session is set using `export AOC_SESSION=XXXMYSESSION`, so I can run the command without specifying the session token again:
![auto command in action](./images/auto.png)
If you don't want to automatically download the input, you can also use the `run` command, which uses a locally stored file or the stdin input:
`./aoc24 [DAY] run -f my_input.txt`:
![run command in action](./images/run.png)
If you just want to run the day's example, simply use the `test` command, as this project already includes the examples:
`./aoc24 [DAY] test`:
![test command in action](./images/test.png)
## Compiling
This project uses `Cargo`, so compiling is pretty easy:
`cargo build --release`
The resulting binary can be found at `./targets/release/aoc22`. You can also directly run the project using `cargo run --release [arguments for aoc24]`
the `--release` option is not required, but it results in better performance.
## Check out other AoC24 solutions
| Repository | Language |
|----------------------------------------------------------------------------------|----------|
| [Trojaner's AdventofCode2024](https://github.com/TrojanerHD/AdventofCode2024) | Rust |
| [Niklas' Advent-of-Code-2024](https://github.com/derNiklaas/Advent-of-Code-2024) | Kotlin |

1
aoc-macro/.gitignore vendored Normal file
View file

@ -0,0 +1 @@
/target

46
aoc-macro/Cargo.lock generated Normal file
View 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
View 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
View 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

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

BIN
images/run.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

BIN
images/test.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

32
src/days/d01.rs Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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!();

File diff suppressed because it is too large Load diff

View 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

View file

@ -0,0 +1,10 @@
467..114..
...*......
..35..633.
......#...
617*......
.....+.58.
..592.....
......755.
...$.*....
.664.598..

View 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

View 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

View file

@ -0,0 +1,2 @@
Time: 7 15 30
Distance: 9 40 200

View file

@ -0,0 +1,5 @@
32T3K 765
T55J5 684
KK677 28
KTJJT 220
QQQJA 483

View 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)

View file

@ -0,0 +1,3 @@
0 3 6 9 12 15
1 3 6 10 15 21
10 13 16 21 30 45

View 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

View file

@ -0,0 +1,10 @@
...#......
.......#..
#.........
..........
......#...
.#........
.........#
..........
.......#..
#...#.....

View file

@ -0,0 +1,6 @@
???.### 1,1,3
.??..??...?##. 1,1,3
?#?#?#?#?#?#?#? 1,3,1,6
????.#...#... 4,1,1
????.######..#####. 1,6,5
?###???????? 3,2,1

View file

@ -0,0 +1,15 @@
#.##..##.
..#.##.#.
##......#
##......#
..#.##.#.
..##..##.
#.#.##.#.
#...##..#
#....#..#
..##..###
#####.##.
#####.##.
..##..###
#....#..#

View file

@ -0,0 +1,10 @@
O....#....
O.OO#....#
.....##...
OO.#O....O
.O.....O#.
O.#..O.#.#
..O..#O..O
.......O..
#....###..
#OO..#....

View file

@ -0,0 +1 @@
rn=1,cm-,qp=3,cm=2,qp-,pc=4,ot=9,ab=5,pc-,pc=6,ot=7

View file

@ -0,0 +1,10 @@
.|...\....
|.-.\.....
.....|-...
........|.
..........
.........\
..../.\\..
.-.-/..|..
.|....-|.\
..//.|....

View file

@ -0,0 +1,13 @@
2413432311323
3215453535623
3255245654254
3446585845452
4546657867536
1438598798454
4457876987766
3637877979653
4654967986887
4564679986453
1224686865563
2546548887735
4322674655533

View 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)

View file

View file

View file

View file

View file

View file

View file

161
src/days/utils.rs Normal file
View 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
View 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
View 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.");
}
}
}
}