diff --git a/2019/day18_many-worlds_interpretation/Cargo.toml b/2019/day18_many-worlds_interpretation/Cargo.toml new file mode 100644 index 0000000..706e352 --- /dev/null +++ b/2019/day18_many-worlds_interpretation/Cargo.toml @@ -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] diff --git a/2019/day18_many-worlds_interpretation/challenge.txt b/2019/day18_many-worlds_interpretation/challenge.txt new file mode 100644 index 0000000..be02ea5 --- /dev/null +++ b/2019/day18_many-worlds_interpretation/challenge.txt @@ -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). \ No newline at end of file diff --git a/2019/day18_many-worlds_interpretation/src/lib.rs b/2019/day18_many-worlds_interpretation/src/lib.rs new file mode 100644 index 0000000..dba8212 --- /dev/null +++ b/2019/day18_many-worlds_interpretation/src/lib.rs @@ -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>, +} + +impl TryFrom<&str> for Vault { + type Error = ParseError; + fn try_from(value: &str) -> Result { + 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::, _>>() + ).collect::, _>>()?; + + 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, + 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::>()).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))); + } +} diff --git a/2019/day18_many-worlds_interpretation/tests/challenge_input b/2019/day18_many-worlds_interpretation/tests/challenge_input new file mode 100644 index 0000000..b1f8cc9 --- /dev/null +++ b/2019/day18_many-worlds_interpretation/tests/challenge_input @@ -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# +################################################################################# diff --git a/2019/day18_many-worlds_interpretation/tests/sample_input b/2019/day18_many-worlds_interpretation/tests/sample_input new file mode 100644 index 0000000..8dfc95a --- /dev/null +++ b/2019/day18_many-worlds_interpretation/tests/sample_input @@ -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# +################# diff --git a/2019/day18_many-worlds_interpretation/tests/sample_input_1 b/2019/day18_many-worlds_interpretation/tests/sample_input_1 new file mode 100644 index 0000000..ee5bf6b --- /dev/null +++ b/2019/day18_many-worlds_interpretation/tests/sample_input_1 @@ -0,0 +1,9 @@ +############# +#g#f.D#..h#l# +#F###e#E###.# +#dCba...BcIJ# +#####.@.##### +#nK.L...G...# +#M###N#H###.# +#o#m..#i#jk.# +#############