1
+ use std:: collections:: BinaryHeap ;
2
+
3
+ use hashbrown:: HashMap ;
4
+ use nd_vec:: { vector, Vector } ;
5
+
1
6
use aoc_lib:: { direction:: Direction , matrix:: Matrix } ;
2
7
use common:: { solution, Answer } ;
3
- use hashbrown:: HashMap ;
4
- use nd_vec:: vector;
5
8
6
9
solution ! ( "Chiton" , 15 ) ;
7
10
11
+ type Point = Vector < usize , 2 > ;
12
+
8
13
fn part_a ( input : & str ) -> Answer {
9
14
let matrix = Matrix :: new_chars ( input, |chr| chr. to_digit ( 10 ) . unwrap ( ) as u8 ) ;
15
+ solve ( matrix. size , |pos| matrix. get ( pos) . copied ( ) ) . into ( )
16
+ }
17
+
18
+ fn part_b ( input : & str ) -> Answer {
19
+ let matrix = Matrix :: new_chars ( input, |chr| chr. to_digit ( 10 ) . unwrap ( ) as u8 ) ;
20
+ solve ( matrix. size * 5 , |pos| {
21
+ let ( cx, cy) = ( pos. x ( ) / matrix. size . x ( ) , pos. y ( ) / matrix. size . y ( ) ) ;
22
+ if cx > 4 || cy > 4 {
23
+ return None ;
24
+ } ;
25
+
26
+ let pos = vector ! ( pos. x( ) % matrix. size. x( ) , pos. y( ) % matrix. size. y( ) ) ;
27
+ matrix
28
+ . get ( pos)
29
+ . map ( |x| ( x + cx as u8 + cy as u8 - 1 ) % 9 + 1 )
30
+ } )
31
+ . into ( )
32
+ }
10
33
11
- let mut out = usize:: MAX ;
12
- let mut visited = HashMap :: new ( ) ;
13
- let mut queue = Vec :: new ( ) ;
14
- queue. push ( ( vector ! ( 0 , 0 ) , 0 ) ) ;
34
+ fn solve ( size : Point , get : impl Fn ( Point ) -> Option < u8 > ) -> u32 {
35
+ let mut seen = HashMap :: new ( ) ;
36
+ let mut queue = BinaryHeap :: new ( ) ;
15
37
16
- while let Some ( ( pos, cost) ) = queue. pop ( ) {
17
- if pos == matrix. size - vector ! ( 1 , 1 ) {
18
- out = out. min ( cost) ;
19
- continue ;
38
+ seen. insert ( vector ! ( 0 , 0 ) , 0 ) ;
39
+ queue. push ( QueueItem {
40
+ pos : vector ! ( 0 , 0 ) ,
41
+ distance : 0 ,
42
+ } ) ;
43
+
44
+ while let Some ( item) = queue. pop ( ) {
45
+ if item. pos == size - vector ! ( 1 , 1 ) {
46
+ return item. distance ;
20
47
}
21
48
22
- visited. insert ( pos, cost) ;
23
49
for dir in Direction :: ALL {
24
- if let Some ( ( next, new_cost) ) = dir
25
- . try_advance ( pos)
26
- . and_then ( |x| Some ( ( x, cost + * matrix. get ( x) ? as usize ) ) )
27
- {
28
- if let Some ( prev) = visited. get ( & next) {
29
- if * prev <= new_cost {
30
- continue ;
31
- }
32
- }
33
-
34
- queue. push ( ( next, new_cost) ) ;
50
+ let Some ( ( pos, cost) ) = dir. try_advance ( item. pos ) . and_then ( |x| Some ( ( x, get ( x) ?) ) )
51
+ else {
52
+ continue ;
53
+ } ;
54
+
55
+ let dist = seen. entry ( pos) . or_insert ( u32:: MAX ) ;
56
+ let next_dist = item. distance + cost as u32 ;
57
+
58
+ if next_dist < * dist {
59
+ * dist = next_dist;
60
+ queue. push ( QueueItem {
61
+ pos,
62
+ distance : next_dist,
63
+ } ) ;
35
64
}
36
65
}
37
66
}
38
67
39
- out. into ( )
68
+ unreachable ! ( )
69
+ }
70
+
71
+ #[ derive( PartialEq , Eq ) ]
72
+ struct QueueItem {
73
+ pos : Point ,
74
+ distance : u32 ,
40
75
}
41
76
42
- fn part_b ( _input : & str ) -> Answer {
43
- Answer :: Unimplemented
77
+ impl Ord for QueueItem {
78
+ fn cmp ( & self , other : & Self ) -> std:: cmp:: Ordering {
79
+ other. distance . cmp ( & self . distance )
80
+ }
81
+ }
82
+
83
+ impl PartialOrd for QueueItem {
84
+ fn partial_cmp ( & self , other : & Self ) -> Option < std:: cmp:: Ordering > {
85
+ Some ( self . cmp ( other) )
86
+ }
44
87
}
45
88
46
89
#[ cfg( test) ]
@@ -67,6 +110,6 @@ mod test {
67
110
68
111
#[ test]
69
112
fn part_b ( ) {
70
- assert_eq ! ( super :: part_b( CASE ) , ( ) . into( ) ) ;
113
+ assert_eq ! ( super :: part_b( CASE ) , 315 . into( ) ) ;
71
114
}
72
115
}
0 commit comments