Using Rayon gets 6b runtime down to only five seconds

This commit is contained in:
Savanni D'Gerinel 2024-12-09 13:41:03 -05:00
parent 4c453b192a
commit 8f47885d0a
1 changed files with 35 additions and 15 deletions

View File

@ -1,6 +1,7 @@
use std::collections::HashSet; use std::{collections::HashSet, sync::{Arc, RwLock}};
use crate::grid::{Direction, Grid}; use crate::grid::{Direction, Grid};
use rayon::prelude::*;
const INPUT: &'static str = include_str!("../data/day6.txt"); const INPUT: &'static str = include_str!("../data/day6.txt");
@ -23,31 +24,42 @@ struct Guard {
fn distinct_locations(grid: &Grid) -> usize { fn distinct_locations(grid: &Grid) -> usize {
let guard = find_guard(grid); let guard = find_guard(grid);
let (_, path) = simulate_path(grid, guard.clone()); let (_, path) = simulate_path(grid, guard.clone());
path.into_iter().map(|guard| guard.location).collect::<HashSet<(usize, usize)>>().len() path.into_iter()
.map(|guard| guard.location)
.collect::<HashSet<(usize, usize)>>()
.len()
} }
fn looping_obstructions(mut grid: Grid) -> HashSet<(usize, usize)> { fn looping_obstructions(grid: Grid) -> HashSet<(usize, usize)> {
let guard = find_guard(&grid); let guard = find_guard(&grid);
let (_, path) = simulate_path(&grid, guard.clone()); 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 start = path.first().unwrap().clone();
let mut path = path.into_iter().map(|g| g.location).collect::<HashSet<(usize, usize)>>(); let mut path = path
.into_iter()
.map(|g| g.location)
.collect::<HashSet<(usize, usize)>>();
path.remove(&start.location); path.remove(&start.location);
// Now that we know the guard's original path, we can traverse all of the locations she would // 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 // step through and consider that location as a potential new obstacle. Place and obstacle
// there and re-run the simulation. // there and re-run the simulation.
for location in path.into_iter() { path.into_par_iter().for_each({
let obstructions = obstructions.clone();
move |location| {
let mut grid = grid.clone();
*grid.elem_mut(location.0, location.1) = '#'; *grid.elem_mut(location.0, location.1) = '#';
let (looping, _) = simulate_path(&grid, guard.clone()); let (looping, _) = simulate_path(&grid, guard.clone());
*grid.elem_mut(location.0, location.1) = '.'; *grid.elem_mut(location.0, location.1) = '.';
if looping { if looping {
obstructions.insert(location); obstructions.write().unwrap().insert(location);
} }
} }
});
obstructions let x = obstructions.read().unwrap().clone();
x
} }
fn find_guard(grid: &Grid) -> Guard { fn find_guard(grid: &Grid) -> Guard {
@ -129,7 +141,13 @@ mod test {
#[test] #[test]
fn it_finds_the_guard() { fn it_finds_the_guard() {
let grid = Grid::from(TEST_INPUT); 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] #[test]
@ -156,7 +174,9 @@ mod test {
assert!(obs.contains(&(3, 8))); assert!(obs.contains(&(3, 8)));
assert!(obs.contains(&(7, 9))); assert!(obs.contains(&(7, 9)));
/* Even with par_iter, this is still too slow to run on every test
let grid = Grid::from(INPUT); let grid = Grid::from(INPUT);
assert_eq!(looping_obstructions(grid).len(), 1703); assert_eq!(looping_obstructions(grid).len(), 1703);
*/
} }
} }