@@ -9,9 +9,29 @@ pub mod part1 {
9
9
pub fn solve ( wires : Vec < WireDescription > ) -> Result < u32 > {
10
10
let ( first, second) = ( wires[ 0 ] . clone ( ) , wires[ 1 ] . clone ( ) ) ;
11
11
let mut index = WireIndex :: new ( first. into ( ) ) ;
12
- let intersection = index. find_closest_intersection ( second) ;
13
- if let Some ( intersection) = intersection {
14
- return Ok ( manhattan_distance ( intersection) ) ;
12
+ let intersection = index. find_best_intersection ( second, manhattan_distance) ;
13
+ if let Some ( ( a, b) ) = intersection {
14
+ return Ok ( manhattan_distance ( & a, & b) ) ;
15
+ } else {
16
+ bail ! ( "No intersections!" ) ;
17
+ }
18
+ }
19
+ }
20
+
21
+ pub mod part2 {
22
+ use anyhow:: * ;
23
+ use super :: * ;
24
+
25
+ // NOTE(pi):
26
+ // This doesn't handle the following clause from the rules:
27
+ // - If a wire visits a position on the grid multiple times, use the steps value from the first time it visits that position when calculating the total value of a specific intersection.
28
+ // This just happened not to come up in the input.
29
+ pub fn solve ( wires : Vec < WireDescription > ) -> Result < u32 > {
30
+ let ( first, second) = ( wires[ 0 ] . clone ( ) , wires[ 1 ] . clone ( ) ) ;
31
+ let mut index = WireIndex :: new ( first. into ( ) ) ;
32
+ let intersection = index. find_best_intersection ( second, signal_delay) ;
33
+ if let Some ( ( a, b) ) = intersection {
34
+ return Ok ( signal_delay ( & a, & b) ) ;
15
35
} else {
16
36
bail ! ( "No intersections!" ) ;
17
37
}
@@ -21,13 +41,26 @@ pub mod part1 {
21
41
#[ derive( Clone , Debug , PartialEq , Eq ) ]
22
42
pub enum Direction { H , V }
23
43
24
- #[ derive( Clone , Debug ) ]
44
+ impl Default for Direction {
45
+ fn default ( ) -> Self {
46
+ Direction :: H
47
+ }
48
+ }
49
+
50
+ #[ derive( Clone , Debug , Default ) ]
25
51
pub struct Line {
26
52
dir : Direction ,
53
+ signal_delay : u32 ,
27
54
c : i32 ,
28
55
range : ( i32 , i32 )
29
56
}
30
57
58
+ impl Line {
59
+ pub fn len ( & self ) -> u32 {
60
+ ( self . range . 0 - self . range . 1 ) . abs ( ) as u32
61
+ }
62
+ }
63
+
31
64
impl PartialEq for Line {
32
65
fn eq ( & self , other : & Self ) -> bool {
33
66
self . dir == other. dir && self . c == other. c && self . range == other. range
@@ -52,12 +85,18 @@ pub enum Instruction {
52
85
}
53
86
54
87
impl Instruction {
55
- pub fn follow ( & self , ( sx, sy) : ( i32 , i32 ) ) -> ( Line , ( i32 , i32 ) ) {
88
+ pub fn len ( & self ) -> u32 {
89
+ use Instruction :: * ;
90
+ match self {
91
+ Right ( l) | Left ( l) | Up ( l) | Down ( l) => l. abs ( ) as u32 ,
92
+ }
93
+ }
94
+ pub fn follow ( & self , signal_delay : u32 , ( sx, sy) : ( i32 , i32 ) ) -> ( Line , ( i32 , i32 ) ) {
56
95
match & self {
57
- Instruction :: Right ( x) => ( Line { dir : Direction :: H , c : sy, range : ( sx, sx + x) } , ( sx + x, sy) ) ,
58
- Instruction :: Left ( x) => ( Line { dir : Direction :: H , c : sy, range : ( sx, sx - x) } , ( sx - x, sy) ) ,
59
- Instruction :: Up ( y) => ( Line { dir : Direction :: V , c : sx, range : ( sy, sy + y ) } , ( sx, sy + y) ) ,
60
- Instruction :: Down ( y) => ( Line { dir : Direction :: V , c : sx, range : ( sy, sy - y ) } , ( sx, sy - y) ) ,
96
+ Instruction :: Right ( x) => ( Line { dir : Direction :: H , signal_delay , c : sy, range : ( sx, sx + x) } , ( sx + x, sy) ) ,
97
+ Instruction :: Left ( x) => ( Line { dir : Direction :: H , signal_delay , c : sy, range : ( sx, sx - x) } , ( sx - x, sy) ) ,
98
+ Instruction :: Up ( y) => ( Line { dir : Direction :: V , signal_delay , c : sx, range : ( sy, sy + y ) } , ( sx, sy + y) ) ,
99
+ Instruction :: Down ( y) => ( Line { dir : Direction :: V , signal_delay , c : sx, range : ( sy, sy - y ) } , ( sx, sy - y) ) ,
61
100
}
62
101
}
63
102
}
@@ -102,8 +141,10 @@ impl From<WireDescription> for Wire {
102
141
103
142
let ( mut cx, mut cy) = ( 0 , 0 ) ;
104
143
let mut segments = vec ! [ ] ;
144
+ let mut signal_delay = 0 ;
105
145
for i in desc. instructions {
106
- let ( segment, ( nx, ny) ) = i. follow ( ( cx, cy) ) ;
146
+ let ( segment, ( nx, ny) ) = i. follow ( signal_delay, ( cx, cy) ) ;
147
+ signal_delay += segment. len ( ) ;
107
148
cx = nx;
108
149
cy = ny;
109
150
segments. push ( segment) ;
@@ -147,10 +188,22 @@ struct WireIndex {
147
188
vertical_lines : SplitVec < Line > ,
148
189
cx : i32 ,
149
190
cy : i32 ,
191
+ signal_delay : u32 ,
192
+ }
193
+
194
+ pub fn manhattan_distance ( a : & Line , b : & Line ) -> u32 {
195
+ // |
196
+ // H: +----x--------+ (a.c, (a.range.0, a.range.1))
197
+ // |
198
+ // + (b.c, (b.range.0, b.range.1))
199
+ // The lines intersect at (a.c, b.c)
200
+ return ( a. c . abs ( ) + b. c . abs ( ) ) as u32
150
201
}
151
202
152
- pub fn manhattan_distance ( ( x, y) : ( i32 , i32 ) ) -> u32 {
153
- ( x. abs ( ) + y. abs ( ) ) as u32
203
+ pub fn signal_delay ( a : & Line , b : & Line ) -> u32 {
204
+ let delay_for_a_at_point = a. signal_delay + ( b. c - a. range . 0 ) . abs ( ) as u32 ;
205
+ let delay_for_b_at_point = b. signal_delay + ( a. c - b. range . 0 ) . abs ( ) as u32 ;
206
+ return delay_for_a_at_point + delay_for_b_at_point;
154
207
}
155
208
156
209
impl WireIndex {
@@ -168,13 +221,15 @@ impl WireIndex {
168
221
}
169
222
}
170
223
return WireIndex {
171
- horizontal_lines : SplitVec :: from ( horizontal_lines, Line { dir : Direction :: H , c : 0 , range : ( 0 , 0 ) } ) ,
172
- vertical_lines : SplitVec :: from ( vertical_lines, Line { dir : Direction :: V , c : 0 , range : ( 0 , 0 ) } ) ,
173
- cx : 0 , cy : 0 ,
224
+ horizontal_lines : SplitVec :: from ( horizontal_lines, Line { dir : Direction :: H , signal_delay : 0 , c : 0 , range : ( 0 , 0 ) } ) ,
225
+ vertical_lines : SplitVec :: from ( vertical_lines, Line { dir : Direction :: V , signal_delay : 0 , c : 0 , range : ( 0 , 0 ) } ) ,
226
+ cx : 0 , cy : 0 , signal_delay : 0 ,
174
227
}
175
228
}
176
229
177
- pub fn ingest_instruction ( & mut self , i : Instruction ) -> Option < ( i32 , i32 ) > {
230
+ pub fn ingest_instruction < F > ( & mut self , i : Instruction , metric : F ) -> Option < ( Line , Line ) >
231
+ where
232
+ F : Fn ( & Line , & Line ) -> u32 {
178
233
// Keep track of the closest intersection we've seen so far
179
234
let mut closest = None ;
180
235
@@ -189,6 +244,8 @@ impl WireIndex {
189
244
let new_coord = match i { Left ( _) | Down ( _) => current_coord - dist, Right ( _) | Up ( _) => current_coord + dist } ;
190
245
// If we're scanning "down" a list, stop when we hit zero, otherwise stop when we hit the end of the array
191
246
let stop_condition = match i { Left ( _) | Down ( _) => 0 , Right ( _) | Up ( _) => lines. elements . len ( ) } ;
247
+ let dir = match i { Left ( _) | Right ( _) => Direction :: H , Up ( _) | Down ( _) => Direction :: V } ;
248
+ let traveling_line = Line { c : traveling_along, dir, signal_delay : self . signal_delay , range : ( current_coord, new_coord) } ;
192
249
193
250
loop {
194
251
if lines. split == stop_condition {
@@ -218,10 +275,9 @@ impl WireIndex {
218
275
continue ;
219
276
}
220
277
221
- let intersection = match i { Left ( _) | Right ( _) => ( line. c , traveling_along) , Up ( _) | Down ( _) => ( traveling_along, line. c ) } ;
222
278
closest = match closest {
223
- None if manhattan_distance ( intersection ) != 0 => Some ( intersection ) ,
224
- Some ( closest ) if manhattan_distance ( intersection ) < manhattan_distance ( closest ) => Some ( intersection ) ,
279
+ None if metric ( & traveling_line , & line ) != 0 => Some ( ( traveling_line . clone ( ) , line . clone ( ) ) ) ,
280
+ Some ( ( a , b ) ) if metric ( & traveling_line , & line ) < metric ( & a , & b ) => Some ( ( traveling_line . clone ( ) , line . clone ( ) ) ) ,
225
281
_ => closest,
226
282
}
227
283
} else {
@@ -234,18 +290,21 @@ impl WireIndex {
234
290
Left ( _) | Right ( _) => self . cx = new_coord,
235
291
Up ( _) | Down ( _) => self . cy = new_coord,
236
292
}
293
+ self . signal_delay += traveling_line. len ( ) ;
237
294
238
295
return closest;
239
296
}
240
297
241
- pub fn find_closest_intersection ( & mut self , w : WireDescription ) -> Option < ( i32 , i32 ) > {
298
+ pub fn find_best_intersection < F > ( & mut self , w : WireDescription , metric : F ) -> Option < ( Line , Line ) >
299
+ where
300
+ F : Fn ( & Line , & Line ) -> u32 {
242
301
let mut closest = None ;
243
302
for instruction in w. instructions {
244
- let intersection = self . ingest_instruction ( instruction) ;
245
- if let Some ( intersection ) = intersection {
303
+ let intersection = self . ingest_instruction ( instruction, manhattan_distance ) ;
304
+ if let Some ( ( a , b ) ) = intersection {
246
305
closest = match closest {
247
- None if manhattan_distance ( intersection ) != 0 => Some ( intersection ) ,
248
- Some ( closest ) if manhattan_distance ( intersection ) < manhattan_distance ( closest ) => Some ( intersection ) ,
306
+ None if metric ( & a , & b ) != 0 => Some ( ( a , b ) ) ,
307
+ Some ( ( x , y ) ) if metric ( & a , & b ) < metric ( & x , & y ) => Some ( ( a , b ) ) ,
249
308
_ => closest,
250
309
}
251
310
}
@@ -296,28 +355,39 @@ mod tests {
296
355
297
356
#[ test]
298
357
fn test_manhattan_distance ( ) {
299
- assert_eq ! ( 2 , manhattan_distance( ( 1 , 1 ) ) ) ;
300
- assert_eq ! ( 2 , manhattan_distance( ( -1 , 1 ) ) ) ;
301
- assert_eq ! ( 2 , manhattan_distance( ( 1 , - 1 ) ) ) ;
302
- assert_eq ! ( 2 , manhattan_distance( ( -1 , - 1 ) ) ) ;
303
- assert_eq ! ( 10 , manhattan_distance( ( -5 , 5 ) ) ) ;
358
+ assert_eq ! ( 2 , manhattan_distance( & Line { c : 1 , .. Default :: default ( ) } , & Line { c : 1 , .. Default :: default ( ) } ) ) ;
359
+ assert_eq ! ( 2 , manhattan_distance( & Line { c : -1 , .. Default :: default ( ) } , & Line { c : 1 , .. Default :: default ( ) } ) ) ;
360
+ assert_eq ! ( 2 , manhattan_distance( & Line { c : 1 , .. Default :: default ( ) } , & Line { c : - 1 , .. Default :: default ( ) } ) ) ;
361
+ assert_eq ! ( 2 , manhattan_distance( & Line { c : -1 , .. Default :: default ( ) } , & Line { c : - 1 , .. Default :: default ( ) } ) ) ;
362
+ assert_eq ! ( 10 , manhattan_distance( & Line { c : -5 , .. Default :: default ( ) } , & Line { c : 5 , .. Default :: default ( ) } ) ) ;
304
363
}
305
364
306
365
#[ test]
307
366
pub fn test_wire_crossing ( ) {
308
367
let wire = "R8,U5,L5,D3" . parse :: < Wire > ( ) . unwrap ( ) ;
309
368
let mut index = WireIndex :: new ( wire) ;
310
- assert_matches ! ( index. ingest_instruction( Instruction :: Up ( 7 ) ) , None ) ;
311
- assert_matches ! ( index. ingest_instruction( Instruction :: Right ( 6 ) ) , None ) ;
312
- assert_matches ! ( index. ingest_instruction( Instruction :: Down ( 4 ) ) , Some ( ( 6 , 5 ) ) ) ;
313
- assert_matches ! ( index. ingest_instruction( Instruction :: Left ( 4 ) ) , Some ( ( 3 , 3 ) ) ) ;
369
+ assert_matches ! ( index. ingest_instruction( Instruction :: Up ( 7 ) , manhattan_distance ) , None ) ;
370
+ assert_matches ! ( index. ingest_instruction( Instruction :: Right ( 6 ) , manhattan_distance ) , None ) ;
371
+ assert_matches ! ( index. ingest_instruction( Instruction :: Down ( 4 ) , manhattan_distance ) , Some ( ( Line { c : 6 , .. } , Line { c : 5 , .. } ) ) ) ;
372
+ assert_matches ! ( index. ingest_instruction( Instruction :: Left ( 4 ) , manhattan_distance ) , Some ( ( Line { c : 3 , .. } , Line { c : 3 , .. } ) ) ) ;
314
373
}
315
374
316
375
#[ test]
317
376
pub fn test_closest_intersection ( ) {
318
377
let wire = "R8,U5,L5,D3" . parse :: < Wire > ( ) . unwrap ( ) ;
319
378
let mut index = WireIndex :: new ( wire) ;
320
379
let desc = "U7,R6,D4,L4" . parse :: < WireDescription > ( ) . unwrap ( ) ;
321
- assert_matches ! ( index. find_closest_intersection( desc) , Some ( ( 3 , 3 ) ) ) ;
380
+ assert_matches ! ( index. find_best_intersection( desc, manhattan_distance) , Some ( ( Line { c: 3 , .. } , Line { c: 3 , .. } ) ) ) ;
381
+ }
382
+
383
+ #[ test]
384
+ pub fn test_signal_delay ( ) {
385
+ let wire = "R8,U5,L5,D3" . parse :: < Wire > ( ) . unwrap ( ) ;
386
+ let mut index = WireIndex :: new ( wire) ;
387
+ let desc = "U7,R6,D4,L4" . parse :: < WireDescription > ( ) . unwrap ( ) ;
388
+ let intersection = index. find_best_intersection ( desc, signal_delay) ;
389
+ assert_matches ! ( intersection, Some ( ( Line { c: 6 , .. } , Line { c: 5 , .. } ) ) ) ;
390
+ let intersection = intersection. unwrap ( ) ;
391
+ assert_eq ! ( 30 , signal_delay( & intersection. 0 , & intersection. 1 ) ) ;
322
392
}
323
393
}
0 commit comments