Skip to content

Commit 4e07af0

Browse files
committed
day 20: 100ms -> 10ms; vec instead of hashmap
1 parent 1fcaf1f commit 4e07af0

File tree

2 files changed

+75
-57
lines changed

2 files changed

+75
-57
lines changed

README.md

+27-27
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,40 @@
11
## Advent of code 2024
22
My solutions for the 2024 Advent of Code event. All solutions are written in Rust, and are of questionable quality since it's my first time using the language.
3-
The code is reasonably performant however and solves all problems in < 300 ms (see benchmarks below).
3+
The code is reasonably performant however and solves all problems in ~ 200 ms (see benchmarks below).
44

55
### Benchmarks
66
Results from `./run.sh` in WSL using a 2016 Asus ZenBook UX303 (Ryzen 7 5700U 1.8GHz, 16GB RAM)
77
```
88
----------------------------------------
99
Day Time (ms) Cumulative (ms)
1010
----------------------------------------
11-
1 0.30 0.30
12-
2 0.53 0.83
13-
3 0.16 0.99
14-
4 0.55 1.54
15-
5 1.71 3.25
16-
6 24.98 28.23
17-
7 13.11 41.34
18-
8 0.38 41.72
19-
9 2.40 44.13
20-
10 0.57 44.70
21-
11 7.81 52.50
22-
12 2.60 55.11
23-
13 1.41 56.52
24-
14 53.28 109.80
25-
15 2.51 112.31
26-
16 31.24 143.55
27-
17 0.05 143.60
28-
18 0.57 144.17
29-
19 1.87 146.04
30-
20 70.11 216.14
31-
21 10.96 227.11
32-
22 20.79 247.89
33-
23 25.34 273.23
34-
24 0.31 273.54
35-
25 0.07 273.61
11+
1 0.21 0.21
12+
2 0.46 0.66
13+
3 0.06 0.72
14+
4 0.53 1.25
15+
5 1.62 2.87
16+
6 22.79 25.65
17+
7 12.82 38.47
18+
8 0.44 38.91
19+
9 2.64 41.55
20+
10 0.50 42.05
21+
11 7.65 49.70
22+
12 2.65 52.34
23+
13 1.75 54.09
24+
14 52.70 106.79
25+
15 2.51 109.29
26+
16 30.36 139.66
27+
17 0.05 139.71
28+
18 0.56 140.26
29+
19 1.91 142.17
30+
20 10.85 153.02
31+
21 10.69 163.71
32+
22 19.20 182.92
33+
23 25.09 208.01
34+
24 0.28 208.28
35+
25 0.07 208.35
3636
----------------------------------------
37-
Total 273.61
37+
Total 208.35
3838
```
3939

4040
### Requirements

src/day20.rs

+48-30
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use rayon::prelude::*;
2-
use std::collections::{HashMap, VecDeque};
2+
use std::collections::VecDeque;
33

44
const DIRS4: [(i32, i32); 4] = [(1, 0), (0, 1), (0, -1), (-1, 0)];
55

@@ -9,31 +9,46 @@ pub struct Pos {
99
}
1010

