Skip to content

Commit adcab0c

Browse files
2024: Optimize day 21
1 parent 54a793a commit adcab0c

File tree

1 file changed

+39
-33
lines changed

1 file changed

+39
-33
lines changed

2024/day21/src/main.rs

Lines changed: 39 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,34 @@
11
use std::collections::{HashMap, VecDeque};
22
use std::fs;
3+
use std::rc::Rc;
34

45
pub const DIRS: [(i32, i32); 4] = [(1, 0), (0, 1), (-1, 0), (0, -1)];
56

6-
fn find_shortest_paths(keypad: &[[u8; 3]], from: u8, to: u8) -> Vec<Vec<u8>> {
7+
const NUMERIC: [[u8; 3]; 4] = [
8+
[b'7', b'8', b'9'],
9+
[b'4', b'5', b'6'],
10+
[b'1', b'2', b'3'],
11+
[b' ', b'0', b'A'],
12+
];
13+
14+
const DIRECTIONAL: [[u8; 3]; 2] = [[b' ', b'^', b'A'], [b'<', b'v', b'>']];
15+
16+
fn find_shortest_paths(
17+
keypad: &[[u8; 3]],
18+
from: u8,
19+
to: u8,
20+
cache: &mut HashMap<(u8, u8), Rc<Vec<Vec<u8>>>>,
21+
) -> Rc<Vec<Vec<u8>>> {
22+
if let Some(cached) = cache.get(&(from, to)) {
23+
return cached.clone();
24+
}
25+
26+
if from == to {
27+
let result = Rc::new(vec![vec![b'A']]);
28+
cache.insert((from, to), result.clone());
29+
return result;
30+
}
31+
732
// find 'from' and 'to' on keypad
833
let mut start = (0, 0);
934
let mut end = (0, 0);
@@ -18,10 +43,6 @@ fn find_shortest_paths(keypad: &[[u8; 3]], from: u8, to: u8) -> Vec<Vec<u8>> {
1843
}
1944
}
2045

21-
if start == end {
22-
return vec![vec![b'A']];
23-
}
24-
2546
// flood fill keypad to find the shortest distances
2647
let mut dists = vec![[usize::MAX; 3]; keypad.len()];
2748
let mut queue = VecDeque::new();
@@ -77,17 +98,18 @@ fn find_shortest_paths(keypad: &[[u8; 3]], from: u8, to: u8) -> Vec<Vec<u8>> {
7798
}
7899
}
79100

80-
paths
101+
let result = Rc::new(paths);
102+
cache.insert((from, to), result.clone());
103+
result
81104
}
82105

83106
fn find_shortest_sequence(
84107
s: &[u8],
85108
depth: usize,
86109
highest: bool,
87110
cursors: &mut Vec<u8>,
88-
numeric: &[[u8; 3]],
89-
directional: &[[u8; 3]],
90111
cache: &mut HashMap<(Vec<u8>, usize, u8), usize>,
112+
path_cache: &mut HashMap<(u8, u8), Rc<Vec<Vec<u8>>>>,
91113
) -> usize {
92114
let cache_key = (s.to_vec(), depth, cursors[depth]);
93115
if let Some(cached) = cache.get(&cache_key) {
@@ -97,26 +119,18 @@ fn find_shortest_sequence(
97119
let mut result = 0;
98120
for &c in s {
99121
let paths = find_shortest_paths(
100-
if highest { numeric } else { directional },
122+
if highest { &NUMERIC } else { &DIRECTIONAL },
101123
cursors[depth],
102124
c,
125+
path_cache,
103126
);
104127
if depth == 0 {
105-
result += paths.into_iter().map(|l| l.len()).min().unwrap();
128+
// all paths have the same length
129+
result += paths[0].len();
106130
} else {
107131
result += paths
108-
.into_iter()
109-
.map(|p| {
110-
find_shortest_sequence(
111-
&p,
112-
depth - 1,
113-
false,
114-
cursors,
115-
numeric,
116-
directional,
117-
cache,
118-
)
119-
})
132+
.iter()
133+
.map(|p| find_shortest_sequence(p, depth - 1, false, cursors, cache, path_cache))
120134
.min()
121135
.unwrap();
122136
}
@@ -129,18 +143,11 @@ fn find_shortest_sequence(
129143
}
130144

131145
fn main() {
132-
let numeric = vec![
133-
[b'7', b'8', b'9'],
134-
[b'4', b'5', b'6'],
135-
[b'1', b'2', b'3'],
136-
[b' ', b'0', b'A'],
137-
];
138-
139-
let directional = vec![[b' ', b'^', b'A'], [b'<', b'v', b'>']];
140-
141146
let input = fs::read_to_string("input.txt").expect("Could not read file");
142147
let lines = input.lines().collect::<Vec<_>>();
148+
143149
let mut cache = HashMap::new();
150+
let mut path_cache = HashMap::new();
144151

145152
for part1 in [true, false] {
146153
let max_depth = if part1 { 2 } else { 25 };
@@ -153,9 +160,8 @@ fn main() {
153160
max_depth,
154161
true,
155162
&mut cursors,
156-
&numeric,
157-
&directional,
158163
&mut cache,
164+
&mut path_cache,
159165
);
160166

161167
let n = l[0..3].parse::<usize>().unwrap();

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy