Skip to content

Commit c402a9c

Browse files
committed
Fix cheat ending logic
1 parent e98a4d6 commit c402a9c

1 file changed

Lines changed: 33 additions & 8 deletions

File tree

day20/src/day20.rs

Lines changed: 33 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,12 @@ impl PartialOrd for Node {
4343
}
4444
}
4545

46+
#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)]
47+
enum CheatPolicy {
48+
Allowed,
49+
Forbidden,
50+
}
51+
4652
impl Racetrack {
4753
fn height(&self) -> i32 {
4854
self.rows.len() as i32
@@ -62,18 +68,24 @@ impl Racetrack {
6268
.find_map(|(y, row)| row.iter().enumerate().find(|(_, &cell)| cell == c).map(|(x, _)| Vec2::new(x as i32, y as i32)))
6369
}
6470

65-
fn shortest_path(&self, start: Vec2<i32>, end: Vec2<i32>) -> Option<Node> {
71+
/// Finds paths through the racetrack, ordered ascendingly by total picoseconds.
72+
fn find_paths(&self, start: Vec2<i32>, end: Vec2<i32>, cheat_policy: CheatPolicy, condition: impl Fn(Node) -> bool) -> Vec<Node> {
6673
// Your run-of-the-mill Dijkstra implementation
6774

6875
let mut queue = BinaryHeap::new();
6976
let mut visited = HashSet::new();
77+
let mut paths = Vec::new();
7078

7179
queue.push(Node { pos: start, picos: 0, cheat: None });
7280
visited.insert((start, None));
7381

7482
while let Some(node) = queue.pop() {
7583
if node.pos == end {
76-
return Some(node);
84+
// dbg!(paths.len(), node.picos);
85+
paths.push(node);
86+
if !condition(node) {
87+
break;
88+
}
7789
}
7890

7991
for dy in -1..=1 {
@@ -83,11 +95,16 @@ impl Racetrack {
8395
if self.in_bounds(neigh) {
8496
let is_wall = self[neigh] == '#';
8597

86-
let can_cheat = node.cheat.map_or(true, |c| c.picos_left > 0);
98+
let cheats_allowed = cheat_policy == CheatPolicy::Allowed;
99+
let can_cheat = cheats_allowed && node.cheat.map_or(true, |c| c.picos_left > 0);
87100
let new_cheat = if let Some(cheat) = node.cheat {
88-
Some(Cheat { start: cheat.start, end: if cheat.picos_left == 1 { Some(neigh) } else { cheat.end }, picos_left: (cheat.picos_left - 1).max(0) })
89-
} else if is_wall {
90-
Some(Cheat { start: neigh, end: None, picos_left: 1 })
101+
let is_ending = cheat.picos_left == 1;
102+
if is_ending && is_wall {
103+
continue;
104+
}
105+
Some(Cheat { start: cheat.start, end: if is_ending { Some(neigh) } else { cheat.end }, picos_left: (cheat.picos_left - 1).max(0) })
106+
} else if cheats_allowed && is_wall {
107+
Some(Cheat { start: node.pos, end: None, picos_left: 1 })
91108
} else {
92109
node.cheat
93110
};
@@ -102,7 +119,7 @@ impl Racetrack {
102119
}
103120
}
104121

105-
None
122+
paths
106123
}
107124
}
108125

@@ -127,5 +144,13 @@ fn main() {
127144
let start = track.locate('S').unwrap();
128145
let end = track.locate('E').unwrap();
129146

130-
println!("Shortest: {:?}", track.shortest_path(start, end).unwrap());
147+
let shortest_path = track.find_paths(start, end, CheatPolicy::Forbidden, |_| false)[0];
148+
let base_picos = shortest_path.picos;
149+
150+
let paths = track.find_paths(start, end, CheatPolicy::Allowed, |_| true);
151+
// let part1 = paths.len();
152+
153+
for p in paths.iter().take(20).map(|n| (base_picos - n.picos, n.cheat)) {
154+
println!("{p:?}");
155+
}
131156
}

0 commit comments

Comments
 (0)