Parallelised the execution of each day

This commit is contained in:
Luke Else 2023-12-05 19:33:10 +00:00
parent ed05221dff
commit 43e3a8ac35
10 changed files with 125 additions and 88 deletions

View File

@ -4,7 +4,9 @@ version = "0.1.0"
edition = "2021" edition = "2021"
[dependencies] [dependencies]
async-trait = "0.1.74"
fancy-regex = "0.12.0" fancy-regex = "0.12.0"
itertools = "0.12.0" itertools = "0.12.0"
strum = "0.25.0" strum = "0.25.0"
strum_macros = "0.25.3" strum_macros = "0.25.3"
tokio = {version = "1.34.0", features = ["full"]}

View File

@ -5,8 +5,9 @@ use std::error::Error;
use solutions::*; use solutions::*;
fn main() -> Result<(), Box<dyn Error>> { #[tokio::main]
let days: Vec<Box<dyn Solution>> = vec![ async fn main() -> Result<(), Box<dyn Error>> {
let days: Vec<Box<dyn Solution + Sync>> = vec![
Box::new(day01::Day01 {}), Box::new(day01::Day01 {}),
Box::new(day02::Day02 {}), Box::new(day02::Day02 {}),
Box::new(day03::Day03 {}), Box::new(day03::Day03 {}),
@ -15,9 +16,24 @@ fn main() -> Result<(), Box<dyn Error>> {
Box::new(day06::Day06 {}), Box::new(day06::Day06 {}),
]; ];
let mut t = vec![];
// Run through and generate solutions // Run through and generate solutions
for day in days.iter().rev() { for day in days.leak().iter().rev() {
day.run()?; let task = tokio::spawn(async { day.run().unwrap() });
t.push(task);
}
let mut days = vec![];
for thread in t {
days.push(thread.await?);
}
for day in days {
println!("========= Day {} ==========", day.day);
println!("Part1 Result: {}", day.part1);
println!("Part2 Result: {}", day.part2);
println!("========= {}ms =========", day.time.as_millis());
} }
Ok(()) Ok(())

View File

@ -24,7 +24,7 @@ impl Solution for Day01 {
fn part1( fn part1(
&self, &self,
input: &mut Vec<String>, input: &mut Vec<String>,
) -> Result<Box<dyn std::fmt::Display>, Box<dyn std::error::Error>> { ) -> Result<Box<dyn std::fmt::Display + Sync>, Box<dyn std::error::Error>> {
const REG: &str = r#"[0-9]"#; const REG: &str = r#"[0-9]"#;
let mut total: u32 = 0; let mut total: u32 = 0;
for line in input { for line in input {
@ -37,7 +37,7 @@ impl Solution for Day01 {
fn part2( fn part2(
&self, &self,
input: &mut Vec<String>, input: &mut Vec<String>,
) -> Result<Box<dyn std::fmt::Display>, Box<dyn std::error::Error>> { ) -> Result<Box<dyn std::fmt::Display + Sync>, Box<dyn std::error::Error>> {
const REG: &str = r#"[0-9]|one|two|three|four|five|six|seven|eight|nine"#; const REG: &str = r#"[0-9]|one|two|three|four|five|six|seven|eight|nine"#;
let mut total: u32 = 0; let mut total: u32 = 0;
for line in input { for line in input {

View File

@ -10,7 +10,7 @@ impl Solution for Day02 {
fn part1( fn part1(
&self, &self,
input: &mut Vec<String>, input: &mut Vec<String>,
) -> Result<Box<dyn std::fmt::Display>, Box<dyn std::error::Error>> { ) -> Result<Box<dyn std::fmt::Display + Sync>, Box<dyn std::error::Error>> {
// Read games // Read games
// Parse into regex with colour to get the number of colours for each game // Parse into regex with colour to get the number of colours for each game
// Create an is Game Valid function // Create an is Game Valid function
@ -31,7 +31,7 @@ impl Solution for Day02 {
fn part2( fn part2(
&self, &self,
input: &mut Vec<String>, input: &mut Vec<String>,
) -> Result<Box<dyn std::fmt::Display>, Box<dyn std::error::Error>> { ) -> Result<Box<dyn std::fmt::Display + Sync>, Box<dyn std::error::Error>> {
let mut power = 0u32; let mut power = 0u32;
for game in input.iter().enumerate() { for game in input.iter().enumerate() {
let mut min_count: HashMap<&str, u32> = let mut min_count: HashMap<&str, u32> =

View File

@ -8,7 +8,7 @@ impl Solution for Day03 {
fn part1( fn part1(
&self, &self,
input: &mut Vec<String>, input: &mut Vec<String>,
) -> Result<Box<dyn std::fmt::Display>, Box<dyn std::error::Error>> { ) -> Result<Box<dyn std::fmt::Display + Sync>, Box<dyn std::error::Error>> {
// Get data into a byte array // Get data into a byte array
let lines = input.iter().map(|s| s.as_bytes()).collect::<Vec<_>>(); let lines = input.iter().map(|s| s.as_bytes()).collect::<Vec<_>>();
let mut symbols: HashMap<(usize, usize, char), Vec<usize>> = HashMap::new(); let mut symbols: HashMap<(usize, usize, char), Vec<usize>> = HashMap::new();
@ -23,7 +23,7 @@ impl Solution for Day03 {
fn part2( fn part2(
&self, &self,
input: &mut Vec<String>, input: &mut Vec<String>,
) -> Result<Box<dyn std::fmt::Display>, Box<dyn std::error::Error>> { ) -> Result<Box<dyn std::fmt::Display + Sync>, Box<dyn std::error::Error>> {
// Get data into a byte array // Get data into a byte array
let lines = input.iter().map(|s| s.as_bytes()).collect::<Vec<_>>(); let lines = input.iter().map(|s| s.as_bytes()).collect::<Vec<_>>();
let mut symbols: HashMap<(usize, usize, char), Vec<usize>> = HashMap::new(); let mut symbols: HashMap<(usize, usize, char), Vec<usize>> = HashMap::new();

View File

@ -1,6 +1,5 @@
use std::collections::HashMap; use std::collections::HashMap;
use super::Solution; use super::Solution;
pub struct Day04 {} pub struct Day04 {}
@ -9,7 +8,7 @@ impl Solution for Day04 {
fn part1( fn part1(
&self, &self,
input: &mut Vec<String>, input: &mut Vec<String>,
) -> Result<Box<dyn std::fmt::Display>, Box<dyn std::error::Error>> { ) -> Result<Box<dyn std::fmt::Display + Sync>, Box<dyn std::error::Error>> {
// Remove Card XXX: at start // Remove Card XXX: at start
let cards: Vec<&str> = input let cards: Vec<&str> = input
.iter() .iter()
@ -29,7 +28,7 @@ impl Solution for Day04 {
fn part2( fn part2(
&self, &self,
input: &mut Vec<String>, input: &mut Vec<String>,
) -> Result<Box<dyn std::fmt::Display>, Box<dyn std::error::Error>> { ) -> Result<Box<dyn std::fmt::Display + Sync>, Box<dyn std::error::Error>> {
// Remove Card XXX: at start and append card index // Remove Card XXX: at start and append card index
let cards: Vec<(usize, &str)> = input let cards: Vec<(usize, &str)> = input
.iter() .iter()
@ -45,7 +44,9 @@ impl Solution for Day04 {
// Check if we are looking at a winning card // Check if we are looking at a winning card
let winning_nums = self.get_count_winning_numbers(card)?; let winning_nums = self.get_count_winning_numbers(card)?;
if winning_nums == 0 { continue; } if winning_nums == 0 {
continue;
}
// We have a winning card... add the next cards resulting * num of current card // We have a winning card... add the next cards resulting * num of current card
for j in 0..winning_nums { for j in 0..winning_nums {

View File

@ -7,49 +7,63 @@ impl Solution for Day05 {
fn part1( fn part1(
&self, &self,
input: &mut Vec<String>, input: &mut Vec<String>,
) -> Result<Box<dyn std::fmt::Display>, Box<dyn std::error::Error>> { ) -> Result<Box<dyn std::fmt::Display + Sync>, Box<dyn std::error::Error>> {
let (seeds, maps) = self.get_mappings(input)?; let (seeds, maps) = self.get_mappings(input)?;
let locations = maps.iter().fold(seeds, |seeds, mappings| let locations = maps.iter().fold(seeds, |seeds, mappings| {
seeds.iter().map(|&seed| seeds
mappings.iter() .iter()
.find(|&&(_, src, range)| (src..src+range).contains(&seed)) .map(|&seed| {
.map(|(dst, src, _)| dst + seed - src) mappings
.unwrap_or(seed) .iter()
).collect() .find(|&&(_, src, range)| (src..src + range).contains(&seed))
); .map(|(dst, src, _)| dst + seed - src)
.unwrap_or(seed)
})
.collect()
});
Ok(Box::new(*locations.iter().min().unwrap())) Ok(Box::new(*locations.iter().min().unwrap()))
} }
fn part2( fn part2(
&self, &self,
input: &mut Vec<String>, input: &mut Vec<String>,
) -> Result<Box<dyn std::fmt::Display>, Box<dyn std::error::Error>> { ) -> Result<Box<dyn std::fmt::Display + Sync>, Box<dyn std::error::Error>> {
let (seeds, maps) = self.get_mappings(input)?; let (seeds, maps) = self.get_mappings(input)?;
let seeds = seeds.iter() let seeds = seeds
.iter()
.tuples() .tuples()
.map(|(&a, len)| (a, a + len)) .map(|(&a, len)| (a, a + len))
.collect::<Vec<_>>(); .collect::<Vec<_>>();
let locations = maps.iter().fold(seeds, |seeds, mappings| let locations = maps.iter().fold(seeds, |seeds, mappings| {
seeds.iter().flat_map(|&(start, end)| { seeds
let mut mapped = Vec::new(); .iter()
let mut unmapped = vec![(start, end)]; .flat_map(|&(start, end)| {
for &(dst, src, len) in mappings { let mut mapped = Vec::new();
let mut m = Vec::new(); let mut unmapped = vec![(start, end)];
for (start, end) in unmapped { for &(dst, src, len) in mappings {
let a = (start, end.min(src)); let mut m = Vec::new();
let b = (start.max(src), (src+len).min(end)); for (start, end) in unmapped {
let c = ((src+len).max(start), end); let a = (start, end.min(src));
if a.0 < a.1 { m.push(a); } let b = (start.max(src), (src + len).min(end));
if b.0 < b.1 { mapped.push((b.0-src+dst, b.1-src+dst)); } let c = ((src + len).max(start), end);
if c.0 < c.1 { m.push(c); } if a.0 < a.1 {
} m.push(a);
unmapped = m; }
} if b.0 < b.1 {
mapped.extend(unmapped); mapped.push((b.0 - src + dst, b.1 - src + dst));
mapped }
}).collect() if c.0 < c.1 {
); m.push(c);
}
}
unmapped = m;
}
mapped.extend(unmapped);
mapped
})
.collect()
});
Ok(Box::new(locations.iter().map(|&(s, _)| s).min().unwrap())) Ok(Box::new(locations.iter().map(|&(s, _)| s).min().unwrap()))
} }
@ -59,21 +73,31 @@ impl Solution for Day05 {
} }
impl Day05 { impl Day05 {
fn get_mappings(&self, input: &Vec<String>) -> Result<(Vec<usize>, Vec<Vec<(usize, usize, usize)>>), Box<dyn std::error::Error>> { fn get_mappings(
let seeds: Vec<usize> = input[0].split_whitespace() &self,
.skip(1) input: &Vec<String>,
.map(|s| s.parse().unwrap()) ) -> Result<(Vec<usize>, Vec<Vec<(usize, usize, usize)>>), Box<dyn std::error::Error>> {
.collect::<Vec<_>>(); let seeds: Vec<usize> = input[0]
.split_whitespace()
.skip(1)
.map(|s| s.parse().unwrap())
.collect::<Vec<_>>();
let maps: Vec<Vec<(usize, usize, usize)>> = input[2..input.len()].join("\n") let maps: Vec<Vec<(usize, usize, usize)>> = input[2..input.len()]
.split("\n\n").map(|s| .join("\n")
s.split('\n').skip(1).map(|l| .split("\n\n")
l.split_whitespace() .map(|s| {
.map(|s| s.parse().unwrap()) s.split('\n')
.collect_tuple() .skip(1)
.unwrap() .map(|l| {
).collect::<Vec<_>>() l.split_whitespace()
).collect::<Vec<_>>(); .map(|s| s.parse().unwrap())
.collect_tuple()
.unwrap()
})
.collect::<Vec<_>>()
})
.collect::<Vec<_>>();
Ok((seeds, maps)) Ok((seeds, maps))
} }

View File

@ -6,14 +6,14 @@ impl Solution for Day06 {
fn part1( fn part1(
&self, &self,
_input: &mut Vec<String>, _input: &mut Vec<String>,
) -> Result<Box<dyn std::fmt::Display>, Box<dyn std::error::Error>> { ) -> Result<Box<dyn std::fmt::Display + Sync>, Box<dyn std::error::Error>> {
Ok(Box::new("Ready")) Ok(Box::new("Ready"))
} }
fn part2( fn part2(
&self, &self,
_input: &mut Vec<String>, _input: &mut Vec<String>,
) -> Result<Box<dyn std::fmt::Display>, Box<dyn std::error::Error>> { ) -> Result<Box<dyn std::fmt::Display + Sync>, Box<dyn std::error::Error>> {
Ok(Box::new("Ready")) Ok(Box::new("Ready"))
} }

View File

@ -9,34 +9,27 @@ use crate::utils::{self, get_input};
use std::{error::Error, fmt::Display, time::SystemTime}; use std::{error::Error, fmt::Display, time::SystemTime};
pub trait Solution { pub trait Solution {
fn part1(&self, input: &mut Vec<String>) -> Result<Box<dyn Display>, Box<dyn Error>>; fn part1(&self, input: &mut Vec<String>) -> Result<Box<dyn Display + Sync>, Box<dyn Error>>;
fn part2(&self, input: &mut Vec<String>) -> Result<Box<dyn Display>, Box<dyn Error>>; fn part2(&self, input: &mut Vec<String>) -> Result<Box<dyn Display + Sync>, Box<dyn Error>>;
fn get_day(&self) -> u8; fn get_day(&self) -> u8;
fn run(&self) -> Result<(), Box<dyn std::error::Error>> { fn run(&self) -> Result<Run, Box<dyn std::error::Error>> {
println!("========== Day {} ==========", self.get_day());
let start_time = SystemTime::now(); let start_time = SystemTime::now();
println!( let run = Run {
"Part1 Test: {}", part1: self.part1(get_input(self.get_day(), utils::InputType::Actual)?.as_mut())?,
self.part1(get_input(self.get_day(), utils::InputType::Test1)?.as_mut())? part2: self.part2(get_input(self.get_day(), utils::InputType::Actual)?.as_mut())?,
); day: self.get_day(),
println!( time: SystemTime::now().duration_since(start_time)?,
"Part1 Result: {}", };
self.part1(get_input(self.get_day(), utils::InputType::Actual)?.as_mut())? Ok(run)
);
println!(
"Part2 Test: {}",
self.part2(get_input(self.get_day(), utils::InputType::Test2)?.as_mut())?
);
println!(
"Part2 Result: {}",
self.part2(get_input(self.get_day(), utils::InputType::Actual)?.as_mut())?
);
println!(
"========= {}ms =========",
SystemTime::now().duration_since(start_time)?.as_millis()
);
Ok(())
} }
} }
pub struct Run {
pub part1: Box<dyn Display + Sync>,
pub part2: Box<dyn Display + Sync>,
pub day: u8,
pub time: core::time::Duration,
}
unsafe impl Send for Run {}

View File

@ -5,6 +5,7 @@ use std::{
}; };
/// Enum used to specify input /// Enum used to specify input
#[allow(unused)]
pub enum InputType { pub enum InputType {
Test1, Test1,
Test2, Test2,