Added Solution for 2019 day 18
This commit is contained in:
parent
0a5a3c79fb
commit
a7f88129cf
6 changed files with 666 additions and 0 deletions
8
2019/day18_many-worlds_interpretation/Cargo.toml
Normal file
8
2019/day18_many-worlds_interpretation/Cargo.toml
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
[package]
|
||||||
|
name = "day18_many-worlds_interpretation"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
318
2019/day18_many-worlds_interpretation/challenge.txt
Normal file
318
2019/day18_many-worlds_interpretation/challenge.txt
Normal file
|
@ -0,0 +1,318 @@
|
||||||
|
As you approach Neptune, a planetary security system detects you and activates a giant [tractor beam](https://en.wikipedia.org/wiki/Tractor_beam) on [Triton](https://en.wikipedia.org/wiki/Triton_(moon))! You have no choice but to land.
|
||||||
|
|
||||||
|
A scan of the local area reveals only one interesting feature: a massive underground vault. You generate a map of the tunnels (your puzzle input). The tunnels are too narrow to move diagonally.
|
||||||
|
|
||||||
|
Only one *entrance* (marked `@`) is present among the *open passages* (marked `.`) and *stone walls* (`#`), but you also detect an assortment of *keys* (shown as lowercase letters) and *doors* (shown as uppercase letters). Keys of a given letter open the door of the same letter: `a` opens `A`, `b` opens `B`, and so on. You aren't sure which key you need to disable the tractor beam, so you'll need to *collect all of them*.
|
||||||
|
|
||||||
|
For example, suppose you have the following map:
|
||||||
|
|
||||||
|
```
|
||||||
|
#########
|
||||||
|
#b.A.@.a#
|
||||||
|
#########
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
Starting from the entrance (`@`), you can only access a large door (`A`) and a key (`a`). Moving toward the door doesn't help you, but you can move `2` steps to collect the key, unlocking `A` in the process:
|
||||||
|
|
||||||
|
```
|
||||||
|
#########
|
||||||
|
#b.....@#
|
||||||
|
#########
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
Then, you can move `6` steps to collect the only other key, `b`:
|
||||||
|
|
||||||
|
```
|
||||||
|
#########
|
||||||
|
#@......#
|
||||||
|
#########
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
So, collecting every key took a total of `*8*` steps.
|
||||||
|
|
||||||
|
Here is a larger example:
|
||||||
|
|
||||||
|
```
|
||||||
|
########################
|
||||||
|
#f.D.E.e.C.b.A.@.a.B.c.#
|
||||||
|
######################.#
|
||||||
|
#d.....................#
|
||||||
|
########################
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
The only reasonable move is to take key `a` and unlock door `A`:
|
||||||
|
|
||||||
|
```
|
||||||
|
########################
|
||||||
|
#f.D.E.e.C.b.....@.B.c.#
|
||||||
|
######################.#
|
||||||
|
#d.....................#
|
||||||
|
########################
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
Then, do the same with key `b`:
|
||||||
|
|
||||||
|
```
|
||||||
|
########################
|
||||||
|
#f.D.E.e.C.@.........c.#
|
||||||
|
######################.#
|
||||||
|
#d.....................#
|
||||||
|
########################
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
...and the same with key `c`:
|
||||||
|
|
||||||
|
```
|
||||||
|
########################
|
||||||
|
#f.D.E.e.............@.#
|
||||||
|
######################.#
|
||||||
|
#d.....................#
|
||||||
|
########################
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
Now, you have a choice between keys `d` and `e`. While key `e` is closer, collecting it now would be slower in the long run than collecting key `d` first, so that's the best choice:
|
||||||
|
|
||||||
|
```
|
||||||
|
########################
|
||||||
|
#f...E.e...............#
|
||||||
|
######################.#
|
||||||
|
#@.....................#
|
||||||
|
########################
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
Finally, collect key `e` to unlock door `E`, then collect key `f`, taking a grand total of `*86*` steps.
|
||||||
|
|
||||||
|
Here are a few more examples:
|
||||||
|
|
||||||
|
* ```
|
||||||
|
########################
|
||||||
|
#...............b.C.D.f#
|
||||||
|
#.######################
|
||||||
|
#.....@.a.B.c.d.A.e.F.g#
|
||||||
|
########################
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
Shortest path is `132` steps: `b`, `a`, `c`, `d`, `f`, `e`, `g`
|
||||||
|
|
||||||
|
* ```
|
||||||
|
#################
|
||||||
|
#i.G..c...e..H.p#
|
||||||
|
########.########
|
||||||
|
#j.A..b...f..D.o#
|
||||||
|
########@########
|
||||||
|
#k.E..a...g..B.n#
|
||||||
|
########.########
|
||||||
|
#l.F..d...h..C.m#
|
||||||
|
#################
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
Shortest paths are `136` steps;
|
||||||
|
one is: `a`, `f`, `b`, `j`, `g`, `n`, `h`, `d`, `l`, `o`, `e`, `p`, `c`, `i`, `k`, `m`
|
||||||
|
|
||||||
|
* ```
|
||||||
|
########################
|
||||||
|
#@..............ac.GI.b#
|
||||||
|
###d#e#f################
|
||||||
|
###A#B#C################
|
||||||
|
###g#h#i################
|
||||||
|
########################
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
Shortest paths are `81` steps; one is: `a`, `c`, `f`, `i`, `d`, `g`, `b`, `e`, `h`
|
||||||
|
|
||||||
|
*How many steps is the shortest path that collects all of the keys?*
|
||||||
|
|
||||||
|
Your puzzle answer was `5182`.
|
||||||
|
|
||||||
|
\--- Part Two ---
|
||||||
|
----------
|
||||||
|
|
||||||
|
You arrive at the vault only to discover that there is not one vault, but *four* - each with its own entrance.
|
||||||
|
|
||||||
|
On your map, find the area in the middle that looks like this:
|
||||||
|
|
||||||
|
```
|
||||||
|
...
|
||||||
|
.@.
|
||||||
|
...
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
Update your map to instead use the correct data:
|
||||||
|
|
||||||
|
```
|
||||||
|
@#@
|
||||||
|
###
|
||||||
|
@#@
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
This change will split your map into four separate sections, each with its own entrance:
|
||||||
|
|
||||||
|
```
|
||||||
|
####### #######
|
||||||
|
#a.#Cd# #a.#Cd#
|
||||||
|
##...## ##@#@##
|
||||||
|
##.@.## --> #######
|
||||||
|
##...## ##@#@##
|
||||||
|
#cB#Ab# #cB#Ab#
|
||||||
|
####### #######
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
Because some of the keys are for doors in other vaults, it would take much too long to collect all of the keys by yourself. Instead, you deploy four remote-controlled robots. Each starts at one of the entrances (`@`).
|
||||||
|
|
||||||
|
Your goal is still to *collect all of the keys in the fewest steps*, but now, each robot has its own position and can move independently. You can only remotely control a single robot at a time. Collecting a key instantly unlocks any corresponding doors, regardless of the vault in which the key or door is found.
|
||||||
|
|
||||||
|
For example, in the map above, the top-left robot first collects key `a`, unlocking door `A` in the bottom-right vault:
|
||||||
|
|
||||||
|
```
|
||||||
|
#######
|
||||||
|
#@.#Cd#
|
||||||
|
##.#@##
|
||||||
|
#######
|
||||||
|
##@#@##
|
||||||
|
#cB#.b#
|
||||||
|
#######
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
Then, the bottom-right robot collects key `b`, unlocking door `B` in the bottom-left vault:
|
||||||
|
|
||||||
|
```
|
||||||
|
#######
|
||||||
|
#@.#Cd#
|
||||||
|
##.#@##
|
||||||
|
#######
|
||||||
|
##@#.##
|
||||||
|
#c.#.@#
|
||||||
|
#######
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
Then, the bottom-left robot collects key `c`:
|
||||||
|
|
||||||
|
```
|
||||||
|
#######
|
||||||
|
#@.#.d#
|
||||||
|
##.#@##
|
||||||
|
#######
|
||||||
|
##.#.##
|
||||||
|
#@.#.@#
|
||||||
|
#######
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
Finally, the top-right robot collects key `d`:
|
||||||
|
|
||||||
|
```
|
||||||
|
#######
|
||||||
|
#@.#.@#
|
||||||
|
##.#.##
|
||||||
|
#######
|
||||||
|
##.#.##
|
||||||
|
#@.#.@#
|
||||||
|
#######
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
In this example, it only took `*8*` steps to collect all of the keys.
|
||||||
|
|
||||||
|
Sometimes, multiple robots might have keys available, or a robot might have to wait for multiple keys to be collected:
|
||||||
|
|
||||||
|
```
|
||||||
|
###############
|
||||||
|
#d.ABC.#.....a#
|
||||||
|
######@#@######
|
||||||
|
###############
|
||||||
|
######@#@######
|
||||||
|
#b.....#.....c#
|
||||||
|
###############
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
First, the top-right, bottom-left, and bottom-right robots take turns collecting keys `a`, `b`, and `c`, a total of `6 + 6 + 6 = 18` steps. Then, the top-left robot can access key `d`, spending another `6` steps; collecting all of the keys here takes a minimum of `*24*` steps.
|
||||||
|
|
||||||
|
Here's a more complex example:
|
||||||
|
|
||||||
|
```
|
||||||
|
#############
|
||||||
|
#DcBa.#.GhKl#
|
||||||
|
#.###@#@#I###
|
||||||
|
#e#d#####j#k#
|
||||||
|
###C#@#@###J#
|
||||||
|
#fEbA.#.FgHi#
|
||||||
|
#############
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
* Top-left robot collects key `a`.
|
||||||
|
* Bottom-left robot collects key `b`.
|
||||||
|
* Top-left robot collects key `c`.
|
||||||
|
* Bottom-left robot collects key `d`.
|
||||||
|
* Top-left robot collects key `e`.
|
||||||
|
* Bottom-left robot collects key `f`.
|
||||||
|
* Bottom-right robot collects key `g`.
|
||||||
|
* Top-right robot collects key `h`.
|
||||||
|
* Bottom-right robot collects key `i`.
|
||||||
|
* Top-right robot collects key `j`.
|
||||||
|
* Bottom-right robot collects key `k`.
|
||||||
|
* Top-right robot collects key `l`.
|
||||||
|
|
||||||
|
In the above example, the fewest steps to collect all of the keys is `*32*`.
|
||||||
|
|
||||||
|
Here's an example with more choices:
|
||||||
|
|
||||||
|
```
|
||||||
|
#############
|
||||||
|
#g#f.D#..h#l#
|
||||||
|
#F###e#E###.#
|
||||||
|
#dCba@#@BcIJ#
|
||||||
|
#############
|
||||||
|
#nK.L@#@G...#
|
||||||
|
#M###N#H###.#
|
||||||
|
#o#m..#i#jk.#
|
||||||
|
#############
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
One solution with the fewest steps is:
|
||||||
|
|
||||||
|
* Top-left robot collects key `e`.
|
||||||
|
* Top-right robot collects key `h`.
|
||||||
|
* Bottom-right robot collects key `i`.
|
||||||
|
* Top-left robot collects key `a`.
|
||||||
|
* Top-left robot collects key `b`.
|
||||||
|
* Top-right robot collects key `c`.
|
||||||
|
* Top-left robot collects key `d`.
|
||||||
|
* Top-left robot collects key `f`.
|
||||||
|
* Top-left robot collects key `g`.
|
||||||
|
* Bottom-right robot collects key `k`.
|
||||||
|
* Bottom-right robot collects key `j`.
|
||||||
|
* Top-right robot collects key `l`.
|
||||||
|
* Bottom-left robot collects key `n`.
|
||||||
|
* Bottom-left robot collects key `m`.
|
||||||
|
* Bottom-left robot collects key `o`.
|
||||||
|
|
||||||
|
This example requires at least `*72*` steps to collect all keys.
|
||||||
|
|
||||||
|
After updating your map and using the remote-controlled robots, *what is the fewest steps necessary to collect all of the keys?*
|
||||||
|
|
||||||
|
Your puzzle answer was `2154`.
|
||||||
|
|
||||||
|
Both parts of this puzzle are complete! They provide two gold stars: \*\*
|
||||||
|
|
||||||
|
At this point, you should [return to your Advent calendar](/2019) and try another puzzle.
|
||||||
|
|
||||||
|
If you still want to see it, you can [get your puzzle input](18/input).
|
241
2019/day18_many-worlds_interpretation/src/lib.rs
Normal file
241
2019/day18_many-worlds_interpretation/src/lib.rs
Normal file
|
@ -0,0 +1,241 @@
|
||||||
|
use core::fmt::Display;
|
||||||
|
use std::collections::{HashMap, HashSet, VecDeque};
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
|
pub enum ParseError {
|
||||||
|
CharMalformed(char),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for ParseError {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
match self {
|
||||||
|
Self::CharMalformed(v) => write!(f, "Unexpected Character: {v}"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type Coordinates = (usize, usize);
|
||||||
|
|
||||||
|
#[derive(PartialEq, Eq, Clone, Copy)]
|
||||||
|
enum Tile {
|
||||||
|
Open,
|
||||||
|
Wall,
|
||||||
|
Entrance,
|
||||||
|
Door(usize),
|
||||||
|
Key(usize),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Tile {
|
||||||
|
fn print(self) -> char {
|
||||||
|
match self {
|
||||||
|
Self::Open => '.',
|
||||||
|
Self::Wall => '#',
|
||||||
|
Self::Entrance => '@',
|
||||||
|
Self::Door(i) => (b'A' + i.ilog2() as u8) as char,
|
||||||
|
Self::Key(i) => (b'a' + i.ilog2() as u8) as char,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Vault {
|
||||||
|
tiles: Vec<Vec<Tile>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryFrom<&str> for Vault {
|
||||||
|
type Error = ParseError;
|
||||||
|
fn try_from(value: &str) -> Result<Self, Self::Error> {
|
||||||
|
let tiles = value.lines()
|
||||||
|
.map(|line| line.chars()
|
||||||
|
.map(|c| {
|
||||||
|
match c {
|
||||||
|
'.' => Ok(Tile::Open),
|
||||||
|
'#' => Ok(Tile::Wall),
|
||||||
|
'@' => Ok(Tile::Entrance),
|
||||||
|
d if d.is_uppercase() => Ok(Tile::Door(2_usize.pow(d as u32 - b'A' as u32))),
|
||||||
|
k if k.is_lowercase() => Ok(Tile::Key(2_usize.pow(k as u32 - b'a' as u32))),
|
||||||
|
_ => Err(ParseError::CharMalformed(c)),
|
||||||
|
}
|
||||||
|
}).collect::<Result<Vec<_>, _>>()
|
||||||
|
).collect::<Result<Vec<_>, _>>()?;
|
||||||
|
|
||||||
|
Ok(Self {
|
||||||
|
tiles,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Vault {
|
||||||
|
fn split(&self, entrance: (usize, usize)) -> Self {
|
||||||
|
let mut tiles = self.tiles.to_vec();
|
||||||
|
|
||||||
|
for dx in 0..3 {
|
||||||
|
for dy in 0..3 {
|
||||||
|
tiles[entrance.1+dy-1][entrance.0+dx-1] = if dx % 2 == 0 && dy % 2 == 0 { Tile::Entrance } else { Tile::Wall };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Self {
|
||||||
|
tiles,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn print(&self) -> String {
|
||||||
|
self.tiles.iter()
|
||||||
|
.flat_map(|row| row.iter()
|
||||||
|
.map(|t| t.print())
|
||||||
|
.chain(['\n'].into_iter()))
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(PartialEq, Eq, Hash, Clone)]
|
||||||
|
struct CollectionState {
|
||||||
|
positions: Vec<Coordinates>,
|
||||||
|
keys_left: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(PartialEq, Eq, Hash, Clone, Copy)]
|
||||||
|
struct TraversalState {
|
||||||
|
position: Coordinates,
|
||||||
|
keys_required: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TraversalState {
|
||||||
|
fn get_neighbours(&self) -> [Self; 4] {
|
||||||
|
[
|
||||||
|
Self { position: (self.position.0-1, self.position.1), keys_required: self.keys_required },
|
||||||
|
Self { position: (self.position.0+1, self.position.1), keys_required: self.keys_required },
|
||||||
|
Self { position: (self.position.0, self.position.1-1), keys_required: self.keys_required },
|
||||||
|
Self { position: (self.position.0, self.position.1+1), keys_required: self.keys_required },
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn run(input: &str) -> Result<(usize, usize), ParseError> {
|
||||||
|
let vault = Vault::try_from(input)?;
|
||||||
|
// println!("{}", vault.print());
|
||||||
|
let keys: Vec<_> = vault.tiles.iter().enumerate().flat_map(|(y, row)| row.iter().enumerate().filter(|(_x, tile)| matches!(tile, Tile::Key(_))).map(|(x, key)| match key { Tile::Key(k) => (x, y, *k), _ => unreachable!(), }).collect::<Vec<_>>()).collect();
|
||||||
|
let entrance = vault.tiles.iter().enumerate().find(|(_y, row)| row.iter().any(|tile| matches!(tile, Tile::Entrance))).map(|(y, row)| (row.iter().position(|tile| matches!(tile, Tile::Entrance)).unwrap(), y)).unwrap();
|
||||||
|
let graph = get_graph(&vault, &keys, &[entrance]);
|
||||||
|
let first = find_shortest(&graph, &keys, &[entrance]);
|
||||||
|
let vault_2 = &vault.split(entrance);
|
||||||
|
// println!("{}", vault_2.print());
|
||||||
|
let entrances_2 = [(entrance.0-1, entrance.1-1), (entrance.0+1, entrance.1-1), (entrance.0-1, entrance.1+1), (entrance.0+1, entrance.1+1)];
|
||||||
|
let graph_2 = get_graph(vault_2, &keys, &entrances_2);
|
||||||
|
// dbg!(&graph_2);
|
||||||
|
let second = find_shortest(&graph_2, &keys, &entrances_2);
|
||||||
|
// let second = 0;
|
||||||
|
Ok((first, second))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn find_shortest(graph: &HashMap<((usize, usize), (usize, usize)), Vec<(usize, usize)>>, keys: &[(usize, usize, usize)], entrances: &[(usize, usize)]) -> usize {
|
||||||
|
let starting = CollectionState { positions: entrances.to_vec(), keys_left: keys.iter().map(|(_x, _y, k)| k).sum() };
|
||||||
|
let mut open_set = HashSet::from([starting.clone()]);
|
||||||
|
let mut costs = HashMap::from([(starting, 0)]);
|
||||||
|
while !open_set.is_empty() {
|
||||||
|
let current = open_set.iter().min_by_key(|s| costs.get(s).unwrap()).unwrap().clone();
|
||||||
|
let old_costs = *costs.get(¤t).unwrap();
|
||||||
|
if current.keys_left == 0 {
|
||||||
|
return old_costs;
|
||||||
|
}
|
||||||
|
open_set.remove(¤t);
|
||||||
|
for (x, y, key) in keys.iter().filter(|(_x, _y, k)| k & current.keys_left > 0) {
|
||||||
|
for cursor in 0..current.positions.len() {
|
||||||
|
let mut new = current.clone();
|
||||||
|
new.positions[cursor] = (*x, *y);
|
||||||
|
new.keys_left -= *key;
|
||||||
|
|
||||||
|
let paths = graph.get(&(current.positions[cursor], new.positions[cursor])).unwrap();
|
||||||
|
let shortest_path = paths.iter().find(|(_dist, keys_required)| keys_required & current.keys_left == 0).map(|(dist, _keys_required)| *dist).unwrap_or(usize::MAX);
|
||||||
|
let new_costs = old_costs.saturating_add(shortest_path);
|
||||||
|
if new_costs < *costs.get(&new).unwrap_or(&usize::MAX) {
|
||||||
|
open_set.insert(new.clone());
|
||||||
|
costs.insert(new.clone(), new_costs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
panic!("Exhausted all ways but found no solution");
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_graph(vault: &Vault, keys: &[(usize, usize, usize)], entrances: &[(usize, usize)]) -> HashMap<((usize, usize), (usize, usize)), Vec<(usize, usize)>> {
|
||||||
|
let mut res = HashMap::new();
|
||||||
|
for dest in keys {
|
||||||
|
let dest = (dest.0, dest.1);
|
||||||
|
for starting in entrances {
|
||||||
|
res.insert((*starting, dest), get_paths(*starting, dest, vault));
|
||||||
|
}
|
||||||
|
for start in keys {
|
||||||
|
let start = (start.0, start.1);
|
||||||
|
let paths = if let Some(rev) = res.get(&(dest, start)) {
|
||||||
|
rev.to_vec()
|
||||||
|
} else {
|
||||||
|
get_paths(start, dest, vault)
|
||||||
|
};
|
||||||
|
res.insert((start, dest), paths);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
res
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_paths(start: Coordinates, dest: Coordinates, vault: &Vault) -> Vec<(usize, usize)> {
|
||||||
|
let mut open_set = VecDeque::from([TraversalState { position: start, keys_required: 0 }]);
|
||||||
|
let mut distances = HashMap::from([(TraversalState { position: start, keys_required: 0 }, 0)]);
|
||||||
|
let mut res = Vec::new();
|
||||||
|
while let Some(current) = open_set.pop_front() {
|
||||||
|
let dist = *distances.get(¤t).unwrap();
|
||||||
|
if distances.iter().any(|(other, d)| other.position == current.position && d <= &dist && other.keys_required | current.keys_required == current.keys_required && other.keys_required < current.keys_required) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if res.iter().any(|(d, keys)| d <= &dist && current.keys_required | keys == current.keys_required) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if current.position == dest {
|
||||||
|
res.push((dist, current.keys_required));
|
||||||
|
if current.keys_required == 0 {
|
||||||
|
res.sort_by_key(|(dist, _keys_required)| *dist);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for neighbour in current.get_neighbours().iter_mut() {
|
||||||
|
match vault.tiles[neighbour.position.1][neighbour.position.0] {
|
||||||
|
Tile::Wall => continue,
|
||||||
|
Tile::Door(i) => neighbour.keys_required |= i,
|
||||||
|
// Tile::Key(_) if neighbour.position != dest => continue,
|
||||||
|
_ => ()
|
||||||
|
}
|
||||||
|
let new_dist = dist + 1;
|
||||||
|
if distances.get(neighbour).unwrap_or(&usize::MAX) > &new_dist {
|
||||||
|
open_set.push_back(*neighbour);
|
||||||
|
distances.insert(*neighbour, new_dist);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
res
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use std::fs::read_to_string;
|
||||||
|
|
||||||
|
fn read_file(name: &str) -> String {
|
||||||
|
read_to_string(name).expect(&format!("Unable to read file: {name}")[..]).trim().to_string()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
// #[ignore]
|
||||||
|
fn test_sample() {
|
||||||
|
let sample_input = read_file("tests/sample_input");
|
||||||
|
assert_eq!(run(&sample_input), Ok((128, 82)));
|
||||||
|
// assert_eq!(run(&sample_input), Ok((114, 72)));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[ignore]
|
||||||
|
fn test_challenge() {
|
||||||
|
let challenge_input = read_file("tests/challenge_input");
|
||||||
|
assert_eq!(run(&challenge_input), Ok((5182, 2154)));
|
||||||
|
}
|
||||||
|
}
|
81
2019/day18_many-worlds_interpretation/tests/challenge_input
Normal file
81
2019/day18_many-worlds_interpretation/tests/challenge_input
Normal file
|
@ -0,0 +1,81 @@
|
||||||
|
#################################################################################
|
||||||
|
#.............#..o..........#...........#...............#b......#...#.........#.#
|
||||||
|
#.#######.#.#.#.#.#########.###.#######.###.#########.###.###.###.#.#C#####.#.#.#
|
||||||
|
#.#...A.#.#.#.#.#.#w....#.#...#..e#.....#...#.....#...#...#...#...#.#.....#.#k..#
|
||||||
|
#.#.###.###.#.###.###.#.#.###.#####.###.#.###.#####.###.###.###.###.#####.#.###.#
|
||||||
|
#.#...#.....#...#.#...#.....#.....#...#.#...#.#...#.#...#.#.....#.#.....#.#.#...#
|
||||||
|
#.###.#########.#.#.#######.#####.###.#.###.#.#.#.#.#.###.#######.###.#.#.#.#####
|
||||||
|
#...#.#...........#.......#.....#.....#.#...#...#.#.#.......#.....#...#.#.#.#...#
|
||||||
|
###.#.###.#############.#.#############.#.###.###.#P#######.###.#.#.###.#.#.#.#.#
|
||||||
|
#...#...#.#.....#.....#.#.....#...#.....#.#.....#.......#...#...#.#.#...#.#...#.#
|
||||||
|
#.#####.#.#.###.#.###.#######.#.#.#.#####.###############.###.#####.#.###.#####.#
|
||||||
|
#.....#.#.#.#.#.#...#.#.....#.#.#.#.....#.......#.......#.#.......#.#...#.#...#.#
|
||||||
|
###.###.#.#.#.#.###.#.#.###.#.#.#.#####.#.#####.#.#####.#.#######.#.###.#.#.###.#
|
||||||
|
#...#...#.#...#.#...#.#.#...#...#.....#.#.#.#...#.#.#...#...#.....#.#...#.#.#...#
|
||||||
|
#.###.#######.#.#.###.#.###.#.#####.###.#.#.#.#.#.#.#.#####.#.###.#D###.#.#.#.###
|
||||||
|
#...#.....#...#.....#.#...#.#.#...#.#...#...#.#.#...#.....#.#.#.X.#...#.#...#...#
|
||||||
|
###.#####.#.#####.###.###.#.###.#.#.#.#######.#.###.#####.#.#.###.###.#####.###.#
|
||||||
|
#.#.....#...#...#.#...#.#.#.#...#.#.#...#.....#.#.#.#...#.#.#...#...#...#...#...#
|
||||||
|
#.#####.#####.#.###.#.#.#.#.#.###.#.###.#.#####.#.#.#.#.#.#.###.#.#####.#.###.###
|
||||||
|
#.#...#.#.....#.....#...#.#...#...#.....#.#.....#.#.#.#.#.......#.#...#.....#...#
|
||||||
|
#.#.#.#.#.###.#########.#.#####.#######.#.#.#####.#.###.#########.#.#.#########.#
|
||||||
|
#...#...#...#.#...#...#.#.#...#.......#.#.#.....#.#.#.....#...#...#.#.........#i#
|
||||||
|
#.#####.###.#.#.#.#.#####.#.#########.#.#.#####.#.#.#.#####.#######.#########.#.#
|
||||||
|
#.#...#...#.#.#.#...#.....#.........#.#.#.....#...#...#n..#..f..#.Z.#...W...#.#.#
|
||||||
|
#K#Y#.#.###.#.#.#####.#####.###.#####.#.#####.#####.###.#.#####.#.###.#.#####.#.#
|
||||||
|
#.#.#.#.#...#.#.#.#...#...#.#.#.#...#.#.#.....#.....#...#.......#.#.#.#......h#.#
|
||||||
|
#.#.#.###.#.###.#.#.#.###.#.#.#.#.#.#.#.#.#J###.#####.###########.#.#.#########.#
|
||||||
|
#.#.#.....#.#...#...#...#...#.#.#.#...#.#.#.#...#...#.....#...#g..#.#.#...#.....#
|
||||||
|
###.#######.#.###.#####.#.###.#.#.#######.###.#####.#####.#.#.#.###.#.#.###.###.#
|
||||||
|
#...#.....#.#.#...#.....#.....#.#.......#...#.#.......#.#...#...#.....#.....#...#
|
||||||
|
#.#####.###.#.#.###.#########.#.#######.#.#.#.###.###.#.#########.#####.#####.###
|
||||||
|
#.....#.....#d#...#.#...#...#.#.......#.#.#.#...#...#.#.......#.#.#...#...#.#...#
|
||||||
|
#.###.#.#####.###.#.#.#.#.#.#.###.#####.###.###.###.#.###.###.#.#.###.###.#.###.#
|
||||||
|
#.#...#...#.#.#...#.#.#.#.#...#.#.....#.#...#.#.....#...#.#.#...#...#.....#.#...#
|
||||||
|
#.#.#####.#.#.#####.#.#.#.#####.#####.#.#.#.#.#########.#.#.###.###.#####.#.#.###
|
||||||
|
#.#.....#.#.#...#...#.#.#...#.......#.#.#.#.......#...#...#...#...#.....#.#.#...#
|
||||||
|
#.#####V#.#.###.#.###.#.###.#.#####.#.#.#.#######.#.#.#####.#.###.#####.#.#U###.#
|
||||||
|
#.....#.#.....#...#...#...#.#.....#.#...#...#.....#.#.......#.#...#..v#.#.....#.#
|
||||||
|
#####.#.###########.#######.#####.#.#####.#.#######.#####.#####.#####.#.#######.#
|
||||||
|
#.....#...........................#.......#.............#.........R...#l........#
|
||||||
|
#######################################.@.#######################################
|
||||||
|
#.............#......r..#.......#...........#.........#...#.......#.....#.#.....#
|
||||||
|
#.###########.#######.###.#.###.#.#####.#.###.#######.#.#.#.###.###.#.#.#.#.#.###
|
||||||
|
#...#.......#.......#.....#.#.#...#...#.#.#...#.....#...#.#...#.....#y#...#.#...#
|
||||||
|
###.#.###.#.#######.#.#####.#.#######.#.#.#.###.###.#####.###.#######.###.#.###Q#
|
||||||
|
#...#.#...#.#.......#.#.....#.......#.#.#...#...#...#...#...#...#...#...#.#.#.#.#
|
||||||
|
#.###.#.#.###.#######.#.#######.###.#.#.#.###.#####.#.#.###.###.#.#.###.#.#.#.#.#
|
||||||
|
#.#...#.#.#.........#.#...#.....#.....#.#.#...#...#...#.#.#.....#.#.#...#.#...#.#
|
||||||
|
#.#.###.###.#######.#####.#.#.#########.#.###.#.#.#####.#.#######.#.#.#######.#.#
|
||||||
|
#q#...#.....#.....#.....#.#.#.#...#.....#...#...#.#...#.........#.#.#.#.......#.#
|
||||||
|
#.#######.###.###.#####.#.#.###.#.#.#######.#.###.#.#.#########.#.#.#.#.#######.#
|
||||||
|
#.#.....#...#.#.#.#...#.#.#.#...#.#.....#..j#.#...#.#.....#.....#.#.#.....#.....#
|
||||||
|
#.#.###.#####.#.#.###.#.#.#.#.###.#####.#.###.#.###.#####.###.###.#.#######.###.#
|
||||||
|
#.#.#.#...#...#.#.#...#...#.#...#.......#.#.#.#.....#...#...#...#.#.......#...#.#
|
||||||
|
#.#L#.###.#.###.#.#.#######.###.#########.#.#.#########.###.###.#.#######.###S#.#
|
||||||
|
#.#...#.#.#.#...#.#.#...#.......#...#...#.#.............#.#.#.#.#.#.....#...#.#.#
|
||||||
|
#.###.#.#.#.###.#.#.#.#.#.#######.#.#.#.#.#.###########.#.#.#.#.#.###.#.###.#.#.#
|
||||||
|
#...#...#...#...#.#.#.#.........#.#.#.#.#.#.#.......#.#.#.#.#...#...#.#...#.#.#.#
|
||||||
|
#.#.###.#####.#.#H#.#.#########.#.#.#N#.#.#.#.#####.#.#.#.#.#######.###.#.#.#.#.#
|
||||||
|
#.#.#...#.....#.#.#.....#...#...#.#...#.#.#.#.#...#.#.....#.#.....#...#.#.#...#.#
|
||||||
|
###.#.###.#.#####.#.#####.#.#.###.#####.#.###.#.#.#.#.#####.#.###.###.#.#######.#
|
||||||
|
#...#...#.#...#...#.#.T...#.#.#.F.#.#...#.....#.#.#.#...#...#.#...#...#...#...#.#
|
||||||
|
#.#####.#.###.#.###########.###.###.#.#########.#.#.###.#.#.###.###.###.#.#.#.#.#
|
||||||
|
#.....#.#.#u..#..z........#....t#.G...#.#.......#.#.#...#.#...#.#...#...#...#...#
|
||||||
|
###.#.#.###.###########.#########.#####.#.#####.#.#.#####.#.###.#.#######.#######
|
||||||
|
#...#s#...#.....#.....#.........#.#.....#.....#.#.#.....#.#.#...#.......#...#...#
|
||||||
|
#.###.###.###.#.#.###.#######.###.#.###########.#######.#.#.#.###.#####.#####.#.#
|
||||||
|
#.#.....#...#.#.....#.......#.....#.....#.....#.......#.#.#.#...#.#...#...#...#.#
|
||||||
|
#.#########.###############.###########.#.###.#####.###.#.#####.#.#.#####.#.###.#
|
||||||
|
#.#x......#.#...#...........#...........#.#.........#...#.#.....#...#.....#.#...#
|
||||||
|
#.#.#####.#I#.#.#.#########.#####.#####.#.###########.###.#.#######.#.#####.#.###
|
||||||
|
#.#...#...#...#...#.....#.#.#...#...#...#.............#...#.....#.#.#.......#.O.#
|
||||||
|
#.###.#.#############.#.#.#.#.#.###.#.###.###############.#####.#.#.#######.###.#
|
||||||
|
#...#.#.....#...#.....#...#.#.#.....#.#.#.#...#...#.....#..m#...#...#.....#.#...#
|
||||||
|
#.###.###.#.#.#.###.#######.#.#######.#.#.#.#.#.#.#.###.###.#.#######.###.#.#.###
|
||||||
|
#.#...#.#.#...#.....#.....#...#.....#...#.#.#...#.#...#.#...#.....#...#...#.#...#
|
||||||
|
#.#M###.#.###########.###.#####.###.###.#.#.#####.###.#.#.#######.#.###.#######.#
|
||||||
|
#.#...#.#...#..a..#...#.#.....#.#.....#.#p..#...#...#.#.#.#.......#.#...#.....#.#
|
||||||
|
#.###.#.###.#.###.#.###.###.###.#.#####.#####.#####.#.#.#.#.#######.#.###.###.#.#
|
||||||
|
#.........#...B.#.........#.....#.......#.............#...#.......E.#.....#....c#
|
||||||
|
#################################################################################
|
9
2019/day18_many-worlds_interpretation/tests/sample_input
Normal file
9
2019/day18_many-worlds_interpretation/tests/sample_input
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
#################
|
||||||
|
#i.G..c.#.e..H.p#
|
||||||
|
#######.#.#######
|
||||||
|
#j.A..b...f..D.o#
|
||||||
|
#######.@.#######
|
||||||
|
#k.E..a...g..B.n#
|
||||||
|
#######.#.#######
|
||||||
|
#l.F..d.#.h..C.m#
|
||||||
|
#################
|
|
@ -0,0 +1,9 @@
|
||||||
|
#############
|
||||||
|
#g#f.D#..h#l#
|
||||||
|
#F###e#E###.#
|
||||||
|
#dCba...BcIJ#
|
||||||
|
#####.@.#####
|
||||||
|
#nK.L...G...#
|
||||||
|
#M###N#H###.#
|
||||||
|
#o#m..#i#jk.#
|
||||||
|
#############
|
Loading…
Add table
Add a link
Reference in a new issue