Day 3 + I formatted everything by accident lol

This commit is contained in:
Tyler Beckman 2023-12-03 00:27:13 -07:00
parent a852107c7f
commit bd64157702
Signed by: Ty
GPG key ID: 2813440C772555A4
5 changed files with 268 additions and 75 deletions

View file

@ -2,7 +2,7 @@ use crate::utils::Day;
#[derive(Debug, Default)] #[derive(Debug, Default)]
pub struct Day1 { pub struct Day1 {
pub input: String pub input: String,
} }
impl Day for Day1 { impl Day for Day1 {
@ -10,12 +10,20 @@ impl Day for Day1 {
let mut values = Vec::<usize>::new(); let mut values = Vec::<usize>::new();
for line in self.input.lines() { for line in self.input.lines() {
let digits = line.chars().filter(|char| char.is_numeric()).collect::<Vec<_>>(); let digits = line
let calibrartion_value = format!("{}{}", digits.first().unwrap(), digits.last().unwrap()); .chars()
.filter(|char| char.is_numeric())
.collect::<Vec<_>>();
let calibrartion_value =
format!("{}{}", digits.first().unwrap(), digits.last().unwrap());
values.push(calibrartion_value.parse().unwrap()); values.push(calibrartion_value.parse().unwrap());
} }
return values.into_iter().reduce(|acc, e| acc + e).unwrap().to_string(); return values
.into_iter()
.reduce(|acc, e| acc + e)
.unwrap()
.to_string();
} }
fn part2(&mut self) -> String { fn part2(&mut self) -> String {
@ -44,7 +52,8 @@ impl Day for Day1 {
line.match_indices("7").collect::<Vec<_>>(), line.match_indices("7").collect::<Vec<_>>(),
line.match_indices("8").collect::<Vec<_>>(), line.match_indices("8").collect::<Vec<_>>(),
line.match_indices("9").collect::<Vec<_>>(), line.match_indices("9").collect::<Vec<_>>(),
].into_iter(); ]
.into_iter();
let mut flat = Vec::<(usize, String)>::new(); let mut flat = Vec::<(usize, String)>::new();
for digit in digits { for digit in digits {
@ -66,10 +75,15 @@ impl Day for Day1 {
} }
flat.sort_by(|a, b| a.0.cmp(&b.0)); flat.sort_by(|a, b| a.0.cmp(&b.0));
let calibration_value = format!("{}{}", flat.first().unwrap().1, flat.last().unwrap().1); let calibration_value =
format!("{}{}", flat.first().unwrap().1, flat.last().unwrap().1);
values.push(calibration_value.parse().unwrap()); values.push(calibration_value.parse().unwrap());
} }
return values.into_iter().reduce(|acc, e| acc + e).unwrap().to_string(); return values
.into_iter()
.reduce(|acc, e| acc + e)
.unwrap()
.to_string();
} }
} }

View file

