From dfa6d05f597908ae68bc66f7a17fda1017033bda Mon Sep 17 00:00:00 2001 From: Adrian Groh Date: Fri, 20 Dec 2024 13:22:57 +0100 Subject: [PATCH] Parallel day20 --- day20/Cargo.lock | 52 +++++++++++++++++ day20/Cargo.toml | 1 + day20/src/main.rs | 142 ++++++++++++++++++++-------------------------- 3 files changed, 115 insertions(+), 80 deletions(-) diff --git a/day20/Cargo.lock b/day20/Cargo.lock index 3124e93..3b2648b 100644 --- a/day20/Cargo.lock +++ b/day20/Cargo.lock @@ -2,15 +2,67 @@ # It is not intended for manual editing. version = 4 +[[package]] +name = "crossbeam-deque" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" + [[package]] name = "day20" version = "0.1.0" dependencies = [ "glam", + "rayon", ] +[[package]] +name = "either" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" + [[package]] name = "glam" version = "0.29.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc46dd3ec48fdd8e693a98d2b8bafae273a2d54c1de02a2a7e3d57d501f39677" + +[[package]] +name = "rayon" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] diff --git a/day20/Cargo.toml b/day20/Cargo.toml index e908723..f92230d 100644 --- a/day20/Cargo.toml +++ b/day20/Cargo.toml @@ -5,3 +5,4 @@ edition = "2021" [dependencies] glam = "0.29.2" +rayon = "1.10.0" diff --git a/day20/src/main.rs b/day20/src/main.rs index 9462c77..7fcb997 100644 --- a/day20/src/main.rs +++ b/day20/src/main.rs @@ -1,6 +1,5 @@ -use std::fmt::Display; - use glam::IVec2; +use rayon::prelude::*; #[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)] enum Direction { @@ -25,52 +24,25 @@ impl Direction { vec![Up, Left, Down, Right] } - fn orthogonal(&self) -> Vec { + fn turn_right(&self) -> Self { match self { - Up | Down => vec![Left, Right], - Left | Right => vec![Up, Down], - } - } -} - -#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)] -enum TileType { - Free, - Wall, - Start, - End, -} -use TileType::*; - -impl Display for TileType { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - Free => write!(f, "."), - Wall => write!(f, "#"), - Start => write!(f, "S"), - End => write!(f, "E"), + Up => Right, + Left => Up, + Down => Left, + Right => Down, } } } #[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)] struct Tile { - tiletype: TileType, + tiletype: bool, distance: usize, } -impl Display for Tile { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - if self.distance < usize::MAX { - write!(f, ",") - } else { - write!(f, "{}", self.tiletype) - } - } -} - -fn parse(input: &str) -> (Vec>, IVec2) { +fn parse(input: &str) -> (Vec>, IVec2, IVec2) { let mut start_pos = IVec2::new(0, 0); + let mut end_pos = IVec2::new(0, 0); ( input .lines() @@ -80,14 +52,18 @@ fn parse(input: &str) -> (Vec>, IVec2) { .enumerate() .map(|(c_idx, c)| Tile { tiletype: match c { - '#' => Wall, + '#' => true, 'S' => { start_pos.x = l_idx as i32; start_pos.y = c_idx as i32; - Start + false } - 'E' => End, - _ => Free, + 'E' => { + end_pos.x = l_idx as i32; + end_pos.y = c_idx as i32; + false + } + _ => false, }, distance: usize::MAX, }) @@ -95,65 +71,71 @@ fn parse(input: &str) -> (Vec>, IVec2) { }) .collect(), start_pos, + end_pos, ) } -fn get_distances(map: &mut [Vec], pos: &IVec2, distance: &usize, path: &mut Vec) { +fn get_distances( + map: &mut [Vec], + pos: &IVec2, + distance: &usize, + path: &mut Vec, + end_pos: &IVec2, +) { let curr_tile = &mut map[pos.x as usize][pos.y as usize]; curr_tile.distance = *distance; - if curr_tile.tiletype == End { + if pos == end_pos { return; } for direction in Direction::all() { let new_tile_pos = pos + direction.to_vec(); let new_tile = map[new_tile_pos.x as usize][new_tile_pos.y as usize]; - if new_tile.tiletype != Wall && new_tile.distance > distance + 1 { + if !new_tile.tiletype && new_tile.distance > distance + 1 { path.push(new_tile_pos); - get_distances(map, &new_tile_pos, &(distance + 1), path); + get_distances(map, &new_tile_pos, &(distance + 1), path, end_pos); + break; } } } fn part12(map: &[Vec], path: &[IVec2], max_distance: i32) -> usize { - let mut res = 0; - for tile in path { - let mut cheated_targets = vec![]; - for direction in Direction::all() { - for i in 2..=max_distance { - for j in 0..=(max_distance - i) { - for other_direction in direction.orthogonal() { - let new_tile_pos = - tile + i * direction.to_vec() + j * other_direction.to_vec(); - let Some(Some(t)) = map - .get(new_tile_pos.x as usize) - .map(|l| l.get(new_tile_pos.y as usize)) - else { - continue; - }; - if t.tiletype == Wall || cheated_targets.contains(&new_tile_pos) { - continue; - } - if t.distance - >= map[tile.x as usize][tile.y as usize].distance - + 100 - + i as usize - + j as usize - { - cheated_targets.push(new_tile_pos); - res += 1; - } - } - } - } - } - } - res + path.par_iter() + .map(|tile| { + Direction::all() + .iter() + .map(|direction| { + (1..=max_distance) + .map(|i| { + (0..=(max_distance - i)) + .filter(|j| { + let new_tile_pos = tile + + i * direction.to_vec() + + j * direction.turn_right().to_vec(); + map.get(new_tile_pos.x as usize) + .and_then(|l| l.get(new_tile_pos.y as usize)) + .map_or(false, |t| { + !t.tiletype + && t.distance + >= map[tile.x as usize][tile.y as usize] + .distance + + 100 + + i as usize + + *j as usize + }) + }) + .count() + }) + .sum::() + }) + .sum::() + }) + .sum() } fn main() { - let (mut map, start_pos) = parse(include_str!("../input.txt")); + let (mut map, start_pos, end_pos) = parse(include_str!("../input.txt")); let mut path = vec![start_pos]; - get_distances(&mut map, &start_pos, &0, &mut path); + get_distances(&mut map, &start_pos, &0, &mut path, &end_pos); println!("{}", part12(&map, &path, 2)); println!("{}", part12(&map, &path, 20)); }