@@ -11,6 +11,7 @@ pub struct Day16 {
1111 end : usize ,
1212 offsets : [ isize ; 4 ] ,
1313 cheapest : Vec < [ u32 ; 4 ] > ,
14+ turned : Vec < u8 > ,
1415 part1 : u32 ,
1516}
1617
@@ -49,6 +50,7 @@ impl Day16 {
4950
5051 let mut instance = Self {
5152 cheapest : vec ! [ [ u32 :: MAX ; 4 ] ; grid. len( ) ] ,
53+ turned : vec ! [ 0 ; grid. len( ) ] ,
5254 part1 : 0 ,
5355 grid,
5456 start,
@@ -77,17 +79,30 @@ impl Day16 {
7779 return true ;
7880 }
7981
80- for ( next_dir, next_score) in [
81- ( dir, score + 1 ) ,
82- ( ( dir + 1 ) % 4 , score + 1001 ) ,
83- ( ( dir + 3 ) % 4 , score + 1001 ) ,
84- ] {
85- let next = index. wrapping_add_signed ( self . offsets [ next_dir] ) ;
86- // Advancing to the next branch each time instead of the neighbor reduces the number
87- // of items pushed to the priority queue significantly
88- if let Some ( branch) = self . find_branch ( next, next_dir, next_score) {
89- // Reverse needed to use BinaryHeap as a min heap and order by the lowest score
90- queue. push ( Reverse ( branch) ) ;
82+ // Advancing to the next branch each time instead of the neighbor reduces the number
83+ // of items pushed to the priority queue significantly
84+ if let Some ( branch) =
85+ self . find_branch ( index. wrapping_add_signed ( self . offsets [ dir] ) , dir, score + 1 )
86+ {
87+ // Reverse needed to use BinaryHeap as a min heap and order by the lowest score
88+ queue. push ( Reverse ( branch) ) ;
89+ }
90+
91+ for next_dir in [ ( dir + 1 ) % 4 , ( dir + 3 ) % 4 ] {
92+ // Only turn if it will be the cheapest way to reach the turned state
93+ if score + 1000 < self . cheapest [ index] [ next_dir] {
94+ self . cheapest [ index] [ next_dir] = score + 1000 ;
95+ // Store that this state was reached by turning, not by traversing tiles heading
96+ // in the next direction to allow reversing the path correctly
97+ self . turned [ index] |= 1 << next_dir;
98+
99+ if let Some ( branch) = self . find_branch (
100+ index. wrapping_add_signed ( self . offsets [ next_dir] ) ,
101+ next_dir,
102+ score + 1001 ,
103+ ) {
104+ queue. push ( Reverse ( branch) ) ;
105+ }
91106 }
92107 }
93108 }
@@ -129,9 +144,15 @@ impl Day16 {
129144 dir = next_dir;
130145 }
131146
132- if score < self . cheapest [ index] [ dir] {
147+ if score <= self . cheapest [ index] [ dir] {
133148 self . cheapest [ index] [ dir] = score;
149+ self . turned [ index] &= !( 1 << dir) ;
134150 Some ( ( score, index, dir) )
151+ } else if score == self . cheapest [ index] [ dir] {
152+ // Ensure the new state isn't marked as only reachable by turning, which would prevent
153+ // this segment from being included when reversing
154+ self . turned [ index] &= !( 1 << dir) ;
155+ None
135156 } else {
136157 None
137158 }
@@ -185,7 +206,9 @@ impl Day16 {
185206 ( ( dir + 1 ) % 4 , score - 1000 ) ,
186207 ( ( dir + 3 ) % 4 , score - 1000 ) ,
187208 ] {
188- if self . cheapest [ index] [ next_dir] == next_score {
209+ if self . cheapest [ index] [ next_dir] == next_score
210+ && self . turned [ index] & 1 << next_dir == 0
211+ {
189212 self . reverse (
190213 index. wrapping_add_signed ( -self . offsets [ next_dir] ) ,
191214 next_dir,
0 commit comments