|
1 | 1 | //! # Supply Stacks
|
2 |
| -//! |
3 |
| -//! There are 2 main challenges to this problem: |
4 |
| -//! * Parsing the input! |
5 |
| -//! * (Rust Specific): The borrow checker prevents mutating a nested `vec` at 2 indices at once. |
6 | 2 | use crate::util::iter::*;
|
7 | 3 | use crate::util::parse::*;
|
8 | 4 |
|
@@ -61,26 +57,23 @@ pub fn part2(input: &Input) -> String {
|
61 | 57 | play(input, false)
|
62 | 58 | }
|
63 | 59 |
|
64 |
| -/// Rust's borrow checker won't allow us to mutate 2 nested `vec`s simulataneously, so we need |
65 |
| -/// to use an temporary intermediate `vec` to store the moving crates. For efficiency we can re-use |
66 |
| -/// the same vec to prevent unnecessary memory allocations. |
67 |
| -/// |
| 60 | +/// `get_disjoint_mut` allows us to acquire two simultaneous mutable references to disjoint indices. |
68 | 61 | /// A nice standard library feature is that we can collect an iterator of `char`s into a `String`
|
69 | 62 | /// for the final answer.
|
70 | 63 | fn play(input: &Input, reverse: bool) -> String {
|
71 | 64 | let (initial, moves) = input;
|
72 | 65 | let mut stack = initial.clone();
|
73 |
| - let mut crates = Vec::new(); |
74 | 66 |
|
75 | 67 | for &[amount, from, to] in moves {
|
76 |
| - let start = stack[from].len() - amount; |
77 |
| - crates.extend(stack[from].drain(start..)); |
| 68 | + let [from, to] = stack.get_disjoint_mut([from, to]).unwrap(); |
| 69 | + let start = from.len() - amount; |
| 70 | + let iter = from.drain(start..); |
| 71 | + |
78 | 72 | if reverse {
|
79 |
| - stack[to].extend(crates.iter().rev()); |
| 73 | + to.extend(iter.rev()); |
80 | 74 | } else {
|
81 |
| - stack[to].extend(crates.iter()); |
| 75 | + to.extend(iter); |
82 | 76 | }
|
83 |
| - crates.clear(); |
84 | 77 | }
|
85 | 78 |
|
86 | 79 | stack.iter().map(|v| v.last().unwrap()).collect()
|
|
0 commit comments