I love overcomplicating an advent calendar
This commit is contained in:
parent
19af7422b2
commit
a852107c7f
4 changed files with 222 additions and 147 deletions
|
@ -1,19 +1,27 @@
|
||||||
pub fn part1(input: String) {
|
use crate::utils::Day;
|
||||||
|
|
||||||
|
#[derive(Debug, Default)]
|
||||||
|
pub struct Day1 {
|
||||||
|
pub input: String
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Day for Day1 {
|
||||||
|
fn part1(&mut self) -> String {
|
||||||
let mut values = Vec::<usize>::new();
|
let mut values = Vec::<usize>::new();
|
||||||
|
|
||||||
for line in input.lines() {
|
for line in self.input.lines() {
|
||||||
let digits = line.chars().filter(|char| char.is_numeric()).collect::<Vec<_>>();
|
let digits = line.chars().filter(|char| char.is_numeric()).collect::<Vec<_>>();
|
||||||
let calibrartion_value = format!("{}{}", digits.first().unwrap(), digits.last().unwrap());
|
let calibrartion_value = format!("{}{}", digits.first().unwrap(), digits.last().unwrap());
|
||||||
values.push(calibrartion_value.parse().unwrap());
|
values.push(calibrartion_value.parse().unwrap());
|
||||||
}
|
}
|
||||||
|
|
||||||
println!("{}", values.into_iter().reduce(|acc, e| acc + e).unwrap());
|
return values.into_iter().reduce(|acc, e| acc + e).unwrap().to_string();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn part2(input: String) {
|
fn part2(&mut self) -> String {
|
||||||
let mut values = Vec::<usize>::new();
|
let mut values = Vec::<usize>::new();
|
||||||
|
|
||||||
for line in input.lines() {
|
for line in self.input.lines() {
|
||||||
let line = line.to_owned();
|
let line = line.to_owned();
|
||||||
|
|
||||||
// Find instances of number words and choose the closest, recursively replacing (Can't just .replace b/c of shit like "twone")
|
// Find instances of number words and choose the closest, recursively replacing (Can't just .replace b/c of shit like "twone")
|
||||||
|
@ -62,5 +70,6 @@ pub fn part2(input: String) {
|
||||||
values.push(calibration_value.parse().unwrap());
|
values.push(calibration_value.parse().unwrap());
|
||||||
}
|
}
|
||||||
|
|
||||||
println!("{}", values.into_iter().reduce(|acc, e| acc + e).unwrap());
|
return values.into_iter().reduce(|acc, e| acc + e).unwrap().to_string();
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -1,7 +1,15 @@
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
|
|
||||||
|
use crate::utils::Day;
|
||||||
|
|
||||||
|
#[derive(Debug, Default)]
|
||||||
|
pub struct Day2 {
|
||||||
|
pub input: String,
|
||||||
|
pub games: Vec<Game>
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct Game {
|
pub struct Game {
|
||||||
id: usize,
|
id: usize,
|
||||||
picks: Vec<CubeCombo>
|
picks: Vec<CubeCombo>
|
||||||
}
|
}
|
||||||
|
@ -13,12 +21,14 @@ struct CubeCombo {
|
||||||
green: usize
|
green: usize
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_games(input: String) -> Vec<Game> {
|
impl Day for Day2 {
|
||||||
|
fn parse(&mut self) {
|
||||||
|
self.games.clear();
|
||||||
|
|
||||||
let game_re = Regex::new(r"Game (\d+): (.+)").unwrap();
|
let game_re = Regex::new(r"Game (\d+): (.+)").unwrap();
|
||||||
let pick_re = Regex::new(r"(?<first>\d+ (?:red|green|blue))(?:, (?<second>\d+ (?:red|green|blue)))?(?:, (?<third>\d+ (?:red|green|blue)))?").unwrap();
|
let pick_re = Regex::new(r"(?<first>\d+ (?:red|green|blue))(?:, (?<second>\d+ (?:red|green|blue)))?(?:, (?<third>\d+ (?:red|green|blue)))?").unwrap();
|
||||||
let mut games = Vec::<Game>::new();
|
|
||||||
|
|
||||||
for line in input.lines() {
|
for line in self.input.lines() {
|
||||||
let line = line.to_string();
|
let line = line.to_string();
|
||||||
let captures = game_re.captures(&line).unwrap();
|
let captures = game_re.captures(&line).unwrap();
|
||||||
let mut game = Game {
|
let mut game = Game {
|
||||||
|
@ -51,30 +61,26 @@ fn parse_games(input: String) -> Vec<Game> {
|
||||||
|
|
||||||
game.picks.push(pick);
|
game.picks.push(pick);
|
||||||
}
|
}
|
||||||
games.push(game);
|
|
||||||
|
self.games.push(game);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
games
|
fn part1(&mut self) -> String {
|
||||||
}
|
|
||||||
|
|
||||||
pub fn part1(input: String) {
|
|
||||||
let games = parse_games(input);
|
|
||||||
|
|
||||||
// Sum the illegal game IDs
|
// Sum the illegal game IDs
|
||||||
let sum = games
|
let sum = self.games
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|g|
|
.filter(|g|
|
||||||
g.picks.iter().all(|pick| pick.red <= 12 && pick.blue <= 14 && pick.green <= 13 )
|
g.picks.iter().all(|pick| pick.red <= 12 && pick.blue <= 14 && pick.green <= 13 )
|
||||||
)
|
)
|
||||||
.fold(0, |acc, e| acc + e.id);
|
.fold(0, |acc, e| acc + e.id);
|
||||||
println!("{sum}");
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn part2(input: String) {
|
sum.to_string()
|
||||||
let games = parse_games(input);
|
}
|
||||||
|
|
||||||
|
fn part2(&mut self) -> String {
|
||||||
// Calculate the least amount of dice possible for all games
|
// Calculate the least amount of dice possible for all games
|
||||||
let sum = games.iter().map(|game| {
|
let sum = self.games.iter().map(|game| {
|
||||||
let mut combo = CubeCombo {
|
let mut combo = CubeCombo {
|
||||||
red: 0,
|
red: 0,
|
||||||
green: 0,
|
green: 0,
|
||||||
|
@ -96,5 +102,6 @@ pub fn part2(input: String) {
|
||||||
combo
|
combo
|
||||||
}).fold(0, |acc, combo| acc + (combo.red * combo.blue * combo.green));
|
}).fold(0, |acc, combo| acc + (combo.red * combo.blue * combo.green));
|
||||||
|
|
||||||
println!("{sum}");
|
sum.to_string()
|
||||||
|
}
|
||||||
}
|
}
|
64
src/main.rs
64
src/main.rs
|
@ -1,5 +1,9 @@
|
||||||
|
use std::{io::Write, time::{Duration, Instant}};
|
||||||
|
|
||||||
use clap::{Parser, Subcommand};
|
use clap::{Parser, Subcommand};
|
||||||
|
|
||||||
|
use crate::{day1::Day1, day2::Day2, utils::Day};
|
||||||
|
|
||||||
pub mod utils;
|
pub mod utils;
|
||||||
pub mod day1;
|
pub mod day1;
|
||||||
pub mod day2;
|
pub mod day2;
|
||||||
|
@ -24,6 +28,17 @@ enum Subcommands {
|
||||||
/// The part to solve for
|
/// The part to solve for
|
||||||
part: u8
|
part: u8
|
||||||
},
|
},
|
||||||
|
/// Runs solution N amount of times, averaging speed
|
||||||
|
Benchmark {
|
||||||
|
/// The day to solve for
|
||||||
|
day: u8,
|
||||||
|
/// The part to solve for
|
||||||
|
part: u8,
|
||||||
|
/// The amount of times to run before actually keeping track
|
||||||
|
warmup: u32,
|
||||||
|
/// The amount of times to run
|
||||||
|
n: u32
|
||||||
|
},
|
||||||
/// Fetches and prints the given input for a specified day
|
/// Fetches and prints the given input for a specified day
|
||||||
Input {
|
Input {
|
||||||
/// The day to fetch
|
/// The day to fetch
|
||||||
|
@ -50,13 +65,52 @@ async fn main() {
|
||||||
.trim_end()
|
.trim_end()
|
||||||
.to_owned();
|
.to_owned();
|
||||||
|
|
||||||
match (day, part) {
|
let mut day: Box<dyn Day> = match day {
|
||||||
(1, 1) => day1::part1(response),
|
1 => Box::new(Day1 { input: response }),
|
||||||
(1, 2) => day1::part2(response),
|
2 => Box::new(Day2 { input: response, games: vec![] }),
|
||||||
(2, 1) => day2::part1(response),
|
|
||||||
(2, 2) => day2::part2(response),
|
|
||||||
_ => panic!("Invalid day or part #")
|
_ => panic!("Invalid day or part #")
|
||||||
|
};
|
||||||
|
let start = std::time::Instant::now();
|
||||||
|
let result = day.solve(part);
|
||||||
|
let end = std::time::Instant::now();
|
||||||
|
println!("Solution: {result}");
|
||||||
|
println!("Solved in {}ns", (end - start).as_nanos() as f64 / 1000.0);
|
||||||
|
},
|
||||||
|
Subcommands::Benchmark { day, part, warmup, n } => {
|
||||||
|
let response = client
|
||||||
|
.get(format!("https://adventofcode.com/2023/day/{day}/input"))
|
||||||
|
.header("Cookie", format!("session={auth}", auth = cli.auth))
|
||||||
|
.send()
|
||||||
|
.await
|
||||||
|
.unwrap()
|
||||||
|
.text()
|
||||||
|
.await
|
||||||
|
.unwrap()
|
||||||
|
.trim_end()
|
||||||
|
.to_owned();
|
||||||
|
|
||||||
|
let mut day: Box<dyn Day> = match day {
|
||||||
|
1 => Box::new(Day1 { input: response }),
|
||||||
|
2 => Box::new(Day2 { input: response, games: vec![] }),
|
||||||
|
_ => panic!("Invalid day #")
|
||||||
|
};
|
||||||
|
let mut timings = Vec::<Duration>::new();
|
||||||
|
for _ in 1..warmup {
|
||||||
|
day.solve(part);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for i in 1..=n {
|
||||||
|
let start = Instant::now();
|
||||||
|
day.solve(part);
|
||||||
|
let end = Instant::now();
|
||||||
|
timings.push(end - start);
|
||||||
|
if i % (n / 100) == 0 {
|
||||||
|
print!("\r{}%", ((i as f32 / n as f32) * 100.0).round());
|
||||||
|
let _ = std::io::stdout().flush();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let avg = timings.into_iter().sum::<Duration>() / n;
|
||||||
|
println!("\nAverage timing: {}µs", avg.as_nanos() as f64 / 1000.0);
|
||||||
},
|
},
|
||||||
Subcommands::Input { day } => {
|
Subcommands::Input { day } => {
|
||||||
let response = client
|
let response = client
|
||||||
|
|
19
src/utils.rs
19
src/utils.rs
|
@ -1,8 +1,13 @@
|
||||||
pub enum CoroutineYield {
|
pub trait Day: std::fmt::Debug {
|
||||||
Data,
|
fn part1(&mut self) -> String;
|
||||||
Output(String)
|
fn part2(&mut self) -> String;
|
||||||
}
|
fn parse(&mut self) { }
|
||||||
|
fn solve(&mut self, part: u8) -> String {
|
||||||
pub enum CoroutineYieldResponse {
|
self.parse();
|
||||||
Data(String),
|
match part {
|
||||||
|
1 => self.part1(),
|
||||||
|
2 => self.part2(),
|
||||||
|
_ => panic!("Invalid part #")
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
Loading…
Reference in a new issue