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"
[dependencies]
async-trait = "0.1.74"
fancy-regex = "0.12.0"
itertools = "0.12.0"
strum = "0.25.0"
strum_macros = "0.25.3"
tokio = {version = "1.34.0", features = ["full"]}

View File

@ -5,8 +5,9 @@ use std::error::Error;
use solutions::*;
fn main() -> Result<(), Box<dyn Error>> {
let days: Vec<Box<dyn Solution>> = vec![
#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
let days: Vec<Box<dyn Solution + Sync>> = vec![
Box::new(day01::Day01 {}),
Box::new(day02::Day02 {}),
Box::new(day03::Day03 {}),
@ -15,9 +16,24 @@ fn main() -> Result<(), Box<dyn Error>> {
Box::new(day06::Day06 {}),
];
let mut t = vec![];
// Run through and generate solutions
for day in days.iter().rev() {
day.run()?;
for day in days.leak().iter().rev() {
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(())

View File

@ -24,7 +24,7 @@ impl Solution for Day01 {
fn part1(
&self,
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]"#;
let mut total: u32 = 0;
for line in input {
@ -37,7 +37,7 @@ impl Solution for Day01 {
fn part2(
&self,
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"#;
let mut total: u32 = 0;
for line in input {

View File

@ -10,7 +10,7 @@ impl Solution for Day02 {
fn part1(
&self,
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
// Parse into regex with colour to get the number of colours for each game
// Create an is Game Valid function
@ -31,7 +31,7 @@ impl Solution for Day02 {
fn part2(
&self,
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;
for game in input.iter().enumerate() {
let mut min_count: HashMap<&str, u32> =

View File

@ -8,7 +8,7 @@ impl Solution for Day03 {
fn part1(
&self,
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
let lines = input.iter().map(|s| s.as_bytes()).collect::<Vec<_>>();
let mut symbols: HashMap<(usize, usize, char), Vec<usize>> = HashMap::new();
@ -23,7 +23,7 @@ impl Solution for Day03 {
fn part2(
&self,
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
let lines = input.iter().map(|s| s.as_bytes()).collect::<Vec<_>>();
let mut symbols: HashMap<(usize, usize, char), Vec<usize>> = HashMap::new();

View File

@ -1,6 +1,5 @@
use std::collections::HashMap;
use super::Solution;
pub struct Day04 {}
@ -9,7 +8,7 @@ impl Solution for Day04 {
fn part1(
&self,
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
let cards: Vec<&str> = input
.iter()
@ -29,7 +28,7 @@ impl Solution for Day04 {
fn part2(
&self,
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
let cards: Vec<(usize, &str)> = input
.iter()
@ -45,7 +44,9 @@ impl Solution for Day04 {
// Check if we are looking at a winning 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
for j in 0..winning_nums {

View File

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

View File

@ -6,14 +6,14 @@ impl Solution for Day06 {
fn part1(
&self,
_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"))
}
fn part2(
&self,
_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"))
}

View File

@ -9,34 +9,27 @@ use crate::utils::{self, get_input};
use std::{error::Error, fmt::Display, time::SystemTime};
pub trait Solution {
fn part1(&self, input: &mut Vec<String>) -> Result<Box<dyn Display>, Box<dyn Error>>;
fn part2(&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 + Sync>, Box<dyn Error>>;
fn get_day(&self) -> u8;
fn run(&self) -> Result<(), Box<dyn std::error::Error>> {
println!("========== Day {} ==========", self.get_day());
fn run(&self) -> Result<Run, Box<dyn std::error::Error>> {
let start_time = SystemTime::now();
println!(
"Part1 Test: {}",
self.part1(get_input(self.get_day(), utils::InputType::Test1)?.as_mut())?
);
println!(
"Part1 Result: {}",
self.part1(get_input(self.get_day(), utils::InputType::Actual)?.as_mut())?
);
let run = Run {
part1: self.part1(get_input(self.get_day(), utils::InputType::Actual)?.as_mut())?,
part2: self.part2(get_input(self.get_day(), utils::InputType::Actual)?.as_mut())?,
day: self.get_day(),
time: SystemTime::now().duration_since(start_time)?,
};
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
#[allow(unused)]
pub enum InputType {
Test1,
Test2,