1111
pub fn find_cheats(
12-
from_start: &HashMap<(usize, usize), i32>,
13-
from_end: &HashMap<(usize, usize), i32>,
12+
from_start: &[Vec<i32>],
13+
from_end: &[Vec<i32>],
1414
e: &Pos,
1515
n: i32,
1616
skips_allowed: i32,
1717
) -> i32 {
18-
let end_steps = from_start[&(e.i, e.j)];
18+
let end_steps = from_start[e.i][e.j];
1919
let threshold = if n > 50 { 100 } else { 50 };
20+
2021
from_start
2122
.par_iter()
22-
.map(|(&(i, j), &_v)| {
23+
.enumerate()
24+
.map(|(i, row)| {
2325
let mut local_result = 0;
24-
let steps = from_start[&(i, j)];
25-
for di in -20..21_i32 {
26-
for dj in (di.abs() - 20)..(21 - di.abs()) {
27-
let (oi, oj) = (i as i32 + di, j as i32 + dj);
28-
if from_end.contains_key(&(oi as usize, oj as usize)) {
29-
let d = di.abs() + dj.abs();
30-
if d > skips_allowed {
31-
continue;
32-
}
33-
let total = steps + from_end[&(oi as usize, oj as usize)] + d;
34-
let saved = end_steps - total;
35-
if saved >= threshold {
36-
local_result += 1;
26+
for (j, &steps) in row.iter().enumerate() {
27+
if steps == -1 {
28+
continue;
29+
}
30+
for di in -20..21_i32 {
31+
for dj in (di.abs() - 20)..(21 - di.abs()) {
32+
let oi = i as i32 + di;
33+
let oj = j as i32 + dj;
34+
if oi >= 0
35+
&& oi < from_end.len() as i32
36+
&& oj >= 0
37+
&& oj < from_end[0].len() as i32
38+
{
39+
let oi = oi as usize;
40+
let oj = oj as usize;
41+
if from_end[oi][oj] != -1 {
42+
let d = di.abs() + dj.abs();
43+
if d > skips_allowed {
44+
continue;
45+
}
46+
let total = steps + from_end[oi][oj] + d;
47+
let saved = end_steps - total;
48+
if saved >= threshold {
49+
local_result += 1;
50+
}
51+
}
3752
}
3853
}
3954
}
@@ -42,33 +57,35 @@ pub fn find_cheats(
4257
})
4358
.sum()
4459
}
45-
4660
pub fn bfs(grid: &[Vec<char>], s: &Pos, e: &Pos) -> (i32, i32) {
47-
let mut from_start: HashMap<(usize, usize), i32> = HashMap::new();
48-
let mut from_end: HashMap<(usize, usize), i32> = HashMap::new();
49-
let n = grid.len() as i32;
50-
let m = grid[0].len() as i32;
61+
let n = grid.len();
62+
let m = grid[0].len();
63+
let mut from_start = vec![vec![-1; m]; n];
64+
let mut from_end = vec![vec![-1; m]; n];
65+
5166
for iter in 0..2 {
5267
let mut steps = 0;
5368
let mut queue = VecDeque::new();
54-
queue.push_back(if iter == 0 { (s.i, s.j) } else { (e.i, e.j) });
69+
let start = if iter == 0 { (s.i, s.j) } else { (e.i, e.j) };
5570
let map = if iter == 0 {
5671
&mut from_start
5772
} else {
5873
&mut from_end
5974
};
75+
76+
queue.push_back(start);
6077
while !queue.is_empty() {
6178
let qlen = queue.len();
6279
for _ in 0..qlen {
6380
let (i, j) = queue.pop_front().unwrap();
64-
if map.contains_key(&(i, j)) {
81+
if map[i][j] != -1 {
6582
continue;
6683
}
67-
map.insert((i, j), steps);
84+
map[i][j] = steps;
6885
for (di, dj) in DIRS4.iter() {
6986
let (ni, nj) = (i as i32 + di, j as i32 + dj);
70-
if (0..n).contains(&ni)
71-
&& (0..m).contains(&nj)
87+
if (0..n as i32).contains(&ni)
88+
&& (0..m as i32).contains(&nj)
7289
&& grid[ni as usize][nj as usize] != '#'
7390
{
7491
queue.push_back((ni as usize, nj as usize));
@@ -78,8 +95,9 @@ pub fn bfs(grid: &[Vec<char>], s: &Pos, e: &Pos) -> (i32, i32) {
7895
steps += 1;
7996
}
8097
}
81-
let part_one = find_cheats(&from_start, &from_end, e, n, 2);
82-
let part_two = find_cheats(&from_start, &from_end, e, n, 20);
98+
99+
let part_one = find_cheats(&from_start, &from_end, e, n as i32, 2);
100+
let part_two = find_cheats(&from_start, &from_end, e, n as i32, 20);
83101
(part_one, part_two)
84102
}
85103

0 commit comments

Comments
 (0)