1
1
use std:: collections:: { HashMap , VecDeque } ;
2
2
use std:: fs;
3
+ use std:: rc:: Rc ;
3
4
4
5
pub const DIRS : [ ( i32 , i32 ) ; 4 ] = [ ( 1 , 0 ) , ( 0 , 1 ) , ( -1 , 0 ) , ( 0 , -1 ) ] ;
5
6
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
+
7
32
// find 'from' and 'to' on keypad
8
33
let mut start = ( 0 , 0 ) ;
9
34
let mut end = ( 0 , 0 ) ;
@@ -18,10 +43,6 @@ fn find_shortest_paths(keypad: &[[u8; 3]], from: u8, to: u8) -> Vec<Vec<u8>> {
18
43
}
19
44
}
20
45
21
- if start == end {
22
- return vec ! [ vec![ b'A' ] ] ;
23
- }
24
-
25
46
// flood fill keypad to find the shortest distances
26
47
let mut dists = vec ! [ [ usize :: MAX ; 3 ] ; keypad. len( ) ] ;
27
48
let mut queue = VecDeque :: new ( ) ;
@@ -77,17 +98,18 @@ fn find_shortest_paths(keypad: &[[u8; 3]], from: u8, to: u8) -> Vec<Vec<u8>> {
77
98
}
78
99
}
79
100
80
- paths
101
+ let result = Rc :: new ( paths) ;
102
+ cache. insert ( ( from, to) , result. clone ( ) ) ;
103
+ result
81
104
}
82
105
83
106
fn find_shortest_sequence (
84
107
s : & [ u8 ] ,
85
108
depth : usize ,
86
109
highest : bool ,
87
110
cursors : & mut Vec < u8 > ,
88
- numeric : & [ [ u8 ; 3 ] ] ,
89
- directional : & [ [ u8 ; 3 ] ] ,
90
111
cache : & mut HashMap < ( Vec < u8 > , usize , u8 ) , usize > ,
112
+ path_cache : & mut HashMap < ( u8 , u8 ) , Rc < Vec < Vec < u8 > > > > ,
91
113
) -> usize {
92
114
let cache_key = ( s. to_vec ( ) , depth, cursors[ depth] ) ;
93
115
if let Some ( cached) = cache. get ( & cache_key) {
@@ -97,26 +119,18 @@ fn find_shortest_sequence(
97
119
let mut result = 0 ;
98
120
for & c in s {
99
121
let paths = find_shortest_paths (
100
- if highest { numeric } else { directional } ,
122
+ if highest { & NUMERIC } else { & DIRECTIONAL } ,
101
123
cursors[ depth] ,
102
124
c,
125
+ path_cache,
103
126
) ;
104
127
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 ( ) ;
106
130
} else {
107
131
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) )
120
134
. min ( )
121
135
. unwrap ( ) ;
122
136
}
@@ -129,18 +143,11 @@ fn find_shortest_sequence(
129
143
}
130
144
131
145
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
-
141
146
let input = fs:: read_to_string ( "input.txt" ) . expect ( "Could not read file" ) ;
142
147
let lines = input. lines ( ) . collect :: < Vec < _ > > ( ) ;
148
+
143
149
let mut cache = HashMap :: new ( ) ;
150
+ let mut path_cache = HashMap :: new ( ) ;
144
151
145
152
for part1 in [ true , false ] {
146
153
let max_depth = if part1 { 2 } else { 25 } ;
@@ -153,9 +160,8 @@ fn main() {
153
160
max_depth,
154
161
true ,
155
162
& mut cursors,
156
- & numeric,
157
- & directional,
158
163
& mut cache,
164
+ & mut path_cache,
159
165
) ;
160
166
161
167
let n = l[ 0 ..3 ] . parse :: < usize > ( ) . unwrap ( ) ;
0 commit comments