@@ -35,30 +35,14 @@ fn main() -> Result<()> {
35
35
36
36
println ! ( "reference: {}" , reference_time) ;
37
37
38
- let mut cheat_candidates: HashSet < coord:: Coord > = HashSet :: new ( ) ;
39
-
40
- for p in path. iter ( ) {
41
- for v in vec ! [ UP , RIGHT , DOWN , LEFT ] . iter ( ) {
42
- let c = p. add ( * v) ;
43
-
44
- if path. contains ( & c) {
45
- continue ;
46
- }
47
-
48
- let tile = racetrack. at_coord ( c) . unwrap ( ) ;
49
-
50
- if * tile == '#' {
51
- cheat_candidates. insert ( c) ;
52
- }
53
- }
54
- }
38
+ let cheat_candidates = find_candidates ( & racetrack, & path) ;
55
39
56
40
println ! ( "candidates: {}" , cheat_candidates. len( ) ) ;
57
41
58
42
let mut total = 0 ;
59
43
60
44
for cheat_start_pos in cheat_candidates. iter ( ) {
61
- let res = find_path ( & racetrack, start, goal, * cheat_start_pos, 2 ) ;
45
+ let res = find_path ( & racetrack, start, goal, & path , * cheat_start_pos, 2 ) ;
62
46
63
47
match res {
64
48
Some ( ( _, picoseconds) ) => {
@@ -82,30 +66,14 @@ fn main() -> Result<()> {
82
66
83
67
println ! ( "reference: {}" , reference_time) ;
84
68
85
- let mut cheat_candidates: HashSet < coord:: Coord > = HashSet :: new ( ) ;
86
-
87
- for p in path. iter ( ) {
88
- for v in vec ! [ UP , RIGHT , DOWN , LEFT ] . iter ( ) {
89
- let c = p. add ( * v) ;
90
-
91
- if path. contains ( & c) {
92
- continue ;
93
- }
94
-
95
- let tile = racetrack. at_coord ( c) . unwrap ( ) ;
96
-
97
- if * tile == '#' {
98
- cheat_candidates. insert ( c) ;
99
- }
100
- }
101
- }
69
+ let cheat_candidates = find_candidates ( & racetrack, & path) ;
102
70
103
71
println ! ( "candidates: {}" , cheat_candidates. len( ) ) ;
104
72
105
73
let mut total = 0 ;
106
74
107
75
for cheat_start_pos in cheat_candidates. iter ( ) {
108
- let res = find_path ( & racetrack, start, goal, * cheat_start_pos, 20 ) ;
76
+ let res = find_path ( & racetrack, start, goal, & path , * cheat_start_pos, 20 ) ;
109
77
110
78
match res {
111
79
Some ( ( _, picoseconds) ) => {
@@ -124,10 +92,33 @@ fn main() -> Result<()> {
124
92
Ok ( ( ) )
125
93
}
126
94
95
+ fn find_candidates ( m : & matrix:: Matrix < char > , path : & Vec < coord:: Coord > ) -> HashSet < coord:: Coord > {
96
+ let mut cheat_candidates: HashSet < coord:: Coord > = HashSet :: new ( ) ;
97
+
98
+ for p in path. iter ( ) {
99
+ for v in vec ! [ UP , RIGHT , DOWN , LEFT ] . iter ( ) {
100
+ let c = p. add ( * v) ;
101
+
102
+ if path. contains ( & c) {
103
+ continue ;
104
+ }
105
+
106
+ let tile = m. at_coord ( c) . unwrap ( ) ;
107
+
108
+ if * tile == '#' {
109
+ cheat_candidates. insert ( c) ;
110
+ }
111
+ }
112
+ }
113
+
114
+ return cheat_candidates;
115
+ }
116
+
127
117
#[ derive( Eq , PartialEq , Hash , Clone ) ]
128
118
struct Pos {
129
119
node : coord:: Coord ,
130
120
remaining : i32 ,
121
+ cheat_enabled : bool ,
131
122
}
132
123
133
124
fn find_reference (
@@ -165,60 +156,91 @@ fn find_reference(
165
156
166
157
fn cheated_successors (
167
158
m : & matrix:: Matrix < char > ,
159
+ reference_path : & Vec < coord:: Coord > ,
168
160
n : & Pos ,
169
161
cheat_pos : coord:: Coord ,
170
162
remaining : i32 ,
171
163
) -> Vec < ( Pos , i32 ) > {
172
- vec ! [ UP , RIGHT , DOWN , LEFT ]
173
- . into_iter ( )
174
- . map ( |v| n. node . add ( v) )
175
- . filter ( |c| {
176
- if !m. in_coord ( * c) {
177
- return false ;
178
- }
164
+ let mut res: Vec < ( Pos , i32 ) > = Vec :: new ( ) ;
179
165
180
- if * c == cheat_pos {
181
- return true ;
182
- }
166
+ for v in vec ! [ UP , RIGHT , DOWN , LEFT ] {
167
+ let next_pos = n. node . add ( v) ;
183
168
184
- if n. remaining > 0 {
185
- return true ;
186
- }
169
+ // skip out of bounds
170
+ if !m. in_coord ( next_pos) {
171
+ continue ;
172
+ }
187
173
188
- let tile = m. at_coord ( * c) ;
189
- match tile {
190
- Some ( v) => return * v != '#' ,
191
- None => return false ,
192
- }
193
- } )
194
- . map ( |c| {
195
- if c == cheat_pos {
196
- return ( Pos { node : c, remaining } , 1 ) ;
174
+ // activate cheat
175
+ if next_pos == cheat_pos {
176
+ res. push ( (
177
+ Pos {
178
+ node : next_pos,
179
+ remaining : remaining - 1 ,
180
+ cheat_enabled : true ,
181
+ } ,
182
+ 1 ,
183
+ ) ) ;
184
+ continue ;
185
+ }
186
+
187
+ // cheat activated
188
+ if n. cheat_enabled == true && n. remaining > 0 {
189
+ // deactivate cheat
190
+ if reference_path. contains ( & next_pos) {
191
+ res. push ( (
192
+ Pos {
193
+ node : next_pos,
194
+ remaining : 0 ,
195
+ cheat_enabled : false ,
196
+ } ,
197
+ 1 ,
198
+ ) ) ;
199
+ } else {
200
+ res. push ( (
201
+ Pos {
202
+ node : next_pos,
203
+ remaining : n. remaining - 1 ,
204
+ cheat_enabled : true ,
205
+ } ,
206
+ 1 ,
207
+ ) ) ;
197
208
}
198
- (
209
+ continue ;
210
+ }
211
+
212
+ // normal detection
213
+ let tile = m. at_coord ( next_pos) . unwrap ( ) ;
214
+ if * tile != '#' {
215
+ res. push ( (
199
216
Pos {
200
- node : c,
201
- remaining : n. remaining - 1 ,
217
+ node : next_pos,
218
+ remaining : 0 ,
219
+ cheat_enabled : false ,
202
220
} ,
203
221
1 ,
204
- )
205
- } )
206
- . collect ( )
222
+ ) ) ;
223
+ }
224
+ }
225
+
226
+ return res;
207
227
}
208
228
209
229
fn find_path (
210
230
m : & matrix:: Matrix < char > ,
211
231
start : coord:: Coord ,
212
232
goal : coord:: Coord ,
233
+ reference_path : & Vec < coord:: Coord > ,
213
234
cheat_pos : coord:: Coord ,
214
235
cheat_dur : i32 ,
215
236
) -> Option < ( Vec < Pos > , i32 ) > {
216
237
astar (
217
238
& Pos {
218
239
node : start,
219
240
remaining : 0 ,
241
+ cheat_enabled : false ,
220
242
} ,
221
- |n| cheated_successors ( m, n, cheat_pos, cheat_dur) ,
243
+ |n| cheated_successors ( m, reference_path , n, cheat_pos, cheat_dur) ,
222
244
|n| {
223
245
let dist = n. node . distance ( goal) ;
224
246
return dist. x . abs ( ) + dist. y . abs ( ) ;
0 commit comments