From f6adc7a8185020ec2eda9ac9c83528af5529241f Mon Sep 17 00:00:00 2001 From: Mattrixwv Date: Thu, 12 Dec 2024 13:24:28 -0500 Subject: [PATCH] Day 6 (almost) solved --- .../adventOfCode24/ProblemSelector.java | 9 +- .../adventOfCode24/days/Problem11.java | 214 +++++++++ .../adventOfCode24/days/Problem12.java | 408 ++++++++++++++++++ src/main/resources/days/Problem11.txt | 130 ++++++ 4 files changed, 760 insertions(+), 1 deletion(-) create mode 100644 src/main/java/com/mattrixwv/adventOfCode24/days/Problem11.java create mode 100644 src/main/java/com/mattrixwv/adventOfCode24/days/Problem12.java create mode 100644 src/main/resources/days/Problem11.txt diff --git a/src/main/java/com/mattrixwv/adventOfCode24/ProblemSelector.java b/src/main/java/com/mattrixwv/adventOfCode24/ProblemSelector.java index e62faee..fe0162c 100644 --- a/src/main/java/com/mattrixwv/adventOfCode24/ProblemSelector.java +++ b/src/main/java/com/mattrixwv/adventOfCode24/ProblemSelector.java @@ -9,6 +9,8 @@ import java.util.StringJoiner; import com.mattrixwv.adventOfCode24.days.Problem; import com.mattrixwv.adventOfCode24.days.Problem1; import com.mattrixwv.adventOfCode24.days.Problem10; +import com.mattrixwv.adventOfCode24.days.Problem11; +import com.mattrixwv.adventOfCode24.days.Problem12; import com.mattrixwv.adventOfCode24.days.Problem2; import com.mattrixwv.adventOfCode24.days.Problem3; import com.mattrixwv.adventOfCode24.days.Problem4; @@ -22,7 +24,10 @@ import com.mattrixwv.adventOfCode24.days.Problem9; public class ProblemSelector{ private static final Scanner input = new Scanner(System.in); //Holds the valid problem numbers - protected static final List PROBLEM_NUMBERS = List.of(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10); + protected static final List PROBLEM_NUMBERS = List.of( + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12 + ); private ProblemSelector(){ @@ -44,6 +49,8 @@ public class ProblemSelector{ case 8 : day = new Problem8(); break; case 9 : day = new Problem9(); break; case 10 : day = new Problem10(); break; + case 11 : day = new Problem11(); break; + case 12 : day = new Problem12(); break; default: throw new InvalidParameterException(); } return day; diff --git a/src/main/java/com/mattrixwv/adventOfCode24/days/Problem11.java b/src/main/java/com/mattrixwv/adventOfCode24/days/Problem11.java new file mode 100644 index 0000000..2b26134 --- /dev/null +++ b/src/main/java/com/mattrixwv/adventOfCode24/days/Problem11.java @@ -0,0 +1,214 @@ +package com.mattrixwv.adventOfCode24.days; + + +import java.util.ArrayList; +import java.util.List; +import java.util.Scanner; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import com.mattrixwv.Stopwatch; +import com.mattrixwv.Triple; + + +public class Problem11 extends Problem{ + private static final String inputFileName = "days/Problem11.txt"; + private List map; + + + public Problem11(){ + super(); + description = "Find the number of distinct positions the guard will visit."; + result = "Unresolved"; + } + + + public String runSolution(){ + Stopwatch timer = new Stopwatch(); + timer.start(); + + + //Read the file + map = new ArrayList<>(); + try(Scanner scanner = new Scanner(this.getClass().getClassLoader().getResourceAsStream(inputFileName))){ + scanner.useDelimiter("\n"); + while(scanner.hasNext()){ + map.add(scanner.next()); + } + } + + //Find the current location of the guard + Triple currentLocation = findInitialLocation(); + //Loop while the guard is still on the map + boolean inBounds = true; + while(inBounds){ + //Move in the direction the guard is facing as far as possible, then turn right + if(currentLocation.getC() == '^'){ + currentLocation = moveUp(currentLocation); + } + else if(currentLocation.getC() == '>'){ + currentLocation = moveRight(currentLocation); + } + else if(currentLocation.getC() == 'v'){ + currentLocation = moveDown(currentLocation); + } + else if(currentLocation.getC() == '<'){ + currentLocation = moveLeft(currentLocation); + } + else{ + throw new RuntimeException("There was an error in the location: " + currentLocation); + } + //Determine if the guard is still on the map + if(currentLocation.getC() == '\0'){ + inBounds = false; + } + } + + //Count the number of distinct locations visited + int count = 0; + Pattern xPattern = Pattern.compile("X"); + for(String mapLine : map){ + Matcher xMatcher = xPattern.matcher(mapLine); + while(xMatcher.find()){ + ++count; + } + } + + + //Save the results + timer.stop(); + result = "The number of distinct positions the guard will visit is " + count + ".\nIt took " + timer.toString() + " to run the algorithm."; + return result; + } + + private Triple findInitialLocation(){ + for(int row = 0;row < map.size();++row){ + String mapLine = map.get(row); + int startIndex = mapLine.indexOf("^"); + if(startIndex != -1){ + return new Triple<>(row, startIndex, '^'); + } + } + + //If it gets this far it was not found + return new Triple<>(-1, -1, '\0'); + } + + private Triple moveUp(Triple currentLocation){ + while(true){ + String currentMapString = map.get(currentLocation.getA()); + //If the current Y value is == 0 then the guard left the area + if(currentLocation.getA() == 0){ + currentMapString = currentMapString.replace("^", "X"); + map.set(currentLocation.getA(), currentMapString); + return new Triple<>(-1, -1, '\0'); + } + String nextMapString = map.get(currentLocation.getA() - 1); + //If the next Y value contains a # then the guard needs to move to the next stage + if(nextMapString.charAt(currentLocation.getB()) == '#'){ + currentMapString = currentMapString.replace("^", ">"); + map.set(currentLocation.getA(), currentMapString); + return new Triple<>(currentLocation.getA(), currentLocation.getB(), '>'); + } + //If the next Y value is a . or X then move to the new location and mark the current location with an X + else{ + currentMapString = currentMapString.replace("^", "X"); + map.set(currentLocation.getA(), currentMapString); + StringBuilder newMapString = new StringBuilder(nextMapString); + newMapString.setCharAt(currentLocation.getB(), '^'); + map.set(currentLocation.getA() - 1, newMapString.toString()); + currentLocation = new Triple<>(currentLocation.getA() - 1, currentLocation.getB(), '^'); + } + } + } + + private Triple moveRight(Triple currentLocation){ + while(true){ + String currentMapString = map.get(currentLocation.getA()); + //If the current X value is == the length of the string then the guard left the area + if(currentLocation.getB() == (currentMapString.length() - 1)){ + currentMapString = currentMapString.replace(">", "X"); + map.set(currentLocation.getA(), currentMapString); + return new Triple<>(-1, -1, '\0'); + } + String nextMapString = map.get(currentLocation.getA()); + //If the next X value contains a # then the guard needs to move to the next stage + if(nextMapString.charAt(currentLocation.getB() + 1) == '#'){ + currentMapString = currentMapString.replace(">", "v"); + map.set(currentLocation.getA(), currentMapString); + return new Triple<>(currentLocation.getA(), currentLocation.getB(), 'v'); + } + //If the next X value is a . or X then move to the new location and mark the current location with an X + else{ + currentMapString = currentMapString.replace(">", "X"); + map.set(currentLocation.getA(), currentMapString); + StringBuilder newMapString = new StringBuilder(nextMapString); + newMapString.setCharAt(currentLocation.getB() + 1, '>'); + map.set(currentLocation.getA(), newMapString.toString()); + currentLocation = new Triple<>(currentLocation.getA(), currentLocation.getB() + 1, '>'); + } + } + } + + private Triple moveDown(Triple currentLocation){ + while(true){ + String currentMapString = map.get(currentLocation.getA()); + //If the current Y value is == the length of the string then the guard left the area + if(currentLocation.getA() == (map.size() - 1)){ + currentMapString = currentMapString.replace("v", "X"); + map.set(currentLocation.getA(), currentMapString); + return new Triple<>(-1, -1, '\0'); + } + String nextMapString = map.get(currentLocation.getA() + 1); + //If the next Y value contains a # then the guard needs to move to the next stage + if(nextMapString.charAt(currentLocation.getB()) == '#'){ + currentMapString = currentMapString.replace("v", "<"); + map.set(currentLocation.getA(), currentMapString); + return new Triple<>(currentLocation.getA(), currentLocation.getB(), '<'); + } + //If the next Y value is a . or X then move to the new location and mark the current location with an X + else{ + currentMapString = currentMapString.replace("v", "X"); + map.set(currentLocation.getA(), currentMapString); + StringBuilder newMapString = new StringBuilder(nextMapString); + newMapString.setCharAt(currentLocation.getB(), 'v'); + map.set(currentLocation.getA() + 1, newMapString.toString()); + currentLocation = new Triple<>(currentLocation.getA() + 1, currentLocation.getB(), 'v'); + } + } + } + + private Triple moveLeft(Triple currentLocation){ + while(true){ + String currentMapString = map.get(currentLocation.getA()); + //If the current X value is == 0 then the guard left the area + if(currentLocation.getB() == 0){ + currentMapString = currentMapString.replace("<", "X"); + map.set(currentLocation.getA(), currentMapString); + return new Triple<>(-1, -1, '\0'); + } + String nextMapString = map.get(currentLocation.getA()); + //If the next X value contains a # then the guard needs to move to the next stage + if(nextMapString.charAt(currentLocation.getB() - 1) == '#'){ + currentMapString = currentMapString.replace("<", "^"); + map.set(currentLocation.getA(), currentMapString); + return new Triple<>(currentLocation.getA(), currentLocation.getB(), '^'); + } + //If the next X value is a . or X then move to the new location and mark the current location with an X + else{ + currentMapString = currentMapString.replace("<", "X"); + map.set(currentLocation.getA(), currentMapString); + StringBuilder newMapString = new StringBuilder(nextMapString); + newMapString.setCharAt(currentLocation.getB() - 1, '<'); + map.set(currentLocation.getA(), newMapString.toString()); + currentLocation = new Triple<>(currentLocation.getA(), currentLocation.getB() - 1, '<'); + } + } + } +} + +/* +Find the number of distinct positions the guard will visit. +The number of distinct positions the guard will visit is 4647. +It took 14.695 milliseconds to run the algorithm. +*/ diff --git a/src/main/java/com/mattrixwv/adventOfCode24/days/Problem12.java b/src/main/java/com/mattrixwv/adventOfCode24/days/Problem12.java new file mode 100644 index 0000000..b292ee2 --- /dev/null +++ b/src/main/java/com/mattrixwv/adventOfCode24/days/Problem12.java @@ -0,0 +1,408 @@ +package com.mattrixwv.adventOfCode24.days; + + +import java.util.ArrayList; +import java.util.List; + +import com.mattrixwv.Stopwatch; +import com.mattrixwv.Triple; + + +public class Problem12 extends Problem{ + private static final String inputFileName = "days/Problem11.txt"; + private List map; + private List> patrolHistory; + private List> loopLocations; + //private int loopCounter = 0; + //private int LOOP_MAX = 7; + //private int LOOP_MAX = 100; + + + public Problem12(){ + super(); + description = "Find the number of places that a new obstacle could be placed that creates a patrol loop."; + result = "Unresolved"; + } + + + public String runSolution(){ + Stopwatch timer = new Stopwatch(); + timer.start(); + + + throw new RuntimeException("This problem is not yet solved"); + + + //Read the file + /* + map = new ArrayList<>(); + try(Scanner scanner = new Scanner(this.getClass().getClassLoader().getResourceAsStream(inputFileName))){ + scanner.useDelimiter("\n"); + while(scanner.hasNext()){ + map.add(scanner.next()); + } + } + /* */ + //Answer: 6 + /* + map = new ArrayList<>(List.of( + "....#.....", + ".........#", + "..........", + "..#.......", + ".......#..", + "..........", + ".#..^.....", + "........#.", + "#.........", + "......#..." + )); + /* */ + //Answer: 19 + /* + map = new ArrayList<>(List.of( + "...........#.....#......", + "...................#....", + "...#.....##.............", + "......................#.", + "..................#.....", + "..#.....................", + "....................#...", + "........................", + ".#........^.............", + "..........#..........#..", + "..#.....#..........#....", + "........#.....#..#......" + )); + /* */ + + /* + //Find the current location of the guard + Triple currentLocation = findInitialLocation(); + patrolHistory = new ArrayList<>(); + loopLocations = new ArrayList<>(); + //printMap(); + //Loop while the guard is still on the map + traverseMap(currentLocation, false); + + //printMap(); + placePotentialLoops(); + //System.out.println("\n\n"); + printMap(); + + + + //Save the results + timer.stop(); + result = "The number of positions that a new object could be placed to create a patrol loop is " + loopLocations.size() + ".\nIt took " + timer.toString() + " to run the algorithm."; + return result; + /* */ + } + + private Triple findInitialLocation(){ + for(int row = 0;row < map.size();++row){ + String mapLine = map.get(row); + int startIndex = mapLine.indexOf("^"); + if(startIndex != -1){ + return new Triple<>(row, startIndex, '^'); + } + } + + //If it gets this far it was not found + return new Triple<>(-1, -1, '\0'); + } + + private void traverseMap(Triple currentLocation, boolean loopCheck){ + boolean inBounds = true; + while(inBounds){ + if(patrolHistory.contains(currentLocation)){ + patrolHistory.add(currentLocation); + break; + } + else{ + patrolHistory.add(currentLocation); + } + + //Move in that direction as far as possible + if(currentLocation.getC() == '^'){ + currentLocation = moveUp(currentLocation, loopCheck); + } + else if(currentLocation.getC() == '>'){ + currentLocation = moveRight(currentLocation, loopCheck); + } + else if(currentLocation.getC() == 'v'){ + currentLocation = moveDown(currentLocation, loopCheck); + } + else if(currentLocation.getC() == '<'){ + currentLocation = moveLeft(currentLocation, loopCheck); + } + else{ + throw new RuntimeException("There was an error in the location: " + currentLocation); + } + //Determine if still in bounds + //if(loopCounter > LOOP_MAX || currentLocation.getC() == '\0'){ + if(currentLocation.getC() == '\0'){ + inBounds = false; + } + //++loopCounter; + } + } + + private Triple moveUp(Triple currentLocation, boolean loopCheck){ + while(true){ + String currentMapString = map.get(currentLocation.getA()); + //If the current Y value is == 0 then the guard left the area + if(currentLocation.getA() == 0){ + currentMapString = currentMapString.replace("^", "X"); + map.set(currentLocation.getA(), currentMapString); + return new Triple<>(-1, -1, '\0'); + } + String nextMapString = map.get(currentLocation.getA() - 1); + //If the next Y value contains a # then the guard needs to move to the next stage + if(nextMapString.charAt(currentLocation.getB()) == '#'){ + currentMapString = currentMapString.replace("^", ">"); + map.set(currentLocation.getA(), currentMapString); + return new Triple<>(currentLocation.getA(), currentLocation.getB(), '>'); + } + //If the next Y value is a . or X then move to the new location and mark the current location with an X + else{ + currentMapString = currentMapString.replace("^", "X"); + map.set(currentLocation.getA(), currentMapString); + StringBuilder newMapString = new StringBuilder(nextMapString); + newMapString.setCharAt(currentLocation.getB(), '^'); + map.set(currentLocation.getA() - 1, newMapString.toString()); + currentLocation = new Triple<>(currentLocation.getA() - 1, currentLocation.getB(), '^'); + + //Check for the potential to create a loop + if(!loopCheck){ + Triple potentialLoop = new Triple<>(currentLocation.getA() - 1, currentLocation.getB(), '>'); + if(createsLoop(potentialLoop) && !loopContains(potentialLoop)){ + loopLocations.add(potentialLoop); + } + } + } + } + } + + private Triple moveRight(Triple currentLocation, boolean loopCheck){ + while(true){ + String currentMapString = map.get(currentLocation.getA()); + //If the current X value is == the length of the string then the guard left the area + if(currentLocation.getB() == (currentMapString.length() - 1)){ + currentMapString = currentMapString.replace(">", "X"); + map.set(currentLocation.getA(), currentMapString); + return new Triple<>(-1, -1, '\0'); + } + String nextMapString = map.get(currentLocation.getA()); + //If the next X value contains a # then the guard needs to move to the next stage + if(nextMapString.charAt(currentLocation.getB() + 1) == '#'){ + currentMapString = currentMapString.replace(">", "v"); + map.set(currentLocation.getA(), currentMapString); + return new Triple<>(currentLocation.getA(), currentLocation.getB(), 'v'); + } + //If the next X value is a . or X then move to the new location and mark the current location with an X + else{ + currentMapString = currentMapString.replace(">", "X"); + map.set(currentLocation.getA(), currentMapString); + StringBuilder newMapString = new StringBuilder(nextMapString); + newMapString.setCharAt(currentLocation.getB() + 1, '>'); + map.set(currentLocation.getA(), newMapString.toString()); + currentLocation = new Triple<>(currentLocation.getA(), currentLocation.getB() + 1, '>'); + + //Check for the potential to create a loop + if(!loopCheck){ + Triple potentialLoop = new Triple<>(currentLocation.getA(), currentLocation.getB() + 1, 'v'); + if(createsLoop(potentialLoop) && !loopContains(potentialLoop)){ + loopLocations.add(potentialLoop); + } + } + } + } + } + + private Triple moveDown(Triple currentLocation, boolean loopCheck){ + while(true){ + String currentMapString = map.get(currentLocation.getA()); + //If the current Y value is == the length of the string then the guard left the area + if(currentLocation.getA() == (map.size() - 1)){ + currentMapString = currentMapString.replace("v", "X"); + map.set(currentLocation.getA(), currentMapString); + return new Triple<>(-1, -1, '\0'); + } + String nextMapString = map.get(currentLocation.getA() + 1); + //If the next Y value contains a # then the guard needs to move to the next stage + if(nextMapString.charAt(currentLocation.getB()) == '#'){ + currentMapString = currentMapString.replace("v", "<"); + map.set(currentLocation.getA(), currentMapString); + return new Triple<>(currentLocation.getA(), currentLocation.getB(), '<'); + } + //If the next Y value is a . or X then move to the new location and mark the current location with an X + else{ + currentMapString = currentMapString.replace("v", "X"); + map.set(currentLocation.getA(), currentMapString); + StringBuilder newMapString = new StringBuilder(nextMapString); + newMapString.setCharAt(currentLocation.getB(), 'v'); + map.set(currentLocation.getA() + 1, newMapString.toString()); + currentLocation = new Triple<>(currentLocation.getA() + 1, currentLocation.getB(), 'v'); + + //Check for the potential to create a loop + if(!loopCheck){ + Triple potentialLoop = new Triple<>(currentLocation.getA() + 1, currentLocation.getB(), '<'); + if(createsLoop(potentialLoop) && !loopContains(potentialLoop)){ + loopLocations.add(potentialLoop); + } + } + } + } + } + + private Triple moveLeft(Triple currentLocation, boolean loopCheck){ + while(true){ + String currentMapString = map.get(currentLocation.getA()); + //If the current X value is == 0 then the guard left the area + if(currentLocation.getB() == 0){ + currentMapString = currentMapString.replace("<", "X"); + map.set(currentLocation.getA(), currentMapString); + return new Triple<>(-1, -1, '\0'); + } + String nextMapString = map.get(currentLocation.getA()); + //If the next X value contains a # then the guard needs to move to the next stage + if(nextMapString.charAt(currentLocation.getB() - 1) == '#'){ + currentMapString = currentMapString.replace("<", "^"); + map.set(currentLocation.getA(), currentMapString); + return new Triple<>(currentLocation.getA(), currentLocation.getB(), '^'); + } + //If the next X value is a . or X then move to the new location and mark the current location with an X + else{ + currentMapString = currentMapString.replace("<", "X"); + map.set(currentLocation.getA(), currentMapString); + StringBuilder newMapString = new StringBuilder(nextMapString); + newMapString.setCharAt(currentLocation.getB() - 1, '<'); + map.set(currentLocation.getA(), newMapString.toString()); + currentLocation = new Triple<>(currentLocation.getA(), currentLocation.getB() - 1, '<'); + + //Check for the potential to create a loop + if(!loopCheck){ + Triple potentialLoop = new Triple<>(currentLocation.getA(), currentLocation.getB() - 1, '^'); + if(createsLoop(potentialLoop)){ + loopLocations.add(potentialLoop); + } + } + } + } + } + + private boolean createsLoop(Triple newObstacleLocation){ + if(loopContains(newObstacleLocation)){ + return false; + } + if(newObstacleLocation.getA() >= map.size()){ + return false; + } + if(newObstacleLocation.getA() < 0){ + return false; + } + if(newObstacleLocation.getB() >= map.get(newObstacleLocation.getA()).length()){ + return false; + } + if(newObstacleLocation.getB() < 0){ + return false; + } + if(map.get(newObstacleLocation.getA()).charAt(newObstacleLocation.getB()) != '.'){ + return false; + } + + boolean loop = false; + List originalMap = new ArrayList<>(map); + List> originalHistory = new ArrayList<>(patrolHistory); + patrolHistory = new ArrayList<>(); + //int orgLoopCnt = loopCounter; + //loopCounter = 0; + //int orgLoopMax = LOOP_MAX; + //LOOP_MAX = 1000; + + + StringBuilder mapLine = new StringBuilder(map.get(newObstacleLocation.getA())); + mapLine.setCharAt(newObstacleLocation.getB(), '#'); + map.set(newObstacleLocation.getA(), mapLine.toString()); + + traverseMap(originalHistory.get(0), true); + + /* */ + if(newObstacleLocation.getC() == '^'){ + //traverseMap(new Triple<>(newObstacleLocation.getA(), newObstacleLocation.getB() + 1, newObstacleLocation.getC()), true); + } + else if(newObstacleLocation.getC() == '>'){ + //traverseMap(new Triple<>(newObstacleLocation.getA() + 1, newObstacleLocation.getB(), newObstacleLocation.getC()), true); + } + else if(newObstacleLocation.getC() == 'v'){ + //traverseMap(new Triple<>(newObstacleLocation.getA(), newObstacleLocation.getB() - 1, newObstacleLocation.getC()), true); + } + else if(newObstacleLocation.getC() == '<'){ + //traverseMap(new Triple<>(newObstacleLocation.getA() - 1, newObstacleLocation.getB(), newObstacleLocation.getC()), true); + } + /* */ + + int lastLocation = patrolHistory.indexOf(patrolHistory.get(patrolHistory.size() - 1)); + if((lastLocation != -1) && (lastLocation != patrolHistory.size() - 1)){ + loop = true; + } + + + map = originalMap; + patrolHistory = originalHistory; + //loopCounter = orgLoopCnt; + //LOOP_MAX = orgLoopMax; + + return loop; + } + + private boolean loopContains(Triple loopLocation){ + for(Triple location : loopLocations){ + if(location.getA() == loopLocation.getA() && location.getB() == loopLocation.getB()){ + return true; + } + } + return false; + } + + private void printMap(){ + for(String mapLine : map){ + System.out.println(mapLine); + } + } + + private void placePotentialLoops(){ + for(Triple loopLocation : loopLocations){ + StringBuilder mapLine = new StringBuilder(map.get(loopLocation.getA())); + mapLine.setCharAt(loopLocation.getB(), 'O'); + map.set(loopLocation.getA(), mapLine.toString()); + } + } +} + +//! Too small +/* +360 +*/ +//! Too large +/* +1938 +*/ + +//! ? +/* +1065 +*/ + +//! ? +/* +Find the number of places that a new obstacle could be placed that creates a patrol loop. +The number of positions that a new object could be placed to create a patrol loop is 1682. +It took 1.641 seconds to run the algorithm. +*/ + +//! How? +/* +1723 +*/ diff --git a/src/main/resources/days/Problem11.txt b/src/main/resources/days/Problem11.txt new file mode 100644 index 0000000..0cfd1af --- /dev/null +++ b/src/main/resources/days/Problem11.txt @@ -0,0 +1,130 @@ +.............#........................................................#...#...........................................#........... +.....#...............................#.........................................#...#...............#........##...............#.#.. +..................................#..................#.......................................#...#................................ +.........................................#................#....#..............................................#................#.# +........#.........................................................#...........#.......#..............................#............ +........................#.............................#.......................#.......#.......................#........#.........# +................................#.......#............................................#...........................................# +...........#........#...#..#...........................#..................#.............#.......#..........................#...... +............................................#........#.......#..#......#..............................#..#................##...... +............#..#...#......#.........................................##.......#..........#.......#...................#............. +.....................................................................................#.....#...................................... +.......................................................#................#.....................................#................... +...........#.....#.#....................................#.......#.#...........#................#.......#.................#........ +............#.............#....................#....#............................#.........................................#...... +.#..........#......#................#........................#............#..#..............#..................................... +..................#....#...........................................#.....#.....#.........................................#.#...... +.............#..............#..#...........................#..#..........#...............................#........................ +.................................................................................................#................................ +.......................................................#..............#..............................................#..#......... +......#............................#.......................#................................................................#..... +..........#.........#..................#....#....#...#......#.........#.................................#........................# +..#...#............................#............#.......###.................................#.............................#...#... +.................#....#...................#........................................................................#..........#... +....#..........................#......................................................................#.....#......#.............. +.#........................................................................#..........#............#..................#............ +...................##.#.......................#....#.#........................................#.........##........................ +#...........................................................#..........#........#.#..................................#............ +.......#...#.........................................#.......#........#...............##..#....................................... +......................#....#...............................#......................................................#..#............ +......#.....................................................#...............................#......................#..#........... +.........................#.#...................................................................................................... +.......................................#...............#...................#................#..........#.#......................#. +.......#......#...#...........................#.........................#...............#..#...............#.............##....... +.....#..#..#..................#............#......................................................#...#.........................#. +#.#...............#...........#................#...................................................#..........#................... +..........................................................................#...............................................#....... +.........#.......#..........................#.##.............................#..##...#.......................................#.... +....#...............#..........#........................................#.....#.........................................#......... +...........#................................................#....##...................................................#..#........ +........................#........#...........#...#............................................#......................##........... +......#........................................#...#.............................................#................................ +#.....#......#..................................#.............#..#...............................#................................ +..................#......................#..........#...................#............................................#....#....... +.................#.............................................................................#.......#.......................... +......#........................................................................................#...#....................#......... +....#......................#..................##..................#.......#.......................#...........#.........#..#...... +............................................................#......##.............................#.#.....#............#.......... +..............#.......................#...^.....................................#.....................................#........... +..............#...##......#..#.....#..........................................................................#.......#.........#. +.#................................................................#........##......#....#.......#................................. +....#.....................#........#...........#.............................................#........#................#......#..# +...................#.............#.........#.........................#...........#..................#...................#....#.... +.#...............................................#.....#..#...#................................................................... +........................##............#.....................................#........#..................................#......... +..............#................................#.....................................#...................................#........ +...........#..........#...........#........#...................#..#..........................#.................................... +.#..............................................................#....#.......#.....................................#.............. +.....................#........#......#................#.............#........................#.......................#........#... +.........................#..............#...#....#..................#............................................................. +..#............................##.........................................................#...........................#.#..#...... +.....#............#...##........#..........#....#......#................................#.................#...............#....#.. +.....#...............#.............................#............#......#....#........................................#............ +...#..........#.........#.....................##.......#.....#...................#................................................ +.................................#...........................................#.................#...........................#...... +..........................................................#........................#.......#.................................#...# +..#......#......................................#...#..#....................#...........#....#.............................#...... +..#........#.............#......................#...#.....#....#........................#..#...................................... +.........#...........#.......................................................................#.........#....#...#................. +..................................#....#.............##....#.......#.........#.........................................#.......... +....#.................................................#.......#...........#.......................................##.....#........ +..............................#.........................................................#.....#........................#.......... +...#........#...........#..#..................................................#..............#.............................#...... +................................................#...............................................................#.....#..#.....#.. +...............#.........................#..#...................#....................................#................#........... +............................#...........................................................................................#......... +.....#.........................#.......#..#..##.............................#................##.......##............#............. +.........#........................................................................................................................ +.........................#............................#........................#.....#..........#.....................#...#..#.... +.......#........#..............................#..........................#...#.................#............#.................... +#...#..#...............................#..........................................#...#...#.........................#............. +...........................................................#..............#..........#..................#......................... +...........................................................#..............................................................#....#.. +...........#.......................#................#......#.....................................#..................#.....#....... +.....#.................................#........................#.#...................#.....#............#........................ +...........................#.#............#..............#..............#..#...#..........................#................#...... +.........#...................#........................#......#..#..................................................#.............. +.............................................#.................................................................#.......#.......#.. +#.......................#...............#.......................#...........#................................#.................... +......................................#............#....................................................##...................#.... +#...............#...........................................#......#....................................#...............#......... +...#...............#.................................#..................................#..#............#......................... +......................#..#............#..#..............................................#......#....#...............#............. +..................#.....................#.....#...................#..#................#....#..........#......#..........#......... +.......................#.....#..............#..........................#............#...................#.#....................... +......#...........#..............#........#........................................#......................................#....... +............#................#..##....................................................................#........................#.. +...........#....................................#.............................#.....#....#...#.#......................#........... +...................................................#...............................#....................#.........#............... +........#......#..#................#..................................................................#.................#......... +.............................#................................................#...........#.....#....#............................ +........#.............#.........#............#....#.....................#........#...............#................................ +..#................................#................................#..#......#.............................................#..... +.........#...........................................#..................................#....#..#.....................#........... +.....................................................#.........................................................#.................. +.........#...#.#.....#.......##................................#...#..........................#........#.......................... +......................##...............................#.......................................................................... +.........#...#.....#........................................#................#........#............#........#..................... +...............#............#.................................................................#................................#.. +......#..............#...................................................#............#.....................#..................... +.........#.........#.............................................................................................................. +.#........#...............#..##......#..............................#...........#..#.........#...........................#........ +...................#................................................................................#...............#............. +..............................................................................#........................#................#......... +...........#.....#..#.#....................................................#......#......#..#................##................... +....#......#...................................................................#..............#.....#.........#..................# +..#...........#...#...........#.......##..........##......................#......................................................# +..................#................................................#.#............................................................ +#................................................................#............#...##..........................................#... +......#............................................#.......#.#.................................................#.................. +..............................#..............#.#....#............#..........................#..................................... +............................#..................................#.................#..#...........................................#. +.........................................#................#..................#...#............................#..#......#........# +....................#..............................................................#..............................#..........##... +...#......................................#...........#..#............................................#.....#....#................ +................#..#....#......................................................................................................... +...................................#...................#...............................#................................#.......#. +..........#.................#.............#..................#...............................................................#.... +.....#...........#........#................#.........................................#..........................#......##......... +..........................#................#..............................................................#....................... +........#.................................................................#......................#.#..........................#...