Skip to content

Commit a1c0cb2

Browse files
committed
Improve 2024 day 16 backtracking
1 parent d117eb8 commit a1c0cb2

File tree

1 file changed

+23
-32
lines changed

1 file changed

+23
-32
lines changed

crates/year2024/src/day16.rs

Lines changed: 23 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ pub struct Day16 {
1111
end: usize,
1212
offsets: [isize; 4],
1313
cheapest: Vec<[u32; 4]>,
14-
turned: Vec<u8>,
1514
part1: u32,
1615
}
1716

@@ -50,7 +49,6 @@ impl Day16 {
5049

5150
let mut instance = Self {
5251
cheapest: vec![[u32::MAX; 4]; grid.len()],
53-
turned: vec![0; grid.len()],
5452
part1: 0,
5553
grid,
5654
start,
@@ -69,6 +67,7 @@ impl Day16 {
6967
fn dijkstra(&mut self) -> bool {
7068
let mut queue = BinaryHeap::new();
7169
queue.push(Reverse((0, self.start, 0)));
70+
self.cheapest[self.start][0] = 0;
7271

7372
while let Some(Reverse((score, index, dir))) = queue.pop() {
7473
if score > self.cheapest[index][dir] {
@@ -92,9 +91,6 @@ impl Day16 {
9291
// Only turn if it will be the cheapest way to reach the turned state
9392
if score + 1000 < self.cheapest[index][next_dir] {
9493
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;
9894

9995
if let Some(branch) = self.find_branch(
10096
index.wrapping_add_signed(self.offsets[next_dir]),
@@ -120,7 +116,17 @@ impl Day16 {
120116
return None;
121117
}
122118

123-
while index != self.end {
119+
loop {
120+
if score < self.cheapest[index][dir] {
121+
self.cheapest[index][dir] = score;
122+
} else if score > self.cheapest[index][dir] {
123+
return None;
124+
}
125+
126+
if index == self.end {
127+
break;
128+
}
129+
124130
let mut count = 0;
125131
let mut next_index = 0;
126132
let mut next_dir = 0;
@@ -144,18 +150,7 @@ impl Day16 {
144150
dir = next_dir;
145151
}
146152

147-
if score <= self.cheapest[index][dir] {
148-
self.cheapest[index][dir] = score;
149-
self.turned[index] &= !(1 << dir);
150-
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
156-
} else {
157-
None
158-
}
153+
Some((score, index, dir))
159154
}
160155

161156
#[must_use]
@@ -165,23 +160,23 @@ impl Day16 {
165160

166161
#[must_use]
167162
pub fn part2(&self) -> u32 {
168-
let mut on_best = vec![false; self.grid.len()];
169-
on_best[self.start] = true;
170-
on_best[self.end] = true;
163+
let mut on_best = vec![0u8; self.grid.len()];
164+
on_best[self.start] = 0b1111;
165+
on_best[self.end] = 0b1111;
171166
for d in 0..4 {
172167
if self.cheapest[self.end][d] == self.part1 {
173168
let prev = self.end.wrapping_add_signed(-self.offsets[d]);
174169
self.reverse(prev, d, self.part1 - 1, &mut on_best);
175170
}
176171
}
177-
on_best.iter().filter(|&&b| b).count() as u32
172+
on_best.iter().filter(|&&b| b != 0).count() as u32
178173
}
179174

180-
fn reverse(&self, index: usize, dir: usize, score: u32, on_best: &mut [bool]) {
181-
if on_best[index] {
175+
fn reverse(&self, index: usize, dir: usize, score: u32, on_best: &mut [u8]) {
176+
if on_best[index] & (1 << dir) != 0 {
182177
return;
183178
}
184-
on_best[index] = true;
179+
on_best[index] |= 1 << dir;
185180

186181
let mut count = 0;
187182
let mut next_index = 0;
@@ -206,15 +201,11 @@ impl Day16 {
206201
((dir + 1) % 4, score - 1000),
207202
((dir + 3) % 4, score - 1000),
208203
] {
204+
let next_index = index.wrapping_add_signed(-self.offsets[next_dir]);
209205
if self.cheapest[index][next_dir] == next_score
210-
&& self.turned[index] & (1 << next_dir) == 0
206+
&& self.cheapest[next_index][next_dir] == next_score - 1
211207
{
212-
self.reverse(
213-
index.wrapping_add_signed(-self.offsets[next_dir]),
214-
next_dir,
215-
next_score - 1,
216-
on_best,
217-
);
208+
self.reverse(next_index, next_dir, next_score - 1, on_best);
218209
}
219210
}
220211
}

0 commit comments

Comments
 (0)