Add another part 2 solution that needs massive optimization
This commit is contained in:
parent
38b84d497e
commit
ca251d9352
@ -47,3 +47,49 @@ ZZZ = (ZZZ, ZZZ)
|
|||||||
```
|
```
|
||||||
|
|
||||||
Starting at AAA, follow the left/right instructions. **How many steps are required to reach ZZZ**?
|
Starting at AAA, follow the left/right instructions. **How many steps are required to reach ZZZ**?
|
||||||
|
|
||||||
|
## Part 2
|
||||||
|
|
||||||
|
The sandstorm is upon you and you aren't any closer to escaping the wasteland. You had the camel follow the
|
||||||
|
instructions, but you've barely left your starting position. It's going to take **significantly more steps** to escape!
|
||||||
|
|
||||||
|
What if the map isn't for people - what if the map is for **ghosts?** Are ghosts even bound by the laws of spacetime?
|
||||||
|
Only one way to find out.
|
||||||
|
|
||||||
|
After examining the maps a bit longer, your attention is drawn to a curious fact: the number of nodes with names
|
||||||
|
ending in A is equal to the number ending in Z! If you were a ghost, you'd probably just **start at every node that
|
||||||
|
ends with A** and follow all of the paths at the same time until they all simultaneously end up at nodes that end with
|
||||||
|
`Z`.
|
||||||
|
|
||||||
|
For example:
|
||||||
|
|
||||||
|
```
|
||||||
|
LR
|
||||||
|
|
||||||
|
11A = (11B, XXX)
|
||||||
|
11B = (XXX, 11Z)
|
||||||
|
11Z = (11B, XXX)
|
||||||
|
22A = (22B, XXX)
|
||||||
|
22B = (22C, 22C)
|
||||||
|
22C = (22Z, 22Z)
|
||||||
|
22Z = (22B, 22B)
|
||||||
|
XXX = (XXX, XXX)
|
||||||
|
```
|
||||||
|
|
||||||
|
Here, there are two starting nodes, 11A and 22A (because they both end with A). As you follow each left/right
|
||||||
|
instruction, use that instruction to **simultaneously** navigate away from both nodes you're currently on. Repeat this
|
||||||
|
process until **all** of the nodes you're currently on end with Z. (If only some of the nodes you're on end with Z, they
|
||||||
|
act like any other node and you continue as normal.) In this example, you would proceed as follows:
|
||||||
|
|
||||||
|
- Step 0: You are at `11A` and `22A`.`
|
||||||
|
- Step 1: You choose all of the **left** paths, leading you to `11B` and `22B`.
|
||||||
|
- Step 2: You choose all of the **right** paths, leading you to **11Z** and `22C`.
|
||||||
|
- Step 3: You choose all of the left paths, leading you to `11B` and **22Z**.
|
||||||
|
- Step 4: You choose all of the right paths, leading you to **11Z** and `22B`.
|
||||||
|
- Step 5: You choose all of the left paths, leading you to `11B` and `22C`.
|
||||||
|
- Step 6: You choose all of the right paths, leading you to **11Z** and **22Z**.
|
||||||
|
|
||||||
|
So, in this example, you end up entirely on nodes that end in Z after **6** steps.
|
||||||
|
|
||||||
|
Simultaneously start on every node that ends with A.
|
||||||
|
**How many steps does it take before you're only on nodes that end with `Z`?**
|
||||||
|
10
2023/day8/src/example-input2.txt
Normal file
10
2023/day8/src/example-input2.txt
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
LR
|
||||||
|
|
||||||
|
11A = (11B, XXX)
|
||||||
|
11B = (XXX, 11Z)
|
||||||
|
11Z = (11B, XXX)
|
||||||
|
22A = (22B, XXX)
|
||||||
|
22B = (22C, 22C)
|
||||||
|
22C = (22Z, 22Z)
|
||||||
|
22Z = (22B, 22B)
|
||||||
|
XXX = (XXX, XXX)
|
@ -86,6 +86,37 @@ impl Network {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn count_steps_part_two(&self) -> usize {
|
||||||
|
let mut count = 0usize;
|
||||||
|
let mut next_keys: Vec<_> = self.map.keys().filter(|k| k.ends_with('A')).collect();
|
||||||
|
let mut current: Vec<_> = next_keys
|
||||||
|
.iter()
|
||||||
|
.map(|k| self.map.get(*k).unwrap())
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
loop {
|
||||||
|
for x in self.direction_list.iter() {
|
||||||
|
count += 1;
|
||||||
|
next_keys = current
|
||||||
|
.iter()
|
||||||
|
.map(|c| match x {
|
||||||
|
Direction::Left => &c.0,
|
||||||
|
Direction::Right => &c.1,
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
if next_keys.iter().all(|k| k.ends_with('Z')) {
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
current = next_keys
|
||||||
|
.iter()
|
||||||
|
.map(|k| self.map.get(*k).unwrap())
|
||||||
|
.collect();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn part_one() {
|
fn part_one() {
|
||||||
@ -95,18 +126,36 @@ fn part_one() {
|
|||||||
println!("Part 1: Step count from AAA to ZZZ {}", step_count);
|
println!("Part 1: Step count from AAA to ZZZ {}", step_count);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn part_two() {
|
||||||
|
let network = Network::parse(FILE_STR);
|
||||||
|
let step_count = network.count_steps_part_two();
|
||||||
|
|
||||||
|
println!(
|
||||||
|
"Part 2: Step count for steps to locations ending in Z {}",
|
||||||
|
step_count
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
part_one();
|
part_one();
|
||||||
|
part_two();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
const EXAMPLE_FILE_STR: &str = include_str!("example-input.txt");
|
const EXAMPLE_FILE_STR: &str = include_str!("example-input.txt");
|
||||||
|
const EXAMPLE2_FILE_STR: &str = include_str!("example-input2.txt");
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn first_example() {
|
fn part_one_example() {
|
||||||
let network = Network::parse(EXAMPLE_FILE_STR);
|
let network = Network::parse(EXAMPLE_FILE_STR);
|
||||||
assert_eq!(6, network.count_steps());
|
assert_eq!(6, network.count_steps());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn part_two_example() {
|
||||||
|
let network = Network::parse(EXAMPLE2_FILE_STR);
|
||||||
|
assert_eq!(6, network.count_steps_part_two());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user