From 43e3a8ac3542943ae3c6ebb8096a2ba98626c4c8 Mon Sep 17 00:00:00 2001 From: Luke Else Date: Tue, 5 Dec 2023 19:33:10 +0000 Subject: [PATCH] Parallelised the execution of each day --- Cargo.toml | 2 + src/main.rs | 24 +++++++-- src/solutions/day01.rs | 4 +- src/solutions/day02.rs | 4 +- src/solutions/day03.rs | 4 +- src/solutions/day04.rs | 11 ++-- src/solutions/day05.rs | 114 +++++++++++++++++++++++++---------------- src/solutions/day06.rs | 4 +- src/solutions/mod.rs | 45 +++++++--------- src/utils.rs | 1 + 10 files changed, 125 insertions(+), 88 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 6cc7d0a..68dd5f6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -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"]} diff --git a/src/main.rs b/src/main.rs index c15e369..3f4680a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -5,8 +5,9 @@ use std::error::Error; use solutions::*; -fn main() -> Result<(), Box> { - let days: Vec> = vec![ +#[tokio::main] +async fn main() -> Result<(), Box> { + let days: Vec> = vec![ Box::new(day01::Day01 {}), Box::new(day02::Day02 {}), Box::new(day03::Day03 {}), @@ -15,9 +16,24 @@ fn main() -> Result<(), Box> { 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(()) diff --git a/src/solutions/day01.rs b/src/solutions/day01.rs index 1a045ff..1ebbf51 100644 --- a/src/solutions/day01.rs +++ b/src/solutions/day01.rs @@ -24,7 +24,7 @@ impl Solution for Day01 { fn part1( &self, input: &mut Vec, - ) -> Result, Box> { + ) -> Result, Box> { 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, - ) -> Result, Box> { + ) -> Result, Box> { const REG: &str = r#"[0-9]|one|two|three|four|five|six|seven|eight|nine"#; let mut total: u32 = 0; for line in input { diff --git a/src/solutions/day02.rs b/src/solutions/day02.rs index ff5af89..2813bd3 100644 --- a/src/solutions/day02.rs +++ b/src/solutions/day02.rs @@ -10,7 +10,7 @@ impl Solution for Day02 { fn part1( &self, input: &mut Vec, - ) -> Result, Box> { + ) -> Result, Box> { // 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, - ) -> Result, Box> { + ) -> Result, Box> { let mut power = 0u32; for game in input.iter().enumerate() { let mut min_count: HashMap<&str, u32> = diff --git a/src/solutions/day03.rs b/src/solutions/day03.rs index dd10a45..7ef8707 100644 --- a/src/solutions/day03.rs +++ b/src/solutions/day03.rs @@ -8,7 +8,7 @@ impl Solution for Day03 { fn part1( &self, input: &mut Vec, - ) -> Result, Box> { + ) -> Result, Box> { // Get data into a byte array let lines = input.iter().map(|s| s.as_bytes()).collect::>(); let mut symbols: HashMap<(usize, usize, char), Vec> = HashMap::new(); @@ -23,7 +23,7 @@ impl Solution for Day03 { fn part2( &self, input: &mut Vec, - ) -> Result, Box> { + ) -> Result, Box> { // Get data into a byte array let lines = input.iter().map(|s| s.as_bytes()).collect::>(); let mut symbols: HashMap<(usize, usize, char), Vec> = HashMap::new(); diff --git a/src/solutions/day04.rs b/src/solutions/day04.rs index b84caae..4cffd0a 100644 --- a/src/solutions/day04.rs +++ b/src/solutions/day04.rs @@ -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, - ) -> Result, Box> { + ) -> Result, Box> { // 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, - ) -> Result, Box> { + ) -> Result, Box> { // 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 { @@ -53,7 +54,7 @@ impl Solution for Day04 { copy_counts[*i + j + 1] += copy_counts[*i]; } } - + Ok(Box::new(copy_counts.iter().sum::())) } diff --git a/src/solutions/day05.rs b/src/solutions/day05.rs index 4e9aba9..cc13ac1 100644 --- a/src/solutions/day05.rs +++ b/src/solutions/day05.rs @@ -7,49 +7,63 @@ impl Solution for Day05 { fn part1( &self, input: &mut Vec, - ) -> Result, Box> { + ) -> Result, Box> { let (seeds, maps) = self.get_mappings(input)?; - 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() - ); + 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() + }); Ok(Box::new(*locations.iter().min().unwrap())) } fn part2( &self, input: &mut Vec, - ) -> Result, Box> { + ) -> Result, Box> { let (seeds, maps) = self.get_mappings(input)?; - let seeds = seeds.iter() + let seeds = seeds + .iter() .tuples() .map(|(&a, len)| (a, a + len)) .collect::>(); - 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 { - let mut m = Vec::new(); - for (start, end) in unmapped { - 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); } - } - unmapped = m; - } - mapped.extend(unmapped); - mapped - }).collect() - ); + 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 { + let mut m = Vec::new(); + for (start, end) in unmapped { + 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); + } + } + unmapped = m; + } + mapped.extend(unmapped); + mapped + }) + .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) -> Result<(Vec, Vec>), Box> { - let seeds: Vec = input[0].split_whitespace() - .skip(1) - .map(|s| s.parse().unwrap()) - .collect::>(); + fn get_mappings( + &self, + input: &Vec, + ) -> Result<(Vec, Vec>), Box> { + let seeds: Vec = input[0] + .split_whitespace() + .skip(1) + .map(|s| s.parse().unwrap()) + .collect::>(); - let maps: Vec> = 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::>() - ).collect::>(); + let maps: Vec> = 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::>() + }) + .collect::>(); Ok((seeds, maps)) } diff --git a/src/solutions/day06.rs b/src/solutions/day06.rs index a874f45..69ebe63 100644 --- a/src/solutions/day06.rs +++ b/src/solutions/day06.rs @@ -6,14 +6,14 @@ impl Solution for Day06 { fn part1( &self, _input: &mut Vec, - ) -> Result, Box> { + ) -> Result, Box> { Ok(Box::new("Ready")) } fn part2( &self, _input: &mut Vec, - ) -> Result, Box> { + ) -> Result, Box> { Ok(Box::new("Ready")) } diff --git a/src/solutions/mod.rs b/src/solutions/mod.rs index 65e27a3..1850896 100644 --- a/src/solutions/mod.rs +++ b/src/solutions/mod.rs @@ -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) -> Result, Box>; - fn part2(&self, input: &mut Vec) -> Result, Box>; + fn part1(&self, input: &mut Vec) -> Result, Box>; + fn part2(&self, input: &mut Vec) -> Result, Box>; fn get_day(&self) -> u8; - fn run(&self) -> Result<(), Box> { - println!("========== Day {} ==========", self.get_day()); + fn run(&self) -> Result> { 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())? - ); - - 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(()) + 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) } } + +pub struct Run { + pub part1: Box, + pub part2: Box, + pub day: u8, + pub time: core::time::Duration, +} + +unsafe impl Send for Run {} diff --git a/src/utils.rs b/src/utils.rs index b860d73..fbe3c16 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -5,6 +5,7 @@ use std::{ }; /// Enum used to specify input +#[allow(unused)] pub enum InputType { Test1, Test2,