Skip to content

Commit 6d32ea2

Browse files
committed
try harder
1 parent b2c3224 commit 6d32ea2

File tree

1 file changed

+87
-65
lines changed

1 file changed

+87
-65
lines changed

Diff for: day-20/main.rs

+87-65
Original file line numberDiff line numberDiff line change
@@ -35,30 +35,14 @@ fn main() -> Result<()> {
3535

3636
println!("reference: {}", reference_time);
3737

38-
let mut cheat_candidates: HashSet<coord::Coord> = HashSet::new();
39-
40-
for p in path.iter() {
41-
for v in vec![UP, RIGHT, DOWN, LEFT].iter() {
42-
let c = p.add(*v);
43-
44-
if path.contains(&c) {
45-
continue;
46-
}
47-
48-
let tile = racetrack.at_coord(c).unwrap();
49-
50-
if *tile == '#' {
51-
cheat_candidates.insert(c);
52-
}
53-
}
54-
}
38+
let cheat_candidates = find_candidates(&racetrack, &path);
5539

5640
println!("candidates: {}", cheat_candidates.len());
5741

5842
let mut total = 0;
5943

6044
for cheat_start_pos in cheat_candidates.iter() {
61-
let res = find_path(&racetrack, start, goal, *cheat_start_pos, 2);
45+
let res = find_path(&racetrack, start, goal, &path, *cheat_start_pos, 2);
6246

6347
match res {
6448
Some((_, picoseconds)) => {
@@ -82,30 +66,14 @@ fn main() -> Result<()> {
8266

8367
println!("reference: {}", reference_time);
8468

85-
let mut cheat_candidates: HashSet<coord::Coord> = HashSet::new();
86-
87-
for p in path.iter() {
88-
for v in vec![UP, RIGHT, DOWN, LEFT].iter() {
89-
let c = p.add(*v);
90-
91-
if path.contains(&c) {
92-
continue;
93-
}
94-
95-
let tile = racetrack.at_coord(c).unwrap();
96-
97-
if *tile == '#' {
98-
cheat_candidates.insert(c);
99-
}
100-
}
101-
}
69+
let cheat_candidates = find_candidates(&racetrack, &path);
10270

10371
println!("candidates: {}", cheat_candidates.len());
10472

10573
let mut total = 0;
10674

10775
for cheat_start_pos in cheat_candidates.iter() {
108-
let res = find_path(&racetrack, start, goal, *cheat_start_pos, 20);
76+
let res = find_path(&racetrack, start, goal, &path, *cheat_start_pos, 20);
10977

11078
match res {
11179
Some((_, picoseconds)) => {
@@ -124,10 +92,33 @@ fn main() -> Result<()> {
12492
Ok(())
12593
}
12694

95+
fn find_candidates(m: &matrix::Matrix<char>, path: &Vec<coord::Coord>) -> HashSet<coord::Coord> {
96+
let mut cheat_candidates: HashSet<coord::Coord> = HashSet::new();
97+
98+
for p in path.iter() {
99+
for v in vec![UP, RIGHT, DOWN, LEFT].iter() {
100+
let c = p.add(*v);
101+
102+
if path.contains(&c) {
103+
continue;
104+
}
105+
106+
let tile = m.at_coord(c).unwrap();
107+
108+
if *tile == '#' {
109+
cheat_candidates.insert(c);
110+
}
111+
}
112+
}
113+
114+
return cheat_candidates;
115+
}
116+
127117
#[derive(Eq, PartialEq, Hash, Clone)]
128118
struct Pos {
129119
node: coord::Coord,
130120
remaining: i32,
121+
cheat_enabled: bool,
131122
}
132123

133124
fn find_reference(
@@ -165,60 +156,91 @@ fn find_reference(
165156

166157
fn cheated_successors(
167158
m: &matrix::Matrix<char>,
159+
reference_path: &Vec<coord::Coord>,
168160
n: &Pos,
169161
cheat_pos: coord::Coord,
170162
remaining: i32,
171163
) -> Vec<(Pos, i32)> {
172-
vec![UP, RIGHT, DOWN, LEFT]
173-
.into_iter()
174-
.map(|v| n.node.add(v))
175-
.filter(|c| {
176-
if !m.in_coord(*c) {
177-
return false;
178-
}
164+
let mut res: Vec<(Pos, i32)> = Vec::new();
179165

180-
if *c == cheat_pos {
181-
return true;
182-
}
166+
for v in vec![UP, RIGHT, DOWN, LEFT] {
167+
let next_pos = n.node.add(v);
183168

184-
if n.remaining > 0 {
185-
return true;
186-
}
169+
// skip out of bounds
170+
if !m.in_coord(next_pos) {
171+
continue;
172+
}
187173

188-
let tile = m.at_coord(*c);
189-
match tile {
190-
Some(v) => return *v != '#',
191-
None => return false,
192-
}
193-
})
194-
.map(|c| {
195-
if c == cheat_pos {
196-
return (Pos { node: c, remaining }, 1);
174+
// activate cheat
175+
if next_pos == cheat_pos {
176+
res.push((
177+
Pos {
178+
node: next_pos,
179+
remaining: remaining - 1,
180+
cheat_enabled: true,
181+
},
182+
1,
183+
));
184+
continue;
185+
}
186+
187+
// cheat activated
188+
if n.cheat_enabled == true && n.remaining > 0 {
189+
// deactivate cheat
190+
if reference_path.contains(&next_pos) {
191+
res.push((
192+
Pos {
193+
node: next_pos,
194+
remaining: 0,
195+
cheat_enabled: false,
196+
},
197+
1,
198+
));
199+
} else {
200+
res.push((
201+
Pos {
202+
node: next_pos,
203+
remaining: n.remaining - 1,
204+
cheat_enabled: true,
205+
},
206+
1,
207+
));
197208
}
198-
(
209+
continue;
210+
}
211+
212+
// normal detection
213+
let tile = m.at_coord(next_pos).unwrap();
214+
if *tile != '#' {
215+
res.push((
199216
Pos {
200-
node: c,
201-
remaining: n.remaining - 1,
217+
node: next_pos,
218+
remaining: 0,
219+
cheat_enabled: false,
202220
},
203221
1,
204-
)
205-
})
206-
.collect()
222+
));
223+
}
224+
}
225+
226+
return res;
207227
}
208228

209229
fn find_path(
210230
m: &matrix::Matrix<char>,
211231
start: coord::Coord,
212232
goal: coord::Coord,
233+
reference_path: &Vec<coord::Coord>,
213234
cheat_pos: coord::Coord,
214235
cheat_dur: i32,
215236
) -> Option<(Vec<Pos>, i32)> {
216237
astar(
217238
&Pos {
218239
node: start,
219240
remaining: 0,
241+
cheat_enabled: false,
220242
},
221-
|n| cheated_successors(m, n, cheat_pos, cheat_dur),
243+
|n| cheated_successors(m, reference_path, n, cheat_pos, cheat_dur),
222244
|n| {
223245
let dist = n.node.distance(goal);
224246
return dist.x.abs() + dist.y.abs();

0 commit comments

Comments
 (0)