Skip to content

Commit 81bf612

Browse files
committed
Seeing how concerency can speed this up
1 parent a01dbf8 commit 81bf612

File tree

4 files changed

+138
-74
lines changed

4 files changed

+138
-74
lines changed

2024/day_20/Cargo.lock

+54
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

2024/day_20/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,4 @@ version = "0.1.0"
44
edition = "2021"
55

66
[dependencies]
7+
rayon = "1.10.0"

2024/day_20/src/lib.rs

+45-47
Original file line numberDiff line numberDiff line change
@@ -1,63 +1,60 @@
1-
use std::collections::{VecDeque, HashSet};
1+
use std::collections::{HashSet, VecDeque};
22

33
pub enum Direction {
44
North,
55
East,
66
South,
7-
West
7+
West,
88
}
99

10-
const DIRECTIONS:[Direction; 4] = [
11-
Direction::North,
10+
const DIRECTIONS: [Direction; 4] = [
11+
Direction::North,
1212
Direction::East,
1313
Direction::South,
14-
Direction::West
14+
Direction::West,
1515
];
1616

1717
#[derive(Debug, Hash, PartialEq, Eq, Clone, Copy)]
18-
pub struct Point{
18+
pub struct Point {
1919
row: usize,
20-
col: usize
20+
col: usize,
2121
}
2222
impl Point {
23-
pub fn new(row: usize, col:usize) -> Self {
24-
Point {row, col}
23+
pub fn new(row: usize, col: usize) -> Self {
24+
Point { row, col }
2525
}
2626
pub fn to_uv(&self) -> (isize, isize) {
2727
let (row, col) = (self.row as isize, self.col as isize);
2828
(row + col, row - col)
2929
}
3030
}
3131

32-
pub struct Map{
32+
pub struct Map {
3333
width: usize,
3434
height: usize,
3535
start: Point,
3636
end: Point,
37-
pub matrix: Vec<Vec<Option<usize>>>
37+
pub matrix: Vec<Vec<Option<usize>>>,
3838
}
3939

4040
impl Map {
41-
fn get(&self, p:&Point) -> Option<usize>{
41+
fn get(&self, p: &Point) -> Option<usize> {
4242
self.matrix[p.row][p.col]
4343
}
4444

4545
pub fn neighbors(&self, p: &Point) -> impl Iterator<Item = Point> + '_ {
4646
let &Point { row, col } = p;
47-
DIRECTIONS.iter().filter_map(move |d| {
48-
49-
match d {
50-
Direction::North if row > 0 => Some(Point::new(row - 1, col)),
51-
Direction::West if col > 0 => Some(Point::new(row,col - 1)),
52-
Direction::South if row < self.height - 1 => Some(Point::new(row + 1, col)),
53-
Direction::East if col < self.width - 1 => Some(Point::new(row,col + 1)),
54-
_ => None
55-
}
47+
DIRECTIONS.iter().filter_map(move |d| match d {
48+
Direction::North if row > 0 => Some(Point::new(row - 1, col)),
49+
Direction::West if col > 0 => Some(Point::new(row, col - 1)),
50+
Direction::South if row < self.height - 1 => Some(Point::new(row + 1, col)),
51+
Direction::East if col < self.width - 1 => Some(Point::new(row, col + 1)),
52+
_ => None,
5653
})
5754
}
5855

59-
/// Perform BFS but skew the resulting path so
60-
/// equal Manhattan distances will be in an
56+
/// Perform BFS but skew the resulting path so
57+
/// equal Manhattan distances will be in an
6158
/// axis-aligned box.
6259
pub fn bfs(&mut self) -> Option<Vec<((isize, isize), usize)>> {
6360
let mut seen = HashSet::new();
@@ -69,11 +66,11 @@ impl Map {
6966
self.matrix[p.row][p.col] = Some(dist);
7067

7168
path.push((p.to_uv(), dist));
72-
if p == self.end {
73-
return Some(path);
69+
if p == self.end {
70+
return Some(path);
7471
}
7572
for neighbor in self.neighbors(&p) {
76-
if !seen.contains(&(neighbor)) && self.get(&neighbor).is_some(){
73+
if !seen.contains(&(neighbor)) && self.get(&neighbor).is_some() {
7774
seen.insert(neighbor);
7875
queue.push_back((neighbor, dist + 1));
7976
}
@@ -84,30 +81,31 @@ impl Map {
8481
}
8582

8683
impl From<&String> for Map {
87-
fn from(s:&String) -> Self {
84+
fn from(s: &String) -> Self {
8885
let mut start = None;
8986
let mut end = None;
90-
let m:Vec<Vec<Option<usize>>> = s.split("\n")
91-
.enumerate()
92-
.map(|(row, line)| {
93-
line.chars()
87+
let m: Vec<Vec<Option<usize>>> = s
88+
.split("\n")
9489
.enumerate()
95-
.map(|(col, c)| {
96-
match c {
97-
'#' => None,
98-
'.' => Some(usize::MAX),
99-
'S' => {
100-
start = Some(Point{row, col});
101-
Some(0)
102-
},
103-
'E' => {
104-
end = Some(Point{row, col});
105-
Some(usize::MAX)
106-
}
107-
_ => panic!("Debis on the field!!")
108-
}
109-
}).collect()
110-
}).collect();
90+
.map(|(row, line)| {
91+
line.chars()
92+
.enumerate()
93+
.map(|(col, c)| match c {
94+
'#' => None,
95+
'.' => Some(usize::MAX),
96+
'S' => {
97+
start = Some(Point { row, col });
98+
Some(0)
99+
}
100+
'E' => {
101+
end = Some(Point { row, col });
102+
Some(usize::MAX)
103+
}
104+
_ => panic!("Debis on the field!!"),
105+
})
106+
.collect()
107+
})
108+
.collect();
111109
Map {
112110
start: start.unwrap(),
113111
end: end.unwrap(),

2024/day_20/src/main.rs

+38-27
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,52 @@
1-
use std::fs;
1+
use rayon::prelude::*;
22
use std::cmp::max;
3+
use std::fs;
4+
35
use day_20::*;
46

57
/// points are (u,v) points to skew them to manhattan distance is axis aligned.
6-
fn find_cheats(uv_points:&[((isize, isize), usize)], cheat_length: usize, min_savings:usize) -> usize{
7-
let mut left = 0;
8-
let mut right = 1;
8+
fn find_cheats(
9+
uv_points: &[((isize, isize), usize)],
10+
cheat_length: usize,
11+
min_savings: usize,
12+
) -> usize {
913
let len = uv_points.len();
10-
let mut total = 0;
11-
12-
for &((u, v), start_dist) in uv_points {
13-
14-
while right < len - 1 && uv_points[right].0.0 < u + 1 + cheat_length as isize {
15-
right += 1;
16-
}
17-
while uv_points[left].0.0 < u - cheat_length as isize {
18-
left += 1;
19-
}
20-
for &((u_next, v_next), end_dist) in &uv_points[left..right+1] {
21-
let cheat = max(v.abs_diff(v_next), u.abs_diff(u_next)); // manhattan distance between the two points
22-
23-
if cheat <= cheat_length // don't go through too many walls
24-
&& start_dist + cheat < end_dist // the cheat is actually an improvement
25-
&& end_dist.abs_diff(start_dist) - cheat >= min_savings { // avoid counting tiny savings
26-
total += 1;
27-
}
28-
}
29-
}
30-
total
14+
15+
uv_points
16+
.par_iter()
17+
.enumerate()
18+
.map(|(i, &((u, v), start_dist))| {
19+
let mut left = i;
20+
let mut right = i;
21+
22+
while right < len - 1 && uv_points[right + 1].0 .0 < u + 1 + cheat_length as isize {
23+
right += 1;
24+
}
25+
26+
while left > 0 && uv_points[left - 1].0 .0 >= u - cheat_length as isize {
27+
left -= 1;
28+
}
29+
30+
uv_points[left..=right]
31+
.iter()
32+
.filter(|&&((u_next, v_next), end_dist)| {
33+
let cheat = max(v.abs_diff(v_next), u.abs_diff(u_next)); // Manhattan distance
34+
cheat <= cheat_length
35+
&& start_dist + cheat < end_dist
36+
&& end_dist.abs_diff(start_dist) - cheat >= min_savings
37+
})
38+
.count()
39+
})
40+
.sum()
3141
}
42+
3243
fn main() {
3344
let s = fs::read_to_string("data.txt").expect("no map found?");
3445
let mut map = Map::from(&s);
35-
let mut uv_path = map.bfs().unwrap();
46+
let mut uv_path = map.bfs().unwrap();
3647

3748
uv_path.sort_by_key(|((u, _v), _dist)| *u);
38-
49+
3950
let part_one = find_cheats(&uv_path, 2, 100);
4051
println!("Part one: {}", part_one);
4152

0 commit comments

Comments
 (0)