feat: initial commit

This commit is contained in:
uku 2024-12-01 13:19:29 +01:00
commit 0279c63a39
Signed by: uku
SSH key fingerprint: SHA256:4P0aN6M8ajKukNi6aPOaX0LacanGYtlfjmN+m/sHY/o
10 changed files with 817 additions and 0 deletions

53
src/common/answer.rs Normal file
View file

@ -0,0 +1,53 @@
use std::fmt::{self, Display};
#[derive(Debug, PartialEq)]
pub enum Answer {
String(String),
Number(u64),
Float(f64),
#[allow(unused)]
Unimplemented,
}
impl Display for Answer {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Answer::String(s) => write!(f, "{s}"),
Answer::Number(n) => write!(f, "{n}"),
Answer::Float(n) => write!(f, "{n}"),
Answer::Unimplemented => write!(f, "Unimplemented"),
}
}
}
impl From<String> for Answer {
fn from(s: String) -> Self {
Self::String(s)
}
}
impl From<&str> for Answer {
fn from(s: &str) -> Self {
Self::String(s.to_string())
}
}
macro_rules! answer_impl {
($answer:ident, $answer_type:ty, { $($type:ty),* }) => {
$(impl From<$type> for Answer {
fn from(n: $type) -> Self {
Self::$answer(n as $answer_type)
}
})*
};
}
answer_impl!(
Number, u64,
{ u8, u16, u32, u64, usize, i8, i16, i32, i64, isize }
);
answer_impl!(
Float, f64,
{ f32, f64 }
);

6
src/common/mod.rs Normal file
View file

@ -0,0 +1,6 @@
// heavily inspired by Basicprogrammer10/advent-of-code
mod answer;
mod solution;
pub use answer::Answer;
pub use solution::Solution;

7
src/common/solution.rs Normal file
View file

@ -0,0 +1,7 @@
use super::Answer;
pub trait Solution {
fn name(&self) -> &'static str;
fn part_a(&self, input: &str) -> Answer;
fn part_b(&self, input: &str) -> Answer;
}

73
src/main.rs Normal file
View file

@ -0,0 +1,73 @@
use std::time::Instant;
mod common;
mod solutions;
fn main() {
if let Err(e) = dotenvy::dotenv() {
eprintln!("Could not load .env: {e}");
}
let args = std::env::args().collect::<Vec<_>>();
let day = args
.get(1)
.and_then(|n| n.parse::<u8>().ok())
.expect("day is not a number");
let part = args
.get(2)
.and_then(|n| n.chars().next())
.expect("part is not a letter");
let Some(solution) = solutions::SOLUTIONS.get((day - 1) as usize) else {
eprintln!("[-] Day {} not implemented", day);
return;
};
let input = load(day).unwrap();
println!(
"[*] Running: {} ({}-{})",
solution.name(),
day,
part.to_uppercase()
);
let start = Instant::now();
let out = match part.to_ascii_lowercase() {
'a' => solution.part_a(&input),
'b' => solution.part_b(&input),
_ => return eprintln!("[-] Invalid Part {}", part),
};
let time = start.elapsed().as_nanos();
println!("[*] Out: {} (took {})", out, format_time(time));
}
fn load(day: u8) -> Result<String, Box<dyn std::error::Error>> {
let token = std::env::var("TOKEN").expect("TOKEN is not set");
Ok(
ureq::get(format!("https://adventofcode.com/2024/day/{day}/input").as_str())
.set("Cookie", format!("session={token}").as_str())
.call()?
.into_string()?
.trim()
.replace('\r', ""),
)
}
fn format_time(nanos: u128) -> String {
const TIME_UNITS: &[&str] = &["ns", "μs", "ms", "s"];
let mut time = nanos;
for i in TIME_UNITS {
if time < 1000 {
return format!("{}{}", time, i);
}
time /= 1000;
}
format!("{}{}", time, TIME_UNITS.last().unwrap())
}

3
src/solutions/mod.rs Normal file
View file

@ -0,0 +1,3 @@
use crate::common::Solution;
pub const SOLUTIONS: &[&dyn Solution] = &[];