@ -5,20 +5,20 @@ use crate::utils::Day;
#[derive(Debug, Default)] #[derive(Debug, Default)]
pub struct Day2 { pub struct Day2 {
pub input: String, pub input: String,
pub games: Vec<Game> pub games: Vec<Game>,
} }
#[derive(Debug)] #[derive(Debug)]
pub struct Game { pub struct Game {
id: usize, id: usize,
picks: Vec<CubeCombo> picks: Vec<CubeCombo>,
} }
#[derive(Debug)] #[derive(Debug)]
struct CubeCombo { struct CubeCombo {
red: usize, red: usize,
blue: usize, blue: usize,
green: usize green: usize,
} }
impl Day for Day2 { impl Day for Day2 {
@ -33,7 +33,7 @@ impl Day for Day2 {
let captures = game_re.captures(&line).unwrap(); let captures = game_re.captures(&line).unwrap();
let mut game = Game { let mut game = Game {
id: captures.get(1).unwrap().as_str().parse().unwrap(), id: captures.get(1).unwrap().as_str().parse().unwrap(),
picks: vec![] picks: vec![],
}; };
let picks = captures.get(2).unwrap().as_str().split("; "); let picks = captures.get(2).unwrap().as_str().split("; ");
for pick in picks { for pick in picks {
@ -46,7 +46,7 @@ impl Day for Day2 {
let mut pick = CubeCombo { let mut pick = CubeCombo {
red: 0, red: 0,
blue: 0, blue: 0,
green: 0 green: 0,
}; };
for capture in captures.iter().filter(|e| e.is_some()).map(|e| e.unwrap()) { for capture in captures.iter().filter(|e| e.is_some()).map(|e| e.unwrap()) {
@ -55,7 +55,7 @@ impl Day for Day2 {
"red" => pick.red = split[0].parse().unwrap(), "red" => pick.red = split[0].parse().unwrap(),
"blue" => pick.blue = split[0].parse().unwrap(), "blue" => pick.blue = split[0].parse().unwrap(),
"green" => pick.green = split[0].parse().unwrap(), "green" => pick.green = split[0].parse().unwrap(),
_ => panic!("impossible wtf") _ => panic!("impossible wtf"),
} }
} }
@ -68,11 +68,14 @@ impl Day for Day2 {
fn part1(&mut self) -> String { fn part1(&mut self) -> String {
// Sum the illegal game IDs // Sum the illegal game IDs
let sum = self.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);
sum.to_string() sum.to_string()
@ -80,27 +83,31 @@ impl Day for Day2 {
fn part2(&mut self) -> String { 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 = self.games.iter().map(|game| { let sum = self
let mut combo = CubeCombo { .games
red: 0, .iter()
green: 0, .map(|game| {
blue: 0 let mut combo = CubeCombo {
}; red: 0,
green: 0,
blue: 0,
};
for pick in &game.picks { for pick in &game.picks {
if combo.red < pick.red { if combo.red < pick.red {
combo.red = pick.red; combo.red = pick.red;
}
if combo.green < pick.green {
combo.green = pick.green;
}
if combo.blue < pick.blue {
combo.blue = pick.blue;
}
} }
if combo.green < pick.green {
combo.green = pick.green;
}
if combo.blue < pick.blue {
combo.blue = pick.blue;
}
}
combo combo
}).fold(0, |acc, combo| acc + (combo.red * combo.blue * combo.green)); })
.fold(0, |acc, combo| acc + (combo.red * combo.blue * combo.green));
sum.to_string() sum.to_string()
} }

155
src/day3/mod.rs Normal file
View file

@ -0,0 +1,155 @@
use std::collections::HashMap;
use regex::Regex;
use crate::utils::Day;
#[derive(Debug)]
pub struct Day3 {
pub input: String,
}
impl Day for Day3 {
fn part1(&mut self) -> String {
let number_re = Regex::new(r"\d+").unwrap();
let line_length = self.input.split('\n').next().unwrap().len() + 1;
let mut valid = Vec::<usize>::new();
for number in number_re.find_iter(&self.input) {
let mut checks = vec![];
if number.start() % line_length != 0 {
checks.push(number.start() - 1)
}
checks.push(number.end());
checks.append(
&mut ((number.start().checked_sub(1).unwrap_or(number.start()))..=(number.end()))
.flat_map(|i| {
let mut checks = vec![];
if number.start() / line_length != 0 {
checks.push(i - line_length)
}
if number.start() / line_length != self.input.len() / line_length {
checks.push(i + line_length)
}
checks
})
.collect::<Vec<_>>(),
);
for check in checks {
if self
.input
.chars()
.nth(check)
.is_some_and(|character| character != '.' && character.is_ascii_punctuation())
{
valid.push(number.as_str().parse().unwrap());
break;
}
}
}
valid.iter().sum::<usize>().to_string()
}
fn part2(&mut self) -> String {
let number_re = Regex::new(r"\d+").unwrap();
let line_length = self.input.split('\n').next().unwrap().len() + 1;
let mut valid /* (number, gear_index) */ = Vec::<(usize, usize)>::new();
for number in number_re.find_iter(&self.input) {
let mut checks = vec![];
if number.start() % line_length != 0 {
checks.push(number.start() - 1)
}
checks.push(number.end());
checks.append(
&mut ((number.start().checked_sub(1).unwrap_or(number.start()))..=(number.end()))
.flat_map(|i| {
let mut checks = vec![];
if number.start() / line_length != 0 {
checks.push(i - line_length)
}
if number.start() / line_length != self.input.len() / line_length {
checks.push(i + line_length)
}
checks
})
.collect::<Vec<_>>(),
);
for check in checks {
if self
.input
.chars()
.nth(check)
.is_some_and(|character| character == '*')
{
valid.push((number.as_str().parse().unwrap(), check));
break;
}
}
}
let mut gear_map = HashMap::<usize, Vec<usize>>::new();
for (number, gear_index) in valid {
match gear_map.get_mut(&gear_index) {
Some(value) => value.push(number),
None => {
gear_map.insert(gear_index, vec![number]);
}
}
}
gear_map
.iter()
.map(|(_, numbers)| match numbers.len() {
2 => numbers[0] * numbers[1],
_ => 0,
})
.sum::<usize>()
.to_string()
}
}
#[cfg(test)]
mod tests {
use crate::{day3::Day3, utils::Day};
#[test]
fn passes_example_1() {
dbg!(Day3 {
input: r#"467..114..
...*......
..35..633.
......#...
617*......
.....+.58.
..592.....
......755.
...$.*....
.664.598.."#
.to_string(),
}
.solve(1));
}
#[test]
fn passes_example_2() {
dbg!(Day3 {
input: r#"467..114..
...*......
..35..633.
......#...
617*......
.....+.58.
..592.....
......755.
...$.*....
.664.598..
"#
.to_string(),
}
.solve(2));
}
}

View file

@ -1,12 +1,16 @@
use std::{io::Write, time::{Duration, Instant}}; use std::{
io::Write,
time::{Duration, Instant},
};
use clap::{Parser, Subcommand}; use clap::{Parser, Subcommand};
use crate::{day1::Day1, day2::Day2, utils::Day}; use crate::{day1::Day1, day2::Day2, day3::Day3, utils::Day};
pub mod utils;
pub mod day1; pub mod day1;
pub mod day2; pub mod day2;
pub mod day3;
pub mod utils;
#[derive(Parser)] #[derive(Parser)]
#[command(author, version, about, long_about = None)] #[command(author, version, about, long_about = None)]
@ -16,7 +20,7 @@ struct Cli {
auth: String, auth: String,
/// The subcommand to run /// The subcommand to run
#[command(subcommand)] #[command(subcommand)]
subcommand: Subcommands subcommand: Subcommands,
} }
#[derive(Subcommand)] #[derive(Subcommand)]
@ -26,7 +30,7 @@ enum Subcommands {
/// The day to solve for /// The day to solve for
day: u8, day: u8,
/// The part to solve for /// The part to solve for
part: u8 part: u8,
}, },
/// Runs solution N amount of times, averaging speed /// Runs solution N amount of times, averaging speed
Benchmark { Benchmark {
@ -37,13 +41,13 @@ enum Subcommands {
/// The amount of times to run before actually keeping track /// The amount of times to run before actually keeping track
warmup: u32, warmup: u32,
/// The amount of times to run /// The amount of times to run
n: u32 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
day: u8 day: u8,
} },
} }
#[tokio::main] #[tokio::main]
@ -67,16 +71,25 @@ async fn main() {
let mut day: Box<dyn Day> = match day { let mut day: Box<dyn Day> = match day {
1 => Box::new(Day1 { input: response }), 1 => Box::new(Day1 { input: response }),
2 => Box::new(Day2 { input: response, games: vec![] }), 2 => Box::new(Day2 {
_ => panic!("Invalid day or part #") input: response,
games: vec![],
}),
3 => Box::new(Day3 { input: response }),
_ => panic!("Invalid day #"),
}; };
let start = std::time::Instant::now(); let start = std::time::Instant::now();
let result = day.solve(part); let result = day.solve(part);
let end = std::time::Instant::now(); let end = std::time::Instant::now();
println!("Solution: {result}"); println!("Solution: {result}");
println!("Solved in {}ns", (end - start).as_nanos() as f64 / 1000.0); println!("Solved in {}ns", (end - start).as_nanos() as f64 / 1000.0);
}, }
Subcommands::Benchmark { day, part, warmup, n } => { Subcommands::Benchmark {
day,
part,
warmup,
n,
} => {
let response = client let response = client
.get(format!("https://adventofcode.com/2023/day/{day}/input")) .get(format!("https://adventofcode.com/2023/day/{day}/input"))
.header("Cookie", format!("session={auth}", auth = cli.auth)) .header("Cookie", format!("session={auth}", auth = cli.auth))
@ -91,8 +104,12 @@ async fn main() {
let mut day: Box<dyn Day> = match day { let mut day: Box<dyn Day> = match day {
1 => Box::new(Day1 { input: response }), 1 => Box::new(Day1 { input: response }),
2 => Box::new(Day2 { input: response, games: vec![] }), 2 => Box::new(Day2 {
_ => panic!("Invalid day #") input: response,
games: vec![],
}),
3 => Box::new(Day3 { input: response }),
_ => panic!("Invalid day #"),
}; };
let mut timings = Vec::<Duration>::new(); let mut timings = Vec::<Duration>::new();
for _ in 1..warmup { for _ in 1..warmup {
@ -111,7 +128,7 @@ async fn main() {
} }
let avg = timings.into_iter().sum::<Duration>() / n; let avg = timings.into_iter().sum::<Duration>() / n;
println!("\nAverage timing: {}µs", avg.as_nanos() as f64 / 1000.0); println!("\nAverage timing: {}µs", avg.as_nanos() as f64 / 1000.0);
}, }
Subcommands::Input { day } => { Subcommands::Input { day } => {
let response = client let response = client
.get(format!("https://adventofcode.com/2023/day/{day}/input")) .get(format!("https://adventofcode.com/2023/day/{day}/input"))
@ -126,6 +143,6 @@ async fn main() {
.to_owned(); .to_owned();
println!("{response}"); println!("{response}");
}, }
} }
} }

View file

@ -1,13 +1,13 @@
pub trait Day: std::fmt::Debug { pub trait Day: std::fmt::Debug {
fn part1(&mut self) -> String; fn part1(&mut self) -> String;
fn part2(&mut self) -> String; fn part2(&mut self) -> String;
fn parse(&mut self) { } fn parse(&mut self) {}
fn solve(&mut self, part: u8) -> String { fn solve(&mut self, part: u8) -> String {
self.parse(); self.parse();
match part { match part {
1 => self.part1(), 1 => self.part1(),
2 => self.part2(), 2 => self.part2(),
_ => panic!("Invalid part #") _ => panic!("Invalid part #"),
} }
} }
} }