Parallel day20

This commit is contained in:
Adrian Groh 2024-12-20 13:22:57 +01:00
parent 1baa3342cc
commit dfa6d05f59
Signed by: Gobidev
GPG Key ID: 3AA3153E98B0D771
3 changed files with 115 additions and 80 deletions

52
day20/Cargo.lock generated
View File

@ -2,15 +2,67 @@
# It is not intended for manual editing. # It is not intended for manual editing.
version = 4 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]] [[package]]
name = "day20" name = "day20"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"glam", "glam",
"rayon",
] ]
[[package]]
name = "either"
version = "1.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0"
[[package]] [[package]]
name = "glam" name = "glam"
version = "0.29.2" version = "0.29.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc46dd3ec48fdd8e693a98d2b8bafae273a2d54c1de02a2a7e3d57d501f39677" 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",
]

View File

@ -5,3 +5,4 @@ edition = "2021"
[dependencies] [dependencies]
glam = "0.29.2" glam = "0.29.2"
rayon = "1.10.0"

View File

@ -1,6 +1,5 @@
use std::fmt::Display;
use glam::IVec2; use glam::IVec2;
use rayon::prelude::*;
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)] #[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
enum Direction { enum Direction {
@ -25,52 +24,25 @@ impl Direction {
vec![Up, Left, Down, Right] vec![Up, Left, Down, Right]
} }
fn orthogonal(&self) -> Vec<Self> { fn turn_right(&self) -> Self {
match self { match self {
Up | Down => vec![Left, Right], Up => Right,
Left | Right => vec![Up, Down], Left => Up,
} Down => Left,
} Right => 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"),
} }
} }
} }
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)] #[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
struct Tile { struct Tile {
tiletype: TileType, tiletype: bool,
distance: usize, distance: usize,
} }
impl Display for Tile { fn parse(input: &str) -> (Vec<Vec<Tile>>, IVec2, IVec2) {
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<Vec<Tile>>, IVec2) {
let mut start_pos = IVec2::new(0, 0); let mut start_pos = IVec2::new(0, 0);
let mut end_pos = IVec2::new(0, 0);
( (
input input
.lines() .lines()
@ -80,14 +52,18 @@ fn parse(input: &str) -> (Vec<Vec<Tile>>, IVec2) {
.enumerate() .enumerate()
.map(|(c_idx, c)| Tile { .map(|(c_idx, c)| Tile {
tiletype: match c { tiletype: match c {
'#' => Wall, '#' => true,
'S' => { 'S' => {
start_pos.x = l_idx as i32; start_pos.x = l_idx as i32;
start_pos.y = c_idx as i32; start_pos.y = c_idx as i32;
Start false
} }
'E' => End, 'E' => {
_ => Free, end_pos.x = l_idx as i32;
end_pos.y = c_idx as i32;
false
}
_ => false,
}, },
distance: usize::MAX, distance: usize::MAX,
}) })
@ -95,65 +71,71 @@ fn parse(input: &str) -> (Vec<Vec<Tile>>, IVec2) {
}) })
.collect(), .collect(),
start_pos, start_pos,
end_pos,
) )
} }
fn get_distances(map: &mut [Vec<Tile>], pos: &IVec2, distance: &usize, path: &mut Vec<IVec2>) { fn get_distances(
map: &mut [Vec<Tile>],
pos: &IVec2,
distance: &usize,
path: &mut Vec<IVec2>,
end_pos: &IVec2,
) {
let curr_tile = &mut map[pos.x as usize][pos.y as usize]; let curr_tile = &mut map[pos.x as usize][pos.y as usize];
curr_tile.distance = *distance; curr_tile.distance = *distance;
if curr_tile.tiletype == End { if pos == end_pos {
return; return;
} }
for direction in Direction::all() { for direction in Direction::all() {
let new_tile_pos = pos + direction.to_vec(); let new_tile_pos = pos + direction.to_vec();
let new_tile = map[new_tile_pos.x as usize][new_tile_pos.y as usize]; 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); 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<Tile>], path: &[IVec2], max_distance: i32) -> usize { fn part12(map: &[Vec<Tile>], path: &[IVec2], max_distance: i32) -> usize {
let mut res = 0; path.par_iter()
for tile in path { .map(|tile| {
let mut cheated_targets = vec![]; Direction::all()
for direction in Direction::all() { .iter()
for i in 2..=max_distance { .map(|direction| {
for j in 0..=(max_distance - i) { (1..=max_distance)
for other_direction in direction.orthogonal() { .map(|i| {
let new_tile_pos = (0..=(max_distance - i))
tile + i * direction.to_vec() + j * other_direction.to_vec(); .filter(|j| {
let Some(Some(t)) = map let new_tile_pos = tile
.get(new_tile_pos.x as usize) + i * direction.to_vec()
.map(|l| l.get(new_tile_pos.y as usize)) + j * direction.turn_right().to_vec();
else { map.get(new_tile_pos.x as usize)
continue; .and_then(|l| l.get(new_tile_pos.y as usize))
}; .map_or(false, |t| {
if t.tiletype == Wall || cheated_targets.contains(&new_tile_pos) { !t.tiletype
continue; && t.distance
} >= map[tile.x as usize][tile.y as usize]
if t.distance .distance
>= map[tile.x as usize][tile.y as usize].distance + 100
+ 100 + i as usize
+ i as usize + *j as usize
+ j as usize })
{ })
cheated_targets.push(new_tile_pos); .count()
res += 1; })
} .sum::<usize>()
} })
} .sum::<usize>()
} })
} .sum()
}
res
} }
fn main() { 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]; 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, 2));
println!("{}", part12(&map, &path, 20)); println!("{}", part12(&map, &path, 20));
} }