From 8f47885d0a8149c2d3699793acc6d57cae92fd6f Mon Sep 17 00:00:00 2001 From: Savanni D'Gerinel Date: Mon, 9 Dec 2024 13:41:03 -0500 Subject: [PATCH] Using Rayon gets 6b runtime down to only five seconds --- 2024/src/day6.rs | 50 +++++++++++++++++++++++++++++++++--------------- 1 file changed, 35 insertions(+), 15 deletions(-) diff --git a/2024/src/day6.rs b/2024/src/day6.rs index 8307edf..f50df6f 100644 --- a/2024/src/day6.rs +++ b/2024/src/day6.rs @@ -1,6 +1,7 @@ -use std::collections::HashSet; +use std::{collections::HashSet, sync::{Arc, RwLock}}; use crate::grid::{Direction, Grid}; +use rayon::prelude::*; const INPUT: &'static str = include_str!("../data/day6.txt"); @@ -23,31 +24,42 @@ struct Guard { fn distinct_locations(grid: &Grid) -> usize { let guard = find_guard(grid); let (_, path) = simulate_path(grid, guard.clone()); - path.into_iter().map(|guard| guard.location).collect::>().len() + path.into_iter() + .map(|guard| guard.location) + .collect::>() + .len() } -fn looping_obstructions(mut grid: Grid) -> HashSet<(usize, usize)> { +fn looping_obstructions(grid: Grid) -> HashSet<(usize, usize)> { let guard = find_guard(&grid); let (_, path) = simulate_path(&grid, guard.clone()); - let mut obstructions = HashSet::new(); + let obstructions = Arc::new(RwLock::new(HashSet::new())); let start = path.first().unwrap().clone(); - let mut path = path.into_iter().map(|g| g.location).collect::>(); + let mut path = path + .into_iter() + .map(|g| g.location) + .collect::>(); path.remove(&start.location); // Now that we know the guard's original path, we can traverse all of the locations she would // step through and consider that location as a potential new obstacle. Place and obstacle // there and re-run the simulation. - for location in path.into_iter() { - *grid.elem_mut(location.0, location.1) = '#'; - let (looping, _) = simulate_path(&grid, guard.clone()); - *grid.elem_mut(location.0, location.1) = '.'; - if looping { - obstructions.insert(location); + path.into_par_iter().for_each({ + let obstructions = obstructions.clone(); + move |location| { + let mut grid = grid.clone(); + *grid.elem_mut(location.0, location.1) = '#'; + let (looping, _) = simulate_path(&grid, guard.clone()); + *grid.elem_mut(location.0, location.1) = '.'; + if looping { + obstructions.write().unwrap().insert(location); + } } - } + }); - obstructions + let x = obstructions.read().unwrap().clone(); + x } fn find_guard(grid: &Grid) -> Guard { @@ -62,7 +74,7 @@ fn find_guard(grid: &Grid) -> Guard { }; if let Some(orientation) = orientation { - return Guard{ + return Guard { location: (x, y), orientation, }; @@ -129,7 +141,13 @@ mod test { #[test] fn it_finds_the_guard() { let grid = Grid::from(TEST_INPUT); - assert_eq!(find_guard(&grid), Guard{ location: (4, 6), orientation: Direction::North }); + assert_eq!( + find_guard(&grid), + Guard { + location: (4, 6), + orientation: Direction::North + } + ); } #[test] @@ -156,7 +174,9 @@ mod test { assert!(obs.contains(&(3, 8))); assert!(obs.contains(&(7, 9))); + /* Even with par_iter, this is still too slow to run on every test let grid = Grid::from(INPUT); assert_eq!(looping_obstructions(grid).len(), 1703); + */ } }