Skip to content

Commit ef92df2

Browse files
committed
Optimize 2024 day 16
Only check branches at junctions if the score is cheaper than the existing score
1 parent 71e45d7 commit ef92df2

File tree

1 file changed

+36
-13
lines changed

1 file changed

+36
-13
lines changed

crates/year2024/src/day16.rs

Lines changed: 36 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)