diff --git a/2019/day20_donut_maze/Cargo.toml b/2019/day20_donut_maze/Cargo.toml new file mode 100644 index 0000000..124e6d2 --- /dev/null +++ b/2019/day20_donut_maze/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "day20_donut_maze" +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/day20_donut_maze/challenge.txt b/2019/day20_donut_maze/challenge.txt new file mode 100644 index 0000000..0d51f9e --- /dev/null +++ b/2019/day20_donut_maze/challenge.txt @@ -0,0 +1,221 @@ +You notice a strange pattern on the surface of Pluto and land nearby to get a closer look. Upon closer inspection, you realize you've come across one of the famous space-warping mazes of the long-lost Pluto civilization! + +Because there isn't much space on Pluto, the civilization that used to live here thrived by inventing a method for folding spacetime. Although the technology is no longer understood, mazes like this one provide a small glimpse into the daily life of an ancient Pluto citizen. + +This maze is shaped like a [donut](https://en.wikipedia.org/wiki/Torus). Portals along the inner and outer edge of the donut can instantly teleport you from one side to the other. For example: + +``` + A + A + #######.######### + #######.........# + #######.#######.# + #######.#######.# + #######.#######.# + ##### B ###.# +BC...## C ###.# + ##.## ###.# + ##...DE F ###.# + ##### G ###.# + #########.#####.# +DE..#######...###.# + #.#########.###.# +FG..#########.....# + ###########.##### + Z + Z + +``` + +This map of the maze shows solid walls (`#`) and open passages (`.`). Every maze on Pluto has a start (the open tile next to `AA`) and an end (the open tile next to `ZZ`). Mazes on Pluto also have portals; this maze has three pairs of portals: `BC`, `DE`, and `FG`. When on an open tile next to one of these labels, a single step can take you to the other tile with the same label. (You can only walk on `.` tiles; labels and empty space are not traversable.) + +One path through the maze doesn't require any portals. Starting at `AA`, you could go down 1, right 8, down 12, left 4, and down 1 to reach `ZZ`, a total of 26 steps. + +However, there is a shorter path: You could walk from `AA` to the inner `BC` portal (4 steps), warp to the outer `BC` portal (1 step), walk to the inner `DE` (6 steps), warp to the outer `DE` (1 step), walk to the outer `FG` (4 steps), warp to the inner `FG` (1 step), and finally walk to `ZZ` (6 steps). In total, this is only *23* steps. + +Here is a larger example: + +``` + A + A + #################.############# + #.#...#...................#.#.# + #.#.#.###.###.###.#########.#.# + #.#.#.......#...#.....#.#.#...# + #.#########.###.#####.#.#.###.# + #.............#.#.....#.......# + ###.###########.###.#####.#.#.# + #.....# A C #.#.#.# + ####### S P #####.# + #.#...# #......VT + #.#.#.# #.##### + #...#.# YN....#.# + #.###.# #####.# +DI....#.# #.....# + #####.# #.###.# +ZZ......# QG....#..AS + ###.### ####### +JO..#.#.# #.....# + #.#.#.# ###.#.# + #...#..DI BU....#..LF + #####.# #.##### +YN......# VT..#....QG + #.###.# #.###.# + #.#...# #.....# + ###.### J L J #.#.### + #.....# O F P #.#...# + #.###.#####.#.#####.#####.###.# + #...#.#.#...#.....#.....#.#...# + #.#####.###.###.#.#.#########.# + #...#.#.....#...#.#.#.#.....#.# + #.###.#####.###.###.#.#.####### + #.#.........#...#.............# + #########.###.###.############# + B J C + U P P + +``` + +Here, `AA` has no direct path to `ZZ`, but it does connect to `AS` and `CP`. By passing through `AS`, `QG`, `BU`, and `JO`, you can reach `ZZ` in *58* steps. + +In your maze, *how many steps does it take to get from the open tile marked `AA` to the open tile marked `ZZ`?* + +Your puzzle answer was `400`. + +\--- Part Two --- +---------- + +Strangely, the exit isn't open when you reach it. Then, you remember: the ancient Plutonians were famous for building *recursive spaces*. + +The marked connections in the maze aren't portals: they *physically connect* to a larger or smaller copy of the maze. Specifically, the labeled tiles around the inside edge actually connect to a smaller copy of the same maze, and the smaller copy's inner labeled tiles connect to yet a *smaller* copy, and so on. + +When you enter the maze, you are at the outermost level; when at the outermost level, only the outer labels `AA` and `ZZ` function (as the start and end, respectively); all other outer labeled tiles are effectively walls. At any other level, `AA` and `ZZ` count as walls, but the other outer labeled tiles bring you one level outward. + +Your goal is to find a path through the maze that brings you back to `ZZ` at the outermost level of the maze. + +In the first example above, the shortest path is now the loop around the right side. If the starting level is `0`, then taking the previously-shortest path would pass through `BC` (to level `1`), `DE` (to level `2`), and `FG` (back to level `1`). Because this is not the outermost level, `ZZ` is a wall, and the only option is to go back around to `BC`, which would only send you even deeper into the recursive maze. + +In the second example above, there is no path that brings you to `ZZ` at the outermost level. + +Here is a more interesting example: + +``` + Z L X W C + Z P Q B K + ###########.#.#.#.#######.############### + #...#.......#.#.......#.#.......#.#.#...# + ###.#.#.#.#.#.#.#.###.#.#.#######.#.#.### + #.#...#.#.#...#.#.#...#...#...#.#.......# + #.###.#######.###.###.#.###.###.#.####### + #...#.......#.#...#...#.............#...# + #.#########.#######.#.#######.#######.### + #...#.# F R I Z #.#.#.# + #.###.# D E C H #.#.#.# + #.#...# #...#.# + #.###.# #.###.# + #.#....OA WB..#.#..ZH + #.###.# #.#.#.# +CJ......# #.....# + ####### ####### + #.#....CK #......IC + #.###.# #.###.# + #.....# #...#.# + ###.### #.#.#.# +XF....#.# RF..#.#.# + #####.# ####### + #......CJ NM..#...# + ###.#.# #.###.# +RE....#.# #......RF + ###.### X X L #.#.#.# + #.....# F Q P #.#.#.# + ###.###########.###.#######.#########.### + #.....#...#.....#.......#...#.....#.#...# + #####.#.###.#######.#######.###.###.#.#.# + #.......#.......#.#.#.#.#...#...#...#.#.# + #####.###.#####.#.#.#.#.###.###.#.###.### + #.......#.....#.#...#...............#...# + #############.#.#.###.################### + A O F N + A A D M + +``` + +One shortest path through the maze is the following: + +* Walk from `AA` to `XF` (16 steps) +* Recurse into level 1 through `XF` (1 step) +* Walk from `XF` to `CK` (10 steps) +* Recurse into level 2 through `CK` (1 step) +* Walk from `CK` to `ZH` (14 steps) +* Recurse into level 3 through `ZH` (1 step) +* Walk from `ZH` to `WB` (10 steps) +* Recurse into level 4 through `WB` (1 step) +* Walk from `WB` to `IC` (10 steps) +* Recurse into level 5 through `IC` (1 step) +* Walk from `IC` to `RF` (10 steps) +* Recurse into level 6 through `RF` (1 step) +* Walk from `RF` to `NM` (8 steps) +* Recurse into level 7 through `NM` (1 step) +* Walk from `NM` to `LP` (12 steps) +* Recurse into level 8 through `LP` (1 step) +* Walk from `LP` to `FD` (24 steps) +* Recurse into level 9 through `FD` (1 step) +* Walk from `FD` to `XQ` (8 steps) +* Recurse into level 10 through `XQ` (1 step) +* Walk from `XQ` to `WB` (4 steps) +* Return to level 9 through `WB` (1 step) +* Walk from `WB` to `ZH` (10 steps) +* Return to level 8 through `ZH` (1 step) +* Walk from `ZH` to `CK` (14 steps) +* Return to level 7 through `CK` (1 step) +* Walk from `CK` to `XF` (10 steps) +* Return to level 6 through `XF` (1 step) +* Walk from `XF` to `OA` (14 steps) +* Return to level 5 through `OA` (1 step) +* Walk from `OA` to `CJ` (8 steps) +* Return to level 4 through `CJ` (1 step) +* Walk from `CJ` to `RE` (8 steps) +* Return to level 3 through `RE` (1 step) +* Walk from `RE` to `IC` (4 steps) +* Recurse into level 4 through `IC` (1 step) +* Walk from `IC` to `RF` (10 steps) +* Recurse into level 5 through `RF` (1 step) +* Walk from `RF` to `NM` (8 steps) +* Recurse into level 6 through `NM` (1 step) +* Walk from `NM` to `LP` (12 steps) +* Recurse into level 7 through `LP` (1 step) +* Walk from `LP` to `FD` (24 steps) +* Recurse into level 8 through `FD` (1 step) +* Walk from `FD` to `XQ` (8 steps) +* Recurse into level 9 through `XQ` (1 step) +* Walk from `XQ` to `WB` (4 steps) +* Return to level 8 through `WB` (1 step) +* Walk from `WB` to `ZH` (10 steps) +* Return to level 7 through `ZH` (1 step) +* Walk from `ZH` to `CK` (14 steps) +* Return to level 6 through `CK` (1 step) +* Walk from `CK` to `XF` (10 steps) +* Return to level 5 through `XF` (1 step) +* Walk from `XF` to `OA` (14 steps) +* Return to level 4 through `OA` (1 step) +* Walk from `OA` to `CJ` (8 steps) +* Return to level 3 through `CJ` (1 step) +* Walk from `CJ` to `RE` (8 steps) +* Return to level 2 through `RE` (1 step) +* Walk from `RE` to `XQ` (14 steps) +* Return to level 1 through `XQ` (1 step) +* Walk from `XQ` to `FD` (8 steps) +* Return to level 0 through `FD` (1 step) +* Walk from `FD` to `ZZ` (18 steps) + +This path takes a total of *396* steps to move from `AA` at the outermost layer to `ZZ` at the outermost layer. + +In your maze, when accounting for recursion, *how many steps does it take to get from the open tile marked `AA` to the open tile marked `ZZ`, both at the outermost layer?* + +Your puzzle answer was `4986`. + +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](20/input). \ No newline at end of file diff --git a/2019/day20_donut_maze/src/lib.rs b/2019/day20_donut_maze/src/lib.rs new file mode 100644 index 0000000..ce9e248 --- /dev/null +++ b/2019/day20_donut_maze/src/lib.rs @@ -0,0 +1,178 @@ +use core::fmt::Display; +use std::collections::{HashMap, HashSet, VecDeque}; + +#[derive(Debug, PartialEq, Eq)] +pub enum ParseError { + InvalidCharacter(char), +} + +impl Display for ParseError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::InvalidCharacter(v) => write!(f, "Unexpected Character found: {v}"), + } + } +} + +#[derive(Clone, Copy, PartialEq, Eq)] +enum Tile { + Open, + Wall, + LabelComponent(u16), +} + +impl TryFrom for Tile { + type Error = ParseError; + fn try_from(value: char) -> Result { + match value { + '.' => Ok(Self::Open), + '#' | ' ' => Ok(Self::Wall), + l @ 'A'..='Z' => Ok(Self::LabelComponent(l as u16 - b'A' as u16)), + e => Err(Self::Error::InvalidCharacter(e)) + } + } +} + +struct Maze { + tiles: Vec>, + portals: HashMap<(usize, usize), (usize, usize)> +} + +impl From>> for Maze { + fn from(value: Vec>) -> Self { + let mut tiles = value.to_vec(); + let mut labels = Vec::new(); + for row in 2..value.len()-2 { + for col in 2..value[row].len()-2 { + match value[row][col] { + Tile::LabelComponent(_) => tiles[row][col] = Tile::Wall, + Tile::Open => match ( (value[row-1][col], value[row-2][col]), (value[row][col-1], value[row][col-2]), (value[row][col+1], value[row][col+2]), (value[row+1][col], value[row+2][col]), ) { + ((Tile::LabelComponent(b), Tile::LabelComponent(a)), _, _, _) | (_, (Tile::LabelComponent(b), Tile::LabelComponent(a)), _, _) | (_, _, (Tile::LabelComponent(a), Tile::LabelComponent(b)), _) | (_, _, _, (Tile::LabelComponent(a), Tile::LabelComponent(b))) => { + labels.push((a*26+b, (row, col))); + }, + _ => (), + }, + _ => (), + } + } + } + let mut portals = HashMap::new(); + labels.sort_by_key(|(label, _coords)| *label); + labels.windows(2).for_each(|labels| { + let a = labels[0]; + let b = labels[1]; + if a.0 == b.0 { + portals.insert(a.1, b.1); + portals.insert(b.1, a.1); + } + }); + portals.insert((0, 0), labels[0].1); + portals.insert((1, 1), labels[labels.len()-1].1); + + Self { tiles, portals, } + } +} + +impl Maze { + fn neighbours(&self, position: (usize, usize)) -> Vec<(usize, usize)> { + let mut neighbours = Vec::new(); + if let Some(dest) = self.portals.get(&(position.0, position.1)) { + neighbours.push(*dest); + } + for offset in [(1, 0), (0, 1), (2, 1), (1, 2)] { + let new_position = (position.0+offset.0-1, position.1+offset.1-1); + if self.tiles[new_position.0][new_position.1] == Tile::Open { + neighbours.push(new_position); + } + } + + neighbours + } + + fn recursive_neighbours(&self, position: (usize, usize), level: usize) -> Vec<((usize, usize), usize)> { + let mut neighbours = Vec::new(); + if let Some(dest) = self.portals.get(&(position.0, position.1)) { + if position.0 == 2 || position.1 == 2 || position.0 == self.tiles.len()-3 || position.1 == self.tiles[position.0].len()-3 { + if level > 0 { + neighbours.push((*dest, level-1)); + } + } else { + neighbours.push((*dest, level+1)); + } + } + for offset in [(1, 0), (0, 1), (2, 1), (1, 2)] { + let new_position = (position.0+offset.0-1, position.1+offset.1-1); + if self.tiles[new_position.0][new_position.1] == Tile::Open { + neighbours.push((new_position, level)); + } + } + + neighbours + } +} + +pub fn run(input: &str) -> Result<(usize, usize), ParseError> { + let tiles: Vec<_> = input.lines().map(|line| line.chars().map(Tile::try_from).collect::, _>>()).collect::>, _>>()?; + let maze = Maze::from(tiles); + let start = maze.portals.get(&(0, 0)).unwrap(); + let goal = maze.portals.get(&(1, 1)).unwrap(); + let first = get_shortest_path(&maze, *start, *goal); + let second = get_shortest_path_recursive(&maze, *start, *goal); + Ok((first, second)) +} + +fn get_shortest_path(maze: &Maze, start: (usize, usize), goal: (usize, usize)) -> usize { + let mut visited = HashSet::from([start]); + let mut open_set = VecDeque::from([(start, 0)]); + while let Some((position, dist)) = open_set.pop_front() { + if position == goal { + return dist; + } + for neighbour in maze.neighbours(position) { + if !visited.contains(&neighbour) { + open_set.push_back((neighbour, dist+1)); + visited.insert(neighbour); + } + } + } + panic!("All ways exhausted, but no solution found") +} + +fn get_shortest_path_recursive(maze: &Maze, start: (usize, usize), goal: (usize, usize)) -> usize { + let mut visited = HashSet::from([(start, 0)]); + let mut open_set = VecDeque::from([((start, 0), 0)]); + while let Some(((position, level), dist)) = open_set.pop_front() { + if position == goal && level == 0 { + return dist; + } + for neighbour in maze.recursive_neighbours(position, level) { + if !visited.contains(&neighbour) { + open_set.push_back((neighbour, dist+1)); + visited.insert(neighbour); + } + } + } + panic!("All ways exhausted, but no solution found") +} + +#[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}")[..]) + } + + #[test] + fn test_sample() { + let sample_input = read_file("tests/sample_input"); + assert_eq!(run(&sample_input), Ok((77, 396))); + } + + #[test] + fn test_challenge() { + let challenge_input = read_file("tests/challenge_input"); + assert_eq!(run(&challenge_input), Ok((400, 4986))); + } +} diff --git a/2019/day20_donut_maze/tests/challenge_input b/2019/day20_donut_maze/tests/challenge_input new file mode 100644 index 0000000..278928f --- /dev/null +++ b/2019/day20_donut_maze/tests/challenge_input @@ -0,0 +1,109 @@ + H I J D A U U W + R Z M S A N V T + #############################.#######.#######.###.#.#######.#####.#######.############################# + #.#...#.#.......#.#...#...#.........#.#.#.......#.#.....#.....#.....#.....#.............#...#.....#...# + #.###.#.###.#####.###.###.###.#####.#.#.#######.#.#.###.#.#####.#.###.###.###.#############.#.#.#####.# + #...#.#...#.#...............#...#...#...#.......#.....#.#.#.#...#.#.#.#.#.....#...#...#.#.#...#.#.....# + #.###.#.###.#####.#####.###.#####.###.###.#####.###.#.#.#.#.#.#.###.#.#.###.#####.###.#.#.#.#####.##### + #.#...........#...#...#.#.......#...#...#.....#.#...#.#.#...#.#.....#.....#.#.........#.......#.#.....# + #.###########.###.#.#.###.###.#.###.#.#####.#####.#####.#.#.#######.#.#####.#.#.#.#######.#####.#.#.### + #.....#.#.....#...#.#.....#.#.#.....#.....#...#...#...#.#.#.#.......#.#.#.#.#.#.#.#...........#...#.#.# + #.#####.#####.#.#######.###.#.#####.#.#####.#######.###.#.###.#######.#.#.###.#########.###.###.#####.# + #.#.#.#...#.#...#.........#.......#.#...#.........#.#.#.#...#.#...#.#.#.........#.#.#...#...#.#.....#.# + #.#.#.###.#.###.#.###########.#.#####.###.###.#####.#.#.###.#.#.###.#.###.#.#.###.#.#.#######.###.###.# + #.#.#.......#.#.#.#...#.......#.#.......#...#.#.#.......#...#.....#.......#.#.....#...#.....#...#...#.# + #.#.#######.#.#######.#######.#######.###.#.#.#.###.#.#.#.###.###.###.#####.#.#####.#######.#.#####.#.# + #...#...#.#.....#.......#.#.#.....#...#...#.#.#.#...#.#.#...#...#.#.#.....#.#...#.#...#...#.#...#.....# + #.###.###.###.###.#####.#.#.###.#.###.###.#####.#######.###.###.###.#.#.#########.#.#####.#.#.#####.#.# + #.....#.........#.#.......#.#...#.#.....#...#.#.....#...#...#.#.....#.#.#.#...#.............#.....#.#.# + ###.#########.#######.###.#.#.#####.###.###.#.#.#.#####.#.###.#####.#.###.###.###.###.#########.###.### + #...#.........#.#.#.#.#...........#.#.....#.....#...#...#.#.#.......#.#.#.....#.#...#...#...#.#.......# + ###.#########.#.#.#.###.#####.#.###.###.###.#.#.#.#####.#.#.#.#######.#.###.###.#.#######.###.#.#.###.# + #...#.....#.#.......#.#.#.....#...#.#...#...#.#.#.#.#...#...#.......#...................#.#.#...#.#.#.# + ###.#####.#.#.#.###.#.###.#####.#.###.###.#########.###.#.#.#######.###.#.#####.###.#####.#.#####.#.### + #.....#...#.#.#...#...#...#.#...#.#...#.........#.....#.#.#.#...#.#.#...#.....#.#.....#.#.............# + ###.#####.#.#.#############.#.#####.#.#.###.#.#####.###.###.#.###.#.#.#####.#####.#.#.#.#.#####.####### + #.....#.......#.....#.#.#.......#...#.#.#...#.#.........#.....#.....#...#.......#.#.#...#.#.......#...# + #.#.#######.#####.###.#.#######.#####.#####.#########.#####.#####.###.#######################.#######.# + #.#.#.#.......#.#.....#.# Y Z L U D H G #...#...#...#.....#...#.# + #.###.#####.#.#.#.#####.# A H U O H S U #.###.#####.###.#####.#.# + #...#.#.#...#.#.......#.# #.#.....#.....#...#.#.#.# + ###.#.#.###.#####.#.#.#.# #.#.#####.###.#.###.#.#.# + #.......#.....#.#.#.#.#.# MZ........#.#.#.#.........# + ###.#.#####.#.#.#.#####.# #.#########.#.#.###.###.# + #...#.#...#.#.#...#.#...# #.#.#.#.........#...#...# + #.#####.###.#####.#.#.### #.#.#.#######.#.###.###.# +ZH..................#...#.# #.#.....#.#.#.#.#...#....QV + #.###.#####.#.###.#.#.#.# #.#.#.###.#.#.#########.# + #...#...#...#.#.....#...# #...#.........#.#.#...#.# + #####.#####.#####.#.###.# ###############.#.#.##### + #...#.#.....#.#.#.#.#....WT QV....#.....#...#.......#.# + #.###########.#.###.#.#.# ###.#.#.###.#.#.#.#.###.# + #...#.....#.#.#.#.#.#.#.# #.....#.....#...#.#.#...# + #.#.###.###.#.#.#.####### #############.#####.#.#.# +UO..#......................BT #.#.#.#.#...#.#...#...#..LY + ######################### #.#.#.#.#.#######.####### + #...................#...# #.....#.............#.#.# + #.###.#.#####.#####.#.#.# ###.###.###.#######.#.#.# +HO..#.#.#...#...#.....#.#.# #...#.....#...#.........# + #.#.#####.#####.#####.#.# ###.###.#####.###.#####.# + #.....#.#...#.....#...#..LY PY..#.........#.#.....#...# + #####.#.#########.#.###.# #.#.###.#.###########.### +MM......#.....#.........#..IZ #...#...#.....#...#......HS + ###########.###.#######.# ###########.#####.####### + #.........#...#.#.....#.# QW........#.#.#...#...#....MZ + #.#######.#.###.#.#.##### #.###.###.#####.###.###.# + #.#.........#.#.#.#.....# #...#.#.......#.#...#...# + #.#.###.#.###.#.###.##### #####.#.#.#####.###.###.# + #.#.#...#...#.#.#........HR #.....#.#...#...#...#.#.# + #.#####.#####.#####.###.# #.#####.#.#####.###.#.#.# +SH....#.................#.# #.......#...............# + ###.#####.#####.######### ###########.###.#####.### + #.#.#.#...#...#.#.#.....# #...#.....#.#.#.#...#.#.# + #.###.#######.###.#.###.# #.#.###.#.###.###.#####.# + #.#...#...#...#.....#.#.# JM..#.....#...#.....#...#..ZZ + #.#.#####.#.#####.#.#.#.# #.###.###.#####.#.###.#.# + #...#.......#.....#.#...# #...#.#.....#.#.#.....#.# + #.#.#.###.#####.###.#.### #.#####.#####.#.#####.#.# +BT..#.....#.........#.#....HO #.#...#.........#.#......PY + #######.#.###.#.#####.### ###.#####.#####.#.#.##### +LU....#...#.#...#.....#.#.# #...#.#.....#...#.#.#....UF + ###.###.#####.#####.###.# ###.#.###########.#####.# + #.....#.#...#.#...#...#..UF LE........................# + #.#########.###.#.#####.# #####.#####.#.########### + #.......#.....#.#.#.#.#.# #.........#.#...#...#.#.# + ###.###.###.#.#.#.#.#.#.# #############.###.#.#.#.# + #.#.#.......#...#.......# UN....#.#...#.#.#...#...#..DQ + #.#.#####.#.#.#.###.#.#.# #.###.#.###.#####.#.###.# + #.....#...#.#.#.#...#.#.# #.#.#...#.#...#.#.#.....# + #########.###.#######.#.# #.#.###.#.###.#.#.#####.# + #.....#.#.#.......#...#.# #.....................#.# + #####.#.#.#.###.######### S U D M A D ###.#.#####.#.#####.###.# + #...#.....#.#...#...#.#.# H V Q M B S #...#...#...#...#.....#.# + ###.#.###.#########.#.#.#####.#######.#########.#####.###########.#######.#######.#.###.###.###.#.###.# + #.....#.....#...#.............#...#.....#.........#.....#.#.......#.............#.#.#.....#...#.#...#.# + #.###.###.###.###.###.#####.#.###.#.###.###.###.###.#####.#.#######.#####.###.###.#####.#.#.###.#####.# + #.#...#.......#.....#.#.....#.#.......#.#...#.#.#.....#.#.......#.....#...#.....#.....#.#.#.#.....#.#.# + #.###.#.#.#####.#.#########.#.#####.#######.#.#.#.#.#.#.#.###.#.###.###########.###.#.#.###.#.#.#.#.#.# + #.#...#.#.....#.#...#.....#.#.#...#.......#...#.#.#.#.#.#.#...#.#...........#...#...#.#...#.#.#.#.#...# + ###.#.###.#######.#####.###.#####.#.#.#####.#######.###.###.#.#####.###################.#.#.###.#####.# + #...#.#...#...........#.........#...#...#.#...#.#.........#.#...#.#.....#.#.#...#.....#.#.#...#.#.....# + #####.###.#.#.#.#.#####.#####.###.#.#####.###.#.#.#.#.###.#.#####.#.#####.#.#.#######.#.#.#####.#.###.# + #...#...#.#.#.#.#.#.....#.#.....#.#.....#.....#.#.#.#...#.#.....#...............#.....#.#.....#.#...#.# + ###.#########.#.#########.#.###.###.#.###.#.###.#.#######.#####.###.###.###.#######.#.#.#########.#.### + #.............#...#.........#.#.#...#...#.#...#.....#.#.#.#.#.....#...#.#.....#.#.#.#...#.#.......#...# + #.#########.#.#.###.###.###.#.#####.#.#####.#######.#.#.#.#.###.###.#########.#.#.#####.#.#######.#.### + #.#.....#...#.#.#.#.#...#...#.#...#.#...#.........#.#.......#...#.#.#.......#...#...#.........#...#...# + #####.###.#.#.#.#.###.#.###.#.#.###.#######.#############.#####.#.#.#.###.#.#####.###.#.#.#.###.#.#.#.# + #.#.....#.#.#.#.#.#.#.#.#.........#...#.#.....#.....#.#.....#.....#.....#.#.#.#...#.#.#.#.#...#.#.#.#.# + #.#.###.###.###.#.#.###.###.###.###.###.###.#.###.###.###.#######.#####.#####.#.###.#.#.#.#.###.#.#.#.# + #...#.......#...#...#.#.#...#.#.#.#.......#.#.....#.#.#...#.........#.#...#.........#.#.#.#...#.#.#.#.# + #.#####.#.#.#######.#.#.#.#.#.#.#.###.###########.#.#.###.###.#######.#.###.###.###.#.###.#.#########.# + #.#.#...#.#.#.#.........#.#.#...#.......#.#...........#.#...#.......#.....#.#.#...#.#...#.#...#.....#.# + ###.#.#.#.###.###.###.#########.###.###.#.#####.#.#####.#.#######.#####.###.#.#####.###.###.#######.#.# + #.#...#.#.#.#.....#.#...#...#.....#.#.#.......#.#.#.......#.#.......#.......#.....#...#.#.......#...#.# + #.###.#.###.#.###.#.###.#.#.#.#####.#.###.#.###.#######.###.#.###.###.#######.#.#######.###.#.#.###.### + #.....#.#.....#...#.....#.#.......#.#.....#.#.....#.........#...#.#...........#.....#.....#.#.#.......# + #################################.###.#########.#########.###.#########.############################### + D G L A Y Q + H U E B A W diff --git a/2019/day20_donut_maze/tests/sample_input b/2019/day20_donut_maze/tests/sample_input new file mode 100644 index 0000000..d051133 --- /dev/null +++ b/2019/day20_donut_maze/tests/sample_input @@ -0,0 +1,37 @@ + Z L X W C + Z P Q B K + ###########.#.#.#.#######.############### + #...#.......#.#.......#.#.......#.#.#...# + ###.#.#.#.#.#.#.#.###.#.#.#######.#.#.### + #.#...#.#.#...#.#.#...#...#...#.#.......# + #.###.#######.###.###.#.###.###.#.####### + #...#.......#.#...#...#.............#...# + #.#########.#######.#.#######.#######.### + #...#.# F R I Z #.#.#.# + #.###.# D E C H #.#.#.# + #.#...# #...#.# + #.###.# #.###.# + #.#....OA WB..#.#..ZH + #.###.# #.#.#.# +CJ......# #.....# + ####### ####### + #.#....CK #......IC + #.###.# #.###.# + #.....# #...#.# + ###.### #.#.#.# +XF....#.# RF..#.#.# + #####.# ####### + #......CJ NM..#...# + ###.#.# #.###.# +RE....#.# #......RF + ###.### X X L #.#.#.# + #.....# F Q P #.#.#.# + ###.###########.###.#######.#########.### + #.....#...#.....#.......#...#.....#.#...# + #####.#.###.#######.#######.###.###.#.#.# + #.......#.......#.#.#.#.#...#...#...#.#.# + #####.###.#####.#.#.#.#.###.###.#.###.### + #.......#.....#.#...#...............#...# + #############.#.#.###.################### + A O F N + A A D M