1+ use object_pool:: Pool ;
12use std:: collections:: VecDeque ;
23
34use mygrid:: {
45 direction:: { Direction , DOWN , LEFT , RIGHT , UP } ,
56 grid:: Grid ,
6- point:: Point ,
77} ;
88
99advent_of_code:: solution!( 16 ) ;
1010
11+ #[ inline]
12+ fn dir_to_index ( dir : Direction ) -> usize {
13+ match dir {
14+ RIGHT => 0 ,
15+ DOWN => 1 ,
16+ LEFT => 2 ,
17+ UP => 3 ,
18+ _ => unreachable ! ( ) ,
19+ }
20+ }
21+
1122pub fn part_one ( input : & str ) -> Option < u64 > {
1223 let ( grid, start) = Grid :: new_from_str_capture_start ( input, & |c| c, & |c| c == 'S' ) ;
13- let target_pos = grid
14- . iter_item_and_position ( )
15- . filter ( |& ( _, c) | * c == 'E' )
16- . map ( |( p, _) | p)
17- . next ( )
18- . unwrap ( ) ;
19-
20- #[ derive( Debug , PartialEq , Eq ) ]
21- struct State {
22- pos : Point ,
23- dir : Direction ,
24- cost : u64 ,
25- }
24+ let target_pos = grid. find_position_of ( & 'E' ) . unwrap ( ) ;
2625
2726 let mut q = VecDeque :: new ( ) ;
28- q. push_back ( State {
29- pos : start,
30- dir : RIGHT ,
31- cost : 0 ,
32- } ) ;
27+ q. push_back ( ( start, RIGHT , 0 ) ) ;
3328
3429 let mut best_cost_grid = Grid :: new ( grid. width , grid. height , [ u64:: MAX ; 4 ] ) ;
35- let dir_to_index = |d : Direction | match d {
36- RIGHT => 0 ,
37- DOWN => 1 ,
38- LEFT => 2 ,
39- UP => 3 ,
40- _ => unreachable ! ( ) ,
41- } ;
4230
43- while let Some ( s ) = q. pop_front ( ) {
44- if s . pos == target_pos {
45- best_cost_grid[ s . pos ] [ dir_to_index ( s . dir ) ] = s . cost ;
31+ while let Some ( ( pos , dir , cost ) ) = q. pop_front ( ) {
32+ if pos == target_pos {
33+ best_cost_grid[ pos] [ dir_to_index ( dir) ] = cost;
4634 continue ;
4735 }
4836
49- let right = s . dir . rotate_clockwise ( ) ;
50- let left = s . dir . rotate_counterclockwise ( ) ;
37+ let right = dir. rotate_clockwise ( ) ;
38+ let left = dir. rotate_counterclockwise ( ) ;
5139
5240 for & ( pos, dir, cost) in [
53- ( s . pos + s . dir , s . dir , s . cost + 1 ) ,
54- ( s . pos + right, right, s . cost + 1000 + 1 ) ,
55- ( s . pos + left, left, s . cost + 1000 + 1 ) ,
41+ ( pos + dir, dir, cost + 1 ) ,
42+ ( pos + right, right, cost + 1000 + 1 ) ,
43+ ( pos + left, left, cost + 1000 + 1 ) ,
5644 ]
5745 . iter ( )
5846 {
@@ -65,85 +53,54 @@ pub fn part_one(input: &str) -> Option<u64> {
6553 }
6654 best_cost_grid[ pos] [ dir_to_index ( dir) ] = cost;
6755
68- let new_state = State { pos, dir, cost } ;
69- q. push_back ( new_state) ;
56+ q. push_back ( ( pos, dir, cost) ) ;
7057 }
7158 }
7259
7360 let min_cost = * best_cost_grid[ target_pos] . iter ( ) . min ( ) . unwrap ( ) ;
7461 Some ( min_cost)
7562}
7663
77- #[ inline]
78- fn dir_to_index ( dir : Direction ) -> usize {
79- match dir {
80- RIGHT => 0 ,
81- DOWN => 1 ,
82- LEFT => 2 ,
83- UP => 3 ,
84- _ => unreachable ! ( ) ,
85- }
86- }
87-
8864pub fn part_two ( input : & str ) -> Option < u64 > {
8965 let ( grid, start) = Grid :: new_from_str_capture_start ( input, & |c| c, & |c| c == 'S' ) ;
90- let target_pos = grid
91- . iter_item_and_position ( )
92- . filter ( |& ( _, c) | * c == 'E' )
93- . map ( |( p, _) | p)
94- . next ( )
95- . unwrap ( ) ;
96-
97- use object_pool:: { Pool , Reusable } ;
98-
99- struct State < ' a > {
100- path : Reusable < ' a , Vec < Point > > ,
101- pos : Point ,
102- dir : Direction ,
103- cost : u64 ,
104- }
66+ let target_pos = grid. find_position_of ( & 'E' ) . unwrap ( ) ;
10567
10668 const PATH_CAPACITY : usize = 512 ;
10769 let path_pool = Pool :: new ( 256 , || Vec :: with_capacity ( PATH_CAPACITY ) ) ;
10870 let mut path = path_pool. pull ( || Vec :: with_capacity ( PATH_CAPACITY ) ) ;
10971 path. push ( start) ;
11072
11173 let mut q = VecDeque :: new ( ) ;
112- q. push_back ( State {
113- path,
114- pos : start,
115- dir : RIGHT ,
116- cost : 0 ,
117- } ) ;
74+ q. push_back ( ( path, start, RIGHT , 0 ) ) ;
11875
11976 let base_false_grid = Grid :: new ( grid. width , grid. height , false ) ;
12077 let mut best_spots_grid = base_false_grid. clone ( ) ;
12178 let mut best_target_cost = u64:: MAX ;
12279 let mut best_cost_grid = Grid :: new ( grid. width , grid. height , [ u64:: MAX ; 4 ] ) ;
12380
124- while let Some ( mut s ) = q. pop_front ( ) {
125- if s . pos == target_pos {
126- if best_target_cost < s . cost {
81+ while let Some ( ( mut path , pos , dir , cost ) ) = q. pop_front ( ) {
82+ if pos == target_pos {
83+ if best_target_cost < cost {
12784 continue ;
12885 }
12986
13087 // reset best_spots_grid if we found a better path
131- if best_target_cost > s . cost {
88+ if best_target_cost > cost {
13289 best_spots_grid = base_false_grid. clone ( ) ;
13390 }
13491
135- for & p in s . path . iter ( ) {
92+ for & p in path. iter ( ) {
13693 best_spots_grid[ p] = true ;
13794 }
13895
139- best_target_cost = s . cost ;
96+ best_target_cost = cost;
14097 continue ;
14198 }
14299
143- best_cost_grid[ s . pos ] [ dir_to_index ( s . dir ) ] = s . cost ;
100+ best_cost_grid[ pos] [ dir_to_index ( dir) ] = cost;
144101
145- let right = s . dir . rotate_clockwise ( ) ;
146- let left = s . dir . rotate_counterclockwise ( ) ;
102+ let right = dir. rotate_clockwise ( ) ;
103+ let left = dir. rotate_counterclockwise ( ) ;
147104 let is_viable = |& ( pos, dir, cost) | {
148105 if grid[ pos] == '#' {
149106 return false ;
@@ -159,9 +116,9 @@ pub fn part_two(input: &str) -> Option<u64> {
159116 } ;
160117
161118 let all_options = [
162- ( s . pos + s . dir , s . dir , s . cost + 1 ) ,
163- ( s . pos + left, left, s . cost + 1000 + 1 ) ,
164- ( s . pos + right, right, s . cost + 1000 + 1 ) ,
119+ ( pos + dir, dir, cost + 1 ) ,
120+ ( pos + left, left, cost + 1000 + 1 ) ,
121+ ( pos + right, right, cost + 1000 + 1 ) ,
165122 ] ;
166123
167124 let viable_options = [
@@ -177,11 +134,8 @@ pub fn part_two(input: &str) -> Option<u64> {
177134 1 => {
178135 let idx = viable_options. iter ( ) . position ( |& b| b) . unwrap ( ) ;
179136 let ( pos, dir, cost) = all_options[ idx] ;
180- s. path . push ( pos) ;
181- s. cost = cost;
182- s. pos = pos;
183- s. dir = dir;
184- q. push_back ( s) ;
137+ path. push ( pos) ;
138+ q. push_back ( ( path, pos, dir, cost) ) ;
185139 }
186140 _ => viable_options
187141 . iter ( )
@@ -193,15 +147,9 @@ pub fn part_two(input: &str) -> Option<u64> {
193147
194148 let ( pos, dir, cost) = all_options[ idx] ;
195149 let mut new_path = path_pool. pull ( || Vec :: with_capacity ( PATH_CAPACITY ) ) ;
196- new_path. clone_from ( & s . path ) ;
150+ new_path. clone_from ( & path) ;
197151 new_path. push ( pos) ;
198- let new_state = State {
199- path : new_path,
200- pos,
201- dir,
202- cost,
203- } ;
204- q. push_back ( new_state) ;
152+ q. push_back ( ( new_path, pos, dir, cost) ) ;
205153 } ) ,
206154 }
207155 }
0 commit comments