|
@@ -48,6 +48,12 @@ struct Track {
|
48
|
48
|
intersections: HashSet<Vector>,
|
49
|
49
|
}
|
50
|
50
|
|
|
51
|
+#[derive(Debug, PartialEq)]
|
|
52
|
+struct Collision {
|
|
53
|
+ position: Vector,
|
|
54
|
+ cart_indices: (usize, usize),
|
|
55
|
+}
|
|
56
|
+
|
51
|
57
|
impl FromStr for Track {
|
52
|
58
|
type Err = Box<Error>;
|
53
|
59
|
|
|
@@ -87,7 +93,7 @@ impl FromStr for Track {
|
87
|
93
|
},
|
88
|
94
|
(col_index, '/') => match bottom_start {
|
89
|
95
|
Some(start) => match incomplete_circuits.remove(&(start, col_index)) {
|
90
|
|
- Some(top_row) => {
|
|
96
|
+ Some(_) => {
|
91
|
97
|
turns.insert(
|
92
|
98
|
Vector {
|
93
|
99
|
x: col_index,
|
|
@@ -210,13 +216,18 @@ impl Cart {
|
210
|
216
|
}
|
211
|
217
|
|
212
|
218
|
impl Track {
|
213
|
|
- fn run_tick(&mut self) -> Option<Vector> {
|
214
|
|
- let mut cart_positions: HashSet<Vector> = HashSet::new();
|
215
|
|
- for cart in self.carts.iter() {
|
216
|
|
- cart_positions.insert(cart.position);
|
|
219
|
+ fn run_tick(&mut self, find_final_cart: bool) -> Option<Vector> {
|
|
220
|
+ let mut collided_cart_indices = HashSet::new();
|
|
221
|
+ let mut cart_positions: HashMap<Vector, usize> = HashMap::new();
|
|
222
|
+ for (index, cart) in self.carts.iter().enumerate() {
|
|
223
|
+ cart_positions.insert(cart.position, index);
|
217
|
224
|
}
|
218
|
225
|
|
219
|
|
- for cart in self.carts.iter_mut() {
|
|
226
|
+ for (index, cart) in self.carts.iter_mut().enumerate() {
|
|
227
|
+ if collided_cart_indices.contains(&index) {
|
|
228
|
+ continue;
|
|
229
|
+ }
|
|
230
|
+
|
220
|
231
|
let Vector { x, y } = cart.position;
|
221
|
232
|
cart_positions.remove(&cart.position);
|
222
|
233
|
cart.position = match cart.direction {
|
|
@@ -235,12 +246,27 @@ impl Track {
|
235
|
246
|
cart.next_turn = (cart.next_turn + 1) % INTER_SEQ.len() as u8;
|
236
|
247
|
}
|
237
|
248
|
|
238
|
|
- if cart_positions.contains(&cart.position) {
|
239
|
|
- return Some(cart.position);
|
|
249
|
+ if let Some(colliding_cart) = cart_positions.get(&cart.position) {
|
|
250
|
+ if find_final_cart {
|
|
251
|
+ collided_cart_indices.insert(index);
|
|
252
|
+ collided_cart_indices.insert(*colliding_cart);
|
|
253
|
+ cart_positions.remove(&cart.position);
|
|
254
|
+ continue;
|
|
255
|
+ } else {
|
|
256
|
+ return Some(cart.position);
|
|
257
|
+ }
|
240
|
258
|
}
|
241
|
259
|
|
242
|
|
- cart_positions.insert(cart.position);
|
|
260
|
+ cart_positions.insert(cart.position, index);
|
243
|
261
|
}
|
|
262
|
+
|
|
263
|
+ self.carts = self
|
|
264
|
+ .carts
|
|
265
|
+ .drain(..)
|
|
266
|
+ .enumerate()
|
|
267
|
+ .filter(|(i, _)| !collided_cart_indices.contains(i))
|
|
268
|
+ .map(|(_, cart)| cart)
|
|
269
|
+ .collect();
|
244
|
270
|
self.carts.sort_unstable();
|
245
|
271
|
None
|
246
|
272
|
}
|
|
@@ -248,10 +274,17 @@ impl Track {
|
248
|
274
|
fn find_first_collision(&mut self) -> Vector {
|
249
|
275
|
let mut collision: Option<Vector> = None;
|
250
|
276
|
while collision.is_none() {
|
251
|
|
- collision = self.run_tick();
|
|
277
|
+ collision = self.run_tick(false);
|
252
|
278
|
}
|
253
|
279
|
collision.unwrap()
|
254
|
280
|
}
|
|
281
|
+
|
|
282
|
+ fn find_last_cart(&mut self) -> &Cart {
|
|
283
|
+ while self.carts.len() != 1 {
|
|
284
|
+ self.run_tick(true);
|
|
285
|
+ }
|
|
286
|
+ &self.carts[0]
|
|
287
|
+ }
|
255
|
288
|
}
|
256
|
289
|
|
257
|
290
|
fn read_track(filename: &str) -> Result<Track> {
|
|
@@ -264,6 +297,11 @@ pub fn solve_part1() -> Result<Vector> {
|
264
|
297
|
Ok(track.find_first_collision())
|
265
|
298
|
}
|
266
|
299
|
|
|
300
|
+pub fn solve_part2() -> Result<Vector> {
|
|
301
|
+ let mut track = read_track(INPUT)?;
|
|
302
|
+ Ok(track.find_last_cart().position)
|
|
303
|
+}
|
|
304
|
+
|
267
|
305
|
#[cfg(test)]
|
268
|
306
|
mod tests {
|
269
|
307
|
use super::*;
|
|
@@ -326,7 +364,7 @@ mod tests {
|
326
|
364
|
track_after.carts[1].direction = Direction::East;
|
327
|
365
|
track_after.carts[1].next_turn = 1;
|
328
|
366
|
let mut track = test_track();
|
329
|
|
- track.run_tick();
|
|
367
|
+ track.run_tick(false);
|
330
|
368
|
assert_eq!(track, track_after);
|
331
|
369
|
}
|
332
|
370
|
|