From 9aa167c99b38149fd6d6c20b036b10aed47ecce8 Mon Sep 17 00:00:00 2001 From: Mattrixwv Date: Tue, 24 Dec 2024 15:56:59 -0500 Subject: [PATCH] Start day 15 --- .../adventOfCode24/ProblemSelector.java | 7 +- .../adventOfCode24/days/Problem29.java | 265 ++++++++++++ .../adventOfCode24/days/Problem30.java | 387 ++++++++++++++++++ src/main/resources/days/Problem29.txt | 71 ++++ 4 files changed, 729 insertions(+), 1 deletion(-) create mode 100644 src/main/java/com/mattrixwv/adventOfCode24/days/Problem29.java create mode 100644 src/main/java/com/mattrixwv/adventOfCode24/days/Problem30.java create mode 100644 src/main/resources/days/Problem29.txt diff --git a/src/main/java/com/mattrixwv/adventOfCode24/ProblemSelector.java b/src/main/java/com/mattrixwv/adventOfCode24/ProblemSelector.java index 5c95eaf..8dd9a26 100644 --- a/src/main/java/com/mattrixwv/adventOfCode24/ProblemSelector.java +++ b/src/main/java/com/mattrixwv/adventOfCode24/ProblemSelector.java @@ -28,7 +28,9 @@ import com.mattrixwv.adventOfCode24.days.Problem25; import com.mattrixwv.adventOfCode24.days.Problem26; import com.mattrixwv.adventOfCode24.days.Problem27; import com.mattrixwv.adventOfCode24.days.Problem28; +import com.mattrixwv.adventOfCode24.days.Problem29; import com.mattrixwv.adventOfCode24.days.Problem3; +import com.mattrixwv.adventOfCode24.days.Problem30; import com.mattrixwv.adventOfCode24.days.Problem4; import com.mattrixwv.adventOfCode24.days.Problem5; import com.mattrixwv.adventOfCode24.days.Problem6; @@ -43,7 +45,8 @@ public class ProblemSelector{ protected static final List PROBLEM_NUMBERS = List.of( 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, - 20, 21, 22, 23, 24, 25, 26, 27, 28 + 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, + 30 ); @@ -84,6 +87,8 @@ public class ProblemSelector{ case 26 : day = new Problem26(); break; case 27 : day = new Problem27(); break; case 28 : day = new Problem28(); break; + case 29 : day = new Problem29(); break; + case 30 : day = new Problem30(); break; default: throw new InvalidParameterException(); } return day; diff --git a/src/main/java/com/mattrixwv/adventOfCode24/days/Problem29.java b/src/main/java/com/mattrixwv/adventOfCode24/days/Problem29.java new file mode 100644 index 0000000..6f8f779 --- /dev/null +++ b/src/main/java/com/mattrixwv/adventOfCode24/days/Problem29.java @@ -0,0 +1,265 @@ +package com.mattrixwv.adventOfCode24.days; + + +import java.util.ArrayList; +import java.util.List; +import java.util.Scanner; + +import com.mattrixwv.Stopwatch; +import com.mattrixwv.Triple; + + +public class Problem29 extends Problem{ + private static final String inputFileName = "days/Problem29.txt"; + private static enum MAP_LEGEND {BLANK, BOX, WALL, ROBOT}; + private List> map; + private String movements; + + + public Problem29(){ + super(); + description = "What is the sum of all boxes' GPS coordinates?"; + 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\n"); + if(scanner.hasNext()){ + String mapGroup = scanner.next(); + for(String mapLine : mapGroup.split("\n")){ + if(!mapLine.isBlank()){ + List mapLineEnum = new ArrayList<>(); + for(char ch : mapLine.toCharArray()){ + switch(ch){ + case '.' : mapLineEnum.add(MAP_LEGEND.BLANK); break; + case 'O' : mapLineEnum.add(MAP_LEGEND.BOX); break; + case '#' : mapLineEnum.add(MAP_LEGEND.WALL); break; + case '@' : mapLineEnum.add(MAP_LEGEND.ROBOT); break; + default : throw new RuntimeException("Error parsing map. " + ch); + } + } + map.add(mapLineEnum); + } + } + } + if(scanner.hasNext()){ + String movementGroup = scanner.next(); + StringBuilder movementBuilder = new StringBuilder(); + for(String movementLine : movementGroup.split("\n")){ + if(!movementLine.isBlank()){ + movementBuilder.append(movementLine); + } + } + movements = movementBuilder.toString(); + } + } + + Triple currentLocation = getRobotLocation(); + for(char movement : movements.toCharArray()){ + switch(movement){ + case '^' : currentLocation = moveUp(currentLocation); break; + case '>' : currentLocation = moveRight(currentLocation); break; + case 'v' : currentLocation = moveDown(currentLocation); break; + case '<' : currentLocation = moveLeft(currentLocation); break; + default : throw new RuntimeException("Error in movement: " + movement); + } + } + + int sum = 0; + for(int row = 0;row < map.size();++row){ + List mapLine = map.get(row); + for(int col = 0;col < mapLine.size();++col){ + if(mapLine.get(col) == MAP_LEGEND.BOX){ + sum += ((100 * row) + col); + } + } + } + + + //Save the result + timer.stop(); + result = "The sum of all the boxes' GPS coordinates is " + sum + ".\nIt took " + timer.toString() + " to run this algorithm."; + return result; + } + + + private Triple getRobotLocation(){ + for(int row = 0;row < map.size();++row){ + int index = map.get(row).indexOf(MAP_LEGEND.ROBOT); + if(index != -1){ + return new Triple<>(row, index, 1); + } + } + throw new RuntimeException("Cannot find robot"); + } + + private Triple moveUp(Triple currentLocation){ + //Check if the robot can move up + boolean canMoveUp = false; + int numBoxes = 0; + for(int row = currentLocation.getA() - 1;row >= 0;--row){ + MAP_LEGEND nextSpace = map.get(row).get(currentLocation.getB()); + //If there is a blank space then move into it + if(nextSpace == MAP_LEGEND.BLANK){ + canMoveUp = true; + break; + } + //If there is a box, increment the counter and try the next space up + else if(nextSpace == MAP_LEGEND.BOX){ + ++numBoxes; + } + //If there is a wall then nothing can be moved + else if(nextSpace == MAP_LEGEND.WALL){ + canMoveUp = false; + break; + } + } + + //If the robot can move then move all the boxes and the robot + if(canMoveUp){ + map.get((currentLocation.getA() - 1) - numBoxes).set(currentLocation.getB(), MAP_LEGEND.BOX); + map.get(currentLocation.getA() - 1).set(currentLocation.getB(), MAP_LEGEND.ROBOT); + map.get(currentLocation.getA()).set(currentLocation.getB(), MAP_LEGEND.BLANK); + return new Triple<>(currentLocation.getA() - 1, currentLocation.getB(), 1); + } + //If the robot can't move then return the currentLocation as the new location + else{ + return currentLocation; + } + } + + private Triple moveRight(Triple currentLocation){ + //Check if the robot can move right + boolean canMoveRight = false; + int numBoxes = 0; + for(int col = currentLocation.getB() + 1;col < map.get(currentLocation.getA()).size();++col){ + MAP_LEGEND nextSpace = map.get(currentLocation.getA()).get(col); + //If there is a blank space then move into it + if(nextSpace == MAP_LEGEND.BLANK){ + canMoveRight = true; + break; + } + //If there is a box, increment the counter and try the next space to the right + else if(nextSpace == MAP_LEGEND.BOX){ + ++numBoxes; + } + //If there is a wall then nothing can be moved + else if(nextSpace == MAP_LEGEND.WALL){ + canMoveRight = false; + break; + } + } + + //If the robot can move then move all the boxes and the robot + if(canMoveRight){ + map.get(currentLocation.getA()).set((currentLocation.getB() + 1) + numBoxes, MAP_LEGEND.BOX); + map.get(currentLocation.getA()).set(currentLocation.getB() + 1, MAP_LEGEND.ROBOT); + map.get(currentLocation.getA()).set(currentLocation.getB(), MAP_LEGEND.BLANK); + return new Triple<>(currentLocation.getA(), currentLocation.getB() + 1, 1); + } + else{ + return currentLocation; + } + } + + private Triple moveDown(Triple currentLocation){ + //Check if the robot can move up + boolean canMoveDown = false; + int numBoxes = 0; + for(int row = currentLocation.getA() + 1;row < map.size();++row){ + MAP_LEGEND nextSpace = map.get(row).get(currentLocation.getB()); + //If there is a blank space then move into it + if(nextSpace == MAP_LEGEND.BLANK){ + canMoveDown = true; + break; + } + //If there is a box, increment the counter and try the next space down + else if(nextSpace == MAP_LEGEND.BOX){ + ++numBoxes; + } + //If there is a wall then nothing can be moved + else if(nextSpace == MAP_LEGEND.WALL){ + canMoveDown = false; + break; + } + } + + //If the robot can move then move all the bxoes and the robot + if(canMoveDown){ + map.get((currentLocation.getA() + 1) + numBoxes).set(currentLocation.getB(), MAP_LEGEND.BOX); + map.get(currentLocation.getA() + 1).set(currentLocation.getB(), MAP_LEGEND.ROBOT); + map.get(currentLocation.getA()).set(currentLocation.getB(), MAP_LEGEND.BLANK); + return new Triple<>(currentLocation.getA() + 1, currentLocation.getB(), 1); + } + //If the robot can't move then return the currentLocation as the new location + else{ + return currentLocation; + } + } + + private Triple moveLeft(Triple currentLocation){ + //Check if the robot can move left + boolean canMoveLeft = false; + int numBoxes = 0; + for(int col = currentLocation.getB() - 1;col >= 0;--col){ + MAP_LEGEND nextSpace = map.get(currentLocation.getA()).get(col); + //If there is a blank space then move into it + if(nextSpace == MAP_LEGEND.BLANK){ + canMoveLeft = true; + break; + } + //If there is a box, increment the counter and try the next space to the left + else if(nextSpace == MAP_LEGEND.BOX){ + ++numBoxes; + } + //If there is a wall then nothing can be moved + else if(nextSpace == MAP_LEGEND.WALL){ + canMoveLeft = false; + break; + } + } + + //If the robot can move then move all the boxes and the robot + if(canMoveLeft){ + map.get(currentLocation.getA()).set((currentLocation.getB() - 1) - numBoxes, MAP_LEGEND.BOX); + map.get(currentLocation.getA()).set(currentLocation.getB() - 1, MAP_LEGEND.ROBOT); + map.get(currentLocation.getA()).set(currentLocation.getB(), MAP_LEGEND.BLANK); + return new Triple<>(currentLocation.getA(), currentLocation.getB() - 1, 1); + } + else{ + return currentLocation; + } + } + + private String printMap(){ + StringBuilder build = new StringBuilder(); + for(List mapLine : map){ + for(MAP_LEGEND ch : mapLine){ + switch(ch){ + case MAP_LEGEND.BLANK : build.append('.'); break; + case MAP_LEGEND.BOX : build.append('O'); break; + case MAP_LEGEND.WALL : build.append('#'); break; + case MAP_LEGEND.ROBOT : build.append('@'); break; + default : throw new RuntimeException("Error printing map: " + ch.name()); + } + } + build.append("\n"); + } + return build.toString(); + } +} + + +/* +What is the sum of all boxes' GPS coordinates? +The sum of all the boxes' GPS coordinates is 1552879. +It took 12.728 milliseconds to run this algorithm. +*/ diff --git a/src/main/java/com/mattrixwv/adventOfCode24/days/Problem30.java b/src/main/java/com/mattrixwv/adventOfCode24/days/Problem30.java new file mode 100644 index 0000000..aaff8d4 --- /dev/null +++ b/src/main/java/com/mattrixwv/adventOfCode24/days/Problem30.java @@ -0,0 +1,387 @@ +package com.mattrixwv.adventOfCode24.days; + + +import java.util.ArrayList; +import java.util.List; +import java.util.Scanner; + +import com.mattrixwv.Stopwatch; +import com.mattrixwv.Triple; + + +public class Problem30 extends Problem{ + private static final String inputFileName = "days/Problem29.txt"; + private static enum MAP_LEGEND {BLANK, BOX_LEFT, BOX_RIGHT, WALL, ROBOT}; + private List> map; + private String movements; + + + public Problem30(){ + super(); + description = "What is the sum of all boxes' GPS coordinates?"; + 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\n"); + if(scanner.hasNext()){ + String mapGroup = scanner.next(); + for(String mapLine : mapGroup.split("\n")){ + if(!mapLine.isBlank()){ + List mapLineEnum = new ArrayList<>(); + for(char ch : mapLine.toCharArray()){ + switch(ch){ + case '.' : mapLineEnum.add(MAP_LEGEND.BLANK); mapLineEnum.add(MAP_LEGEND.BLANK); break; + case 'O' : mapLineEnum.add(MAP_LEGEND.BOX_LEFT); mapLineEnum.add(MAP_LEGEND.BOX_RIGHT); break; + case '#' : mapLineEnum.add(MAP_LEGEND.WALL); mapLineEnum.add(MAP_LEGEND.WALL); break; + case '@' : mapLineEnum.add(MAP_LEGEND.ROBOT); mapLineEnum.add(MAP_LEGEND.BLANK); break; + default : throw new RuntimeException("Error parsing map. " + ch); + } + } + map.add(mapLineEnum); + } + } + } + if(scanner.hasNext()){ + String movementGroup = scanner.next(); + StringBuilder movementBuilder = new StringBuilder(); + for(String movementLine : movementGroup.split("\n")){ + if(!movementLine.isBlank()){ + movementBuilder.append(movementLine); + } + } + movements = movementBuilder.toString(); + } + } + /* */ + /* */ + map = new ArrayList<>(); + map.add(new ArrayList<>(List.of( + MAP_LEGEND.WALL, MAP_LEGEND.WALL, MAP_LEGEND.WALL, MAP_LEGEND.WALL, MAP_LEGEND.WALL, MAP_LEGEND.WALL, MAP_LEGEND.WALL, MAP_LEGEND.WALL, MAP_LEGEND.WALL, MAP_LEGEND.WALL, MAP_LEGEND.WALL, MAP_LEGEND.WALL, MAP_LEGEND.WALL, MAP_LEGEND.WALL, MAP_LEGEND.WALL, MAP_LEGEND.WALL + ))); + map.add(new ArrayList<>(List.of( + MAP_LEGEND.WALL, MAP_LEGEND.WALL, MAP_LEGEND.BLANK, MAP_LEGEND.BLANK, MAP_LEGEND.BLANK, MAP_LEGEND.BLANK, MAP_LEGEND.BOX_LEFT, MAP_LEGEND.BOX_RIGHT, MAP_LEGEND.BLANK, MAP_LEGEND.BLANK, MAP_LEGEND.BOX_LEFT, MAP_LEGEND.BOX_RIGHT, MAP_LEGEND.BLANK, MAP_LEGEND.BLANK, MAP_LEGEND.WALL, MAP_LEGEND.WALL + ))); + map.add(new ArrayList<>(List.of( + MAP_LEGEND.WALL, MAP_LEGEND.WALL, MAP_LEGEND.WALL, MAP_LEGEND.WALL, MAP_LEGEND.ROBOT, MAP_LEGEND.BLANK, MAP_LEGEND.BLANK, MAP_LEGEND.BLANK, MAP_LEGEND.BOX_LEFT, MAP_LEGEND.BOX_RIGHT, MAP_LEGEND.BLANK, MAP_LEGEND.BLANK, MAP_LEGEND.BLANK, MAP_LEGEND.BLANK, MAP_LEGEND.WALL, MAP_LEGEND.WALL + ))); + map.add(new ArrayList<>(List.of( + MAP_LEGEND.WALL, MAP_LEGEND.WALL, MAP_LEGEND.BLANK, MAP_LEGEND.BLANK, MAP_LEGEND.BLANK, MAP_LEGEND.BLANK, MAP_LEGEND.BLANK, MAP_LEGEND.BLANK, MAP_LEGEND.BOX_LEFT, MAP_LEGEND.BOX_RIGHT, MAP_LEGEND.BLANK, MAP_LEGEND.BLANK, MAP_LEGEND.BLANK, MAP_LEGEND.BLANK, MAP_LEGEND.WALL, MAP_LEGEND.WALL + ))); + map.add(new ArrayList<>(List.of( + MAP_LEGEND.WALL, MAP_LEGEND.WALL, MAP_LEGEND.BLANK, MAP_LEGEND.BLANK, MAP_LEGEND.WALL, MAP_LEGEND.WALL, MAP_LEGEND.BLANK, MAP_LEGEND.BLANK, MAP_LEGEND.BOX_LEFT, MAP_LEGEND.BOX_RIGHT, MAP_LEGEND.BLANK, MAP_LEGEND.BLANK, MAP_LEGEND.BLANK, MAP_LEGEND.BLANK, MAP_LEGEND.WALL, MAP_LEGEND.WALL + ))); + map.add(new ArrayList<>(List.of( + MAP_LEGEND.WALL, MAP_LEGEND.WALL, MAP_LEGEND.BLANK, MAP_LEGEND.BLANK, MAP_LEGEND.BLANK, MAP_LEGEND.BLANK, MAP_LEGEND.WALL, MAP_LEGEND.WALL, MAP_LEGEND.BOX_LEFT, MAP_LEGEND.BOX_RIGHT, MAP_LEGEND.BLANK, MAP_LEGEND.BLANK, MAP_LEGEND.BLANK, MAP_LEGEND.BLANK, MAP_LEGEND.WALL, MAP_LEGEND.WALL + ))); + map.add(new ArrayList<>(List.of( + MAP_LEGEND.WALL, MAP_LEGEND.WALL, MAP_LEGEND.BLANK, MAP_LEGEND.BLANK, MAP_LEGEND.BLANK, MAP_LEGEND.BLANK, MAP_LEGEND.BLANK, MAP_LEGEND.BLANK, MAP_LEGEND.BLANK, MAP_LEGEND.BLANK, MAP_LEGEND.BLANK, MAP_LEGEND.BLANK, MAP_LEGEND.BLANK, MAP_LEGEND.BLANK, MAP_LEGEND.WALL, MAP_LEGEND.WALL + ))); + map.add(new ArrayList<>(List.of( + MAP_LEGEND.WALL, MAP_LEGEND.WALL, MAP_LEGEND.WALL, MAP_LEGEND.WALL, MAP_LEGEND.WALL, MAP_LEGEND.WALL, MAP_LEGEND.WALL, MAP_LEGEND.WALL, MAP_LEGEND.WALL, MAP_LEGEND.WALL, MAP_LEGEND.WALL, MAP_LEGEND.WALL, MAP_LEGEND.WALL, MAP_LEGEND.WALL, MAP_LEGEND.WALL, MAP_LEGEND.WALL + ))); + movements = "<^^>>>vv>v<<"; + //movements = "<"; + /* */ + + System.out.println(printMap()); + Triple currentLocation = getRobotLocation(); + for(char movement : movements.toCharArray()){ + switch(movement){ + case '^' : currentLocation = moveUp(currentLocation); break; + case '>' : currentLocation = moveRight(currentLocation); break; + case 'v' : currentLocation = moveDown(currentLocation); break; + case '<' : currentLocation = moveLeft(currentLocation); break; + default : throw new RuntimeException("Error in movement: " + movement); + } + System.out.println(printMap()); + } + + int sum = 0; + for(int row = 0;row < map.size();++row){ + List mapLine = map.get(row); + for(int col = 0;col < mapLine.size();++col){ + if(mapLine.get(col) == MAP_LEGEND.BOX_LEFT){ + sum += ((100 * row) + col); + //System.out.println("row = " + row + ", col = " + col + ", sum = " + sum); + } + } + } + + + //Save the result + timer.stop(); + result = "The sum of all the boxes' GPS coordinates is " + sum + ".\nIt took " + timer.toString() + " to run this algorithm."; + return result; + } + + + private Triple getRobotLocation(){ + for(int row = 0;row < map.size();++row){ + int index = map.get(row).indexOf(MAP_LEGEND.ROBOT); + if(index != -1){ + return new Triple<>(row, index, 1); + } + } + throw new RuntimeException("Cannot find robot"); + } + + private Triple moveUp(Triple currentLocation){ + if(currentLocation.getA() <= 0){ + return currentLocation; + } + //Check if the robot can move up + boolean canMoveUp = false; + boolean moveBox = false; + MAP_LEGEND nextSpace = map.get(currentLocation.getA() - 1).get(currentLocation.getB()); + //If there is a blank space then move into it + if(nextSpace == MAP_LEGEND.BLANK){ + canMoveUp = true; + } + //If there is a box, increment the counter and try the next space up + else if((nextSpace == MAP_LEGEND.BOX_LEFT) || (nextSpace == MAP_LEGEND.BOX_RIGHT)){ + if(canBoxMoveUp(new Triple<>(currentLocation.getA() - 1, currentLocation.getB(), 1))){ + canMoveUp = true; + moveBox = true; + } + else{ + canMoveUp = false; + } + } + //If there is a wall then nothing can be moved + else if(nextSpace == MAP_LEGEND.WALL){ + canMoveUp = false; + } + + //If the robot can move then move all the boxes and the robot + if(canMoveUp){ + if(moveBox){ + moveBoxUp(new Triple<>(currentLocation.getA() - 1, currentLocation.getB(), 1)); + } + map.get(currentLocation.getA() - 1).set(currentLocation.getB(), MAP_LEGEND.ROBOT); + map.get(currentLocation.getA()).set(currentLocation.getB(), MAP_LEGEND.BLANK); + return new Triple<>(currentLocation.getA() - 1, currentLocation.getB(), 1); + } + //If the robot can't move then return the currentLocation as the new location + else{ + return currentLocation; + } + } + + private Triple moveRight(Triple currentLocation){ + if((currentLocation.getB() + 1) >= map.get(currentLocation.getA()).size()){ + return currentLocation; + } + //Check if the robot can move right + boolean canMoveRight = false; + boolean moveBox = false; + MAP_LEGEND nextSpace = map.get(currentLocation.getA()).get(currentLocation.getB() + 1); + //If there is a blank space then move into it + if(nextSpace == MAP_LEGEND.BLANK){ + canMoveRight = true; + } + //If there is a box, increment the counter and try the next space to the right + else if((nextSpace == MAP_LEGEND.BOX_LEFT) || (nextSpace == MAP_LEGEND.BOX_RIGHT)){ + if(canBoxMoveRight(new Triple<>(currentLocation.getA(), currentLocation.getB() + 1, 1))){ + canMoveRight = true; + moveBox = true; + } + else{ + canMoveRight = false; + } + } + //If there is a wall then nothing can be moved + else if(nextSpace == MAP_LEGEND.WALL){ + canMoveRight = false; + } + + //If the robot can move then move all the boxes and the robot + if(canMoveRight){ + if(moveBox){ + moveBoxRight(new Triple<>(currentLocation.getA(), currentLocation.getB() + 1, 1)); + } + map.get(currentLocation.getA()).set(currentLocation.getB() + 1, MAP_LEGEND.ROBOT); + map.get(currentLocation.getA()).set(currentLocation.getB(), MAP_LEGEND.BLANK); + return new Triple<>(currentLocation.getA(), currentLocation.getB() + 1, 1); + } + else{ + return currentLocation; + } + } + + private Triple moveDown(Triple currentLocation){ + if((currentLocation.getA() + 1) >= map.size()){ + return currentLocation; + } + //Check if the robot can move up + boolean canMoveDown = false; + boolean moveBox = false; + MAP_LEGEND nextSpace = map.get(currentLocation.getA() + 1).get(currentLocation.getB()); + //If there is a blank space then move into it + if(nextSpace == MAP_LEGEND.BLANK){ + canMoveDown = true; + } + //If there is a box, increment the counter and try the next space down + else if((nextSpace == MAP_LEGEND.BOX_LEFT) || (nextSpace == MAP_LEGEND.BOX_RIGHT)){ + if(canBoxMoveDown(new Triple<>(currentLocation.getA() + 1, currentLocation.getB(), 1))){ + canMoveDown = true; + moveBox = true; + } + else{ + canMoveDown = false; + } + } + //If there is a wall then nothing can be moved + else if(nextSpace == MAP_LEGEND.WALL){ + canMoveDown = false; + } + + //If the robot can move then move all the boxes and the robot + if(canMoveDown){ + if(moveBox){ + moveBoxDown(new Triple<>(currentLocation.getA() + 1, currentLocation.getB(), 1)); + } + map.get(currentLocation.getA() + 1).set(currentLocation.getB(), MAP_LEGEND.ROBOT); + map.get(currentLocation.getA()).set(currentLocation.getB(), MAP_LEGEND.BLANK); + return new Triple<>(currentLocation.getA() + 1, currentLocation.getB(), 1); + } + //If the robot can't move then return the currentLocation as the new location + else{ + return currentLocation; + } + } + + private Triple moveLeft(Triple currentLocation){ + if(currentLocation.getB() <= 0){ + return currentLocation; + } + //Check if the robot can move left + boolean canMoveLeft = false; + boolean moveBox = false; + MAP_LEGEND nextSpace = map.get(currentLocation.getA()).get(currentLocation.getB() - 1); + //If there is a blank space then move into it + if(nextSpace == MAP_LEGEND.BLANK){ + canMoveLeft = true; + } + //If there is a box, increment the counter and try the next space to the left + else if((nextSpace == MAP_LEGEND.BOX_LEFT) || (nextSpace == MAP_LEGEND.BOX_RIGHT)){ + if(canBoxMoveLeft(new Triple<>(currentLocation.getA(), currentLocation.getB() - 1, 1))){ + canMoveLeft = true; + moveBox = true; + } + else{ + canMoveLeft = false; + } + } + //If there is a wall then nothing can be moved + else if(nextSpace == MAP_LEGEND.WALL){ + canMoveLeft = false; + } + + //If the robot can move then move all the boxes and the robot + if(canMoveLeft){ + if(moveBox){ + moveBoxLeft(new Triple<>(currentLocation.getA(), currentLocation.getB() - 1, 1)); + } + map.get(currentLocation.getA()).set(currentLocation.getB() - 1, MAP_LEGEND.ROBOT); + map.get(currentLocation.getA()).set(currentLocation.getB(), MAP_LEGEND.BLANK); + return new Triple<>(currentLocation.getA(), currentLocation.getB() - 1, 1); + } + else{ + return currentLocation; + } + } + + private boolean canBoxMoveUp(Triple currentLocation){ + //Make sure coordinates are in bounds + if((currentLocation.getA() <= 0) || (currentLocation.getB() + 1 >= map.get(currentLocation.getA()).size()) || (currentLocation.getB() < 0)){ + return false; + } + + //If the box is against a wall return no + if((map.get(currentLocation.getA() - 1).get(currentLocation.getB()) == MAP_LEGEND.WALL) || (map.get(currentLocation.getA() - 1).get(currentLocation.getB() + 1) == MAP_LEGEND.WALL)){ + return false; + } + //If this is the left side of the box check above the current location and the location to the right + else if(map.get(currentLocation.getA()).get(currentLocation.getB()) == MAP_LEGEND.BOX_LEFT){ + //TODO: + //Check the left side + //If there is a blank space then the left side can move + //If there is a box above the left side then recurse + //If there is a wall above the left side then it cannot move + //Check the right side + //If there is a blank space then the right side can move + //If there is a box above the right side then recurse + //If there is a wall above the right side then it cannot move + + //If both the left and right side can move then the box can move + //If either side cannot move then the box cannot move + } + //If this is the right side of the box recurse with the left side + else if(map.get(currentLocation.getA()).get(currentLocation.getB()) == MAP_LEGEND.BOX_RIGHT){ + return canBoxMoveUp(new Triple<>(currentLocation.getA(), currentLocation.getB() - 1, 1)); + } + //If the box is against nothing return true + else{ + return false; + } + } + + private void moveBoxUp(Triple boxLocation){ + //TODO: + } + + private boolean canBoxMoveRight(Triple currentLocation){ + //TODO: + return false; + } + + private void moveBoxRight(Triple boxLocation){ + //TODO: + } + + private boolean canBoxMoveDown(Triple currentLocation){ + //TODO: + return false; + } + + private void moveBoxDown(Triple boxLocation){ + //TODO: + } + + private boolean canBoxMoveLeft(Triple currentLocation){ + //TODO: + return false; + } + + private void moveBoxLeft(Triple boxLocation){ + //TODO: + } + + private String printMap(){ + StringBuilder build = new StringBuilder(); + for(List mapLine : map){ + for(MAP_LEGEND ch : mapLine){ + switch(ch){ + case MAP_LEGEND.BLANK : build.append('.'); break; + case MAP_LEGEND.BOX_LEFT : build.append('['); break; + case MAP_LEGEND.BOX_RIGHT : build.append(']'); break; + case MAP_LEGEND.WALL : build.append('#'); break; + case MAP_LEGEND.ROBOT : build.append('@'); break; + default : throw new RuntimeException("Error printing map: " + ch.name()); + } + } + build.append("\n"); + } + return build.toString(); + } +} diff --git a/src/main/resources/days/Problem29.txt b/src/main/resources/days/Problem29.txt new file mode 100644 index 0000000..731a353 --- /dev/null +++ b/src/main/resources/days/Problem29.txt @@ -0,0 +1,71 @@ +################################################## +#O#...O...O..#....O.OOO..#...........O.#..#.O..#.# +#...O.#.O....O.O#.....#OO....O............O......# +#..O.#.OO.O.......#.O#O..#..O.O...#.OO.OO.OOO#O.O# +#..O..O.O..O.O...OO.O.OO.#.##....O.O#.O...#O..O..# +#..O.O....O...O...O.OOO.O.O.....#.OO.O.O.#O.OO.O.# +#.....O..#......#......O.....#....#..O#O......O..# +#.....OOOO.........OOO.O.O.O...OO.O.......O.....O# +##.O..#.O.......#.....OO.......O...#.........OO..# +#.O.#....##..O.O..O#....OO.......O..OO#OO....#...# +#...............O....#O..#O..OOO.O.#O.O#.O.#..O..# +#OOO#..O.OOO..O.......OO#O..#..O.O#.....O.O..#...# +#O...O...#O....O..O.O...O#.O.#..O#O..OOO..#...#..# +#.....O.O...#...O.OO....#.O#...O..O.O.#....O.#...# +#O.....#....O..O#.O.O...O.O..OO##..#O......O#...O# +#O...O.#..O#...OO..O.#O.....O#.O.O.O.##O...O...OO# +#...O#...#.O.O.......OO..O..O.OO.#.OO.O..O...##..# +#..O.O..OO...O...O..OOO.O.......#.....#.O..O#...O# +#.O.OO#...O..#.OO.#.#.#..O.OO....O.#O#..O.OO.....# +#.OO..OO.OO...OO.....#....O#.O.OO#O#O...O....##.## +#...O..O.OO#..#....OO........#.#........#........# +#..#..O.O...#..O.###O........OO..#O.O..OO.O.O.#O.# +##.OOO..OO.#.O......#.O...O.O...#O#...O....#O...O# +#...O....O..O...OO.......O...O.OOOO....O#O...O#..# +#....O.O......#.........@.O..#....##O.#...O.#...O# +#O...#OO#OOO......##.#.....#O..O........O..#...#.# +#....O......O..O...O.......O.O.....O.O..OO.#OO...# +#......O........O..O...O...#OOO.##...#..#...O...O# +#OO...O.O.O.OOO.#OO#.O..O..O...#O..O....O.#..O...# +#.O.O.#O....O#O..#.O#.OOO....OO.#.O.....OO....O#.# +#..O..O.O.O.#...O....O..#......O....#...OO.O...O.# +#....O#..OO...O......OO..O.O....#OO.O....OO...##.# +#..OOOOO#OO#.O..OOOO.O.....O.O.O.OO.....OO..OO..O# +#.....O...OO.O#..#..O.O#O..........O......O.O..O.# +#O..OO#...O...O..OO.OOOO#OO....O.O..O..OOO..#..O.# +#...O..O...##.O.#.OOO......OO..O....#........O.OO# +##...#O.OO..O....O#...#..OO.O.O..O...O#..#...OOOO# +#O.#.O.....O#O.O.....#O...OO..............OO..O..# +#..OO..O............OOO..O.O.O..O..O.......O.#...# +#.O#...#..O.O..#O..#..#O.O.....#....O.#O....#O..## +#O.O.O.O#..O.O....O#OO...O....O.OO.OO.O....#....## +##O.#..#.#....O..#O..O..O.#...O..O.#.OO#..O.....O# +#.#.............O.O#..##.O....O...#......O..O..O.# +#.O...O...O..#.O...OO...O.#OO#O.O..##.OO.#...OOO.# +#.O.........O..#.O...........OOOOOO.OOO##.#.O.OO.# +#....OO.O.........#...OO.O.O..O......O#.OO#.O..OO# +#.....O......O#..O..O...O..O..O.O...O.O..O.#O...O# +#.....O...OO...........O....OO.O.....O.O...O.#O..# +###.OOO...O##.O..O#......OO....O..#.OOO#O....OOOO# +################################################## + +<>v>>>^v<<^<^^<^v<^^v>>>^>vv>^<<^<^^v<<>>>>^<>^^v<^^<^<>>><^>vv>>^^^<<<>^^v^^v^>^^v>^><<<>^><^v<<><^>^>>v^v^^v<^>v<<>vv<<<<<<<^<<^vv><><<>v>>vv^>^^<>^^^v^<^>><>v>v>v>>^<<<^^>v>>vvv<<^v><<>><<<^<><^^^><^>><^^>v<>^^vv<<<<>^^^>><>>^><^v<^v^>^v^<>^<<^^>>^vv<^^v<<>>vvv^^<^vv>v^<<v><>><>v<<<<><<<>v^>v^<<^^^v>>v><^^vvv><^<>vv>^^^^>v><>^v<>v^^^vv>^vvv>v^^><>vv>^>^>>>v<<>><>>^vvvv>^v^<<>^^^^>^>vv<^vv>vv<^>>vv>><<^^^^><<>>^v>>>^^^^v>^^^<>><<>v><>^vv>^^^vvvv^^>>^^v>v^>^v<^v^<<<^>^><^><^<<^vvv^^v^^v<^^v^^>^^><^><^<^>vvv^<<^v^^^^^v>^>>>^^v<>><>^<>>^v^v<^vvv^^^v<^v^^v><>v><<><^v<>^v^^<<^vvv><^>>^vv<<<>^vv<^^><><^>>>v><>^^<<<>vv>><^<<^<^^^^<><>v^<<^<^<><><>v<v>vv>^v>^>^^^>^^><><>vv<^>v>v<^v>>v><<>>^<>>v<>v^<^< +>v<><^v<>>>^^>>v^<^v^<^v^<><^^<>^^^<<><>>^v^^v^^^>^^>>>>^<^^<^>v^><<^>>vv>^<>>vv>^v>^><^<vv<<<><<>>vv<^<<>^vv<^^>>^^v>^<>>v><<<>vv>>v>><^^v^<>vv>^<>v^<<<^v>^<^>vvv>>v>><<><><><<><>v^>>>>v<^v>^>vv^>v^<^>^^^^v^^v<>v><<^>v<><><<<^^v<^v>^^>^v^>^^<<^<>^>v^v>>><^>>^^<<^><^v^v^v>>v^^<^^<>>^<^>^vv^^^>>>>>v<^vv>vv^vvv>><^^<^><^>>><<<<^^>v^v<^vv^^><<<>v<<<>>vv><>>^^<><<^vv>vv^>>^>vv^vv><>^><>^^v>vvv<>^>>^^>>v<>>>><<><^v<^<^><>>>^v<^<^<<>>v^>>v^<><^vv^>vvv>vvv^v<^><><^><>vv<>>>v^>^v<<>v^^^^<^^v^^^^^<<><<^v>v>vvv>v^vvv<^^>vvv^v>^>^<^<^>v^>v>v>^v^>><^vv^^><>>^^>v^^^v>v^>>v>>^<>^v<<<^^>^<<>v>^<^>^v<>^<>^^v^<>>vv>^^v<<^v<^v<<>v>>v<<><<^>^^^<<^v><>^^>^^<><<><^>^^^>><<>>>>v<>>< +>vv<^>vvv><>>vvvv^<>^>vvvv^vv<^^v^vv^^v><>^v^<^<^<^^v<^vv^>v><>^vv><<>>vv<^<>vvvv><>>^>>v^<<^>>>^^>>>><<>>>vv^><^^<^^>^v^^><<^<>>>^>^><><<><^v<^v>><>^^vv><^^^><^<><><>^^<>^v^v>>^^<<^^vv>><>v^v>^><^vv<<^^v^v^v^^>^v>vv<<>v>^v^<><>v^>v^><<^<^>^>^>>^<><<<<>vv>>^^v^^^v>v^<<>^v^<>><<<^^v<>v>^v<^^><><<^><>^vv><>vv^>^>>v>>>^vv^<^>^v>>^v>^^<^<^<^><^<>>^vv^vv<>vv<^>^><>>vvvvv>^>vv^v^^v^^>>>>v>vv<>>>vvvv^>>><><>v>>^>v<>>^^^^<^><>^<^^>^v<^v^v^^>^^^>v<^v><<^v>>v<v<^^v^^^><>^>>><<<<^<>^v>^v>^^vv^vv>^v^<^<^^<<>^^><<>><^v<<^v<>>^><><>vvv><<^v<>>>vvv<<^>v>^v<vv>vv^v>^>^<>^><<>>^^v^>v^>v><>v><>^<>>^>^^v>^<^v>>^>^v^v>>v><<^^^<^>v^>^>^vv>>vv^vv^>>>vv>^vvv^v^> +>>v^<<>^<>^^v<^>>v^<^^vv>>>><<>>>vv>vv^>v<>>^^^^><>vvv^v><><>vvv^v>>v>^v^^<>>^>^v^^<>>>>^^>>>>>^^v>^v<<^v^><<^>vv<v^vv>v^^v>^<>>>>><^<<^<<^v>>^^>>v>^^^^>>>>^^vvvv>v>>^<^>^>>>vv^v>^vv^^<<<<><^<^v^^^v<^>^vv^>^^>^^^v<<<<>^<<>^v><<>v>^vv<^>^^^>v^<>^>vv>>>>^v>^^><>>v<^>^>^^>vv<v>>v>^>^>>>vv^>><>>>vvv<^^^<^>>v^<>^<>>^v>v<<>vv^>v^>v^<>>^<>vv>><<<<<<>^^v>v^v^^>>><^<<^^<^v<^><><<<<>vvvv^<>>>>^><^<^^vvv^vv<<>><^>^v^<<>vv<<<^<^>^<^v^v>v>><^v^><><><>^<^vv>>>vvv^<>>^>^v<<^^><>v>^<>v>v<>>>>v<>vvv^>^>v><>v>>v^v^^vv^v>^^<^>>^^v<><>>>>vvv>v>^v^v^><<>v<<<<<>^vv>^>^>^>^v<<>^>v^^><^>v><>^^<^>v<>>><>^v><<^vv<^^v>v>><<^>^v^<>vv><<<<>v>^^<^><^>^<<<>><>>vv<>^><>>^<^<>v>^>^<^>>v^<^<^vv>^>>v^^>^^^v^>>>v +v^<>^<>v^vv>^><^v>vv^>^<<>^^<<^^v>v^v^>^><^^^<>>^<^^<<^>^^>v>^<>^^^^vvvv^v^v^v<<^<<<^v<^>^>>><><^^>>^^>^vvv>v^^vv^v^<>v<<^>v^>>>v^v<^<>^<>^^><><><<>v>v^v>^^<<>^v><>^><v^><>v><vv<^>^<^vv>^^vvv>vv<<^v^^v<^<>>v^^>><>vvv<<>^>>^<^<^^v><>v>^<>>vv^^>^<^><^^^^v^<>^><^^^>vv^<^^v^><<^<<>^^<^^<^v<^v^v<<<>^>v^>^><>^>^<>^>v>^><>v>><<^<<>><<^^><><^^v>v^><><^<>>><^>v>^>^>^^v>^^v><>>>v>v>v^vvv>^^^^<>^><^^>v<^>^^v^>^>^>^<<><>v<<>v^><<^<<>^v<>>>>>^>v^<><v>><<>>^<>^<^<>v<<^<^v>^vv<>^v<^<><>^^v>^vv>v^v^^v><<v><>^^<>v<^>>>vvvvvv^<^^v<>^><^<>v^>v<<^>vv^<^^<<>vv^vv^^<<>v^^<^<<<><>>^<^^^^>^^>v<^>v<>><<<>v^^vvv<<<^>>><<>>v>^^v<^v>>><<>^<^^<><>vv^>>v>^^^>>>v>^^^^^<>^<<^<>^^>^>><^>vv^^^>>^>^v^v< +^>^^v><>>>>^^^v^^><>>>v<^<>>^>^<^^><^vvv^<<^^^>^v<^<>>v<>^^v<^<><^^^v>^v^^v>><>>v<>vv>^>vv^<><>^vv<>>vv>^vvv<^v^^^vvv^^v>^v<^v><^<^<<>^>>^v>>^vv>>>v^<^^^>^<><<<>>^vv>^^^>>><<>vv>^>v<>v>v^>^v^<<>vvvv^^vv^<>^^vvvv<^^><^>^>^v^^<<>><<^^<<>^><^^>>>v^^^^>^vv<<<>v>^v^v^v<^><^>^v<^>^^>>v^>vv^><^^<<^^><>>v^<<^^>v^^^<^>^^v>>^><>^<<>v^v^^>v>>v^<>v^>v><^>v^<v>><^^^>vv^^v<^>^v>>>v>^>^^>>>^<>v^^>^^v^^v<>^>>v<^v<^^<^v<^>^v^^vv<>^^^v<^v^>v^><^<<>v>vv^>>><>v<v^^v<<^><>vv^>>><>v<^>v>^>^^><^^>v>v>^^>><>>^v^<<^<<^v<^><^v^^^v<>v^^v<v^>^v^v<>><<>v>>^>v>v><>>><<^>v>v<>v>>^^<^v^vvv^>v^^^^<<><>v>vv^vv<<>>v<><>>>^<>v<<^^<^^v<^>^v<^^<^vvv<>v^v>v<^>>>vv^v>>^<^ +<^^v<>v>^>>v>vv>^^>v<>^vv^<<>>vv>v<<>vv>vv>><<<>v>>^<^v>>^vvv>vvvv>v^v^^<>><^vv>>>^^>^>>^^>>^vvv^<<<<^v^v^v>>^^v><>>>><^^<^^v>>v>>^^^v<<^><<^^vvv<><^v<^>vv>^<^<>>>>^^^v^>^^v<<^><^v<><^v<^v<^<^vv^<^<^^v^^>^<>^v>^^vv^<^><^^v<^v>^<^vvvvv>><<^^^^<>^^^v^>><>^><^<>>>v>v^<<><^v<<^<>>>vvvv^^>^v>>^^<^^^^>v<^><>>^><>>>^^>^>><^><>vvv^^v<>>^^v>>v>>^><^<>v^<<^vv<<>^>v<>v<>^>>^vv^^<<^v<>^<<<^^<<^><^<<^v>vv>>>^<^v<^v^<><>v^v^<<>v^>^>v<^<<<>v^v>>^^^>><^v>^><<<^v><^v^>>^^vvv>>>^>^v>>>>^>vv^>^<<>^>>^^vv^v>^^><v<<>^>><>vv^^>v>^><<<>>>>>>^>>v>>>^<<<^^^v>vvv^>>>>>v>><<>^>^>>>^v>^^>^>v<^v^^v<>^><<^<>^^<^<^^<>>v^^^v>^v>v<>vvv>v>>>^>^>>^<<>^><^v^vvv<>vvv>>v^>v>^>v<^v>v>^v<><>^^>^<<>v^>^^><<^<>><>^^vv< +<><^^<>^v>v^^>>^^^<<>^v^>><<<>v^^v>><<^<>><>^^^vvv<>>^v<^^^>v^>^>^>vv^>v^>^vv<>v>>v<<>^>^<^<^><><>vv>^>^vvv<>^<^v^>^<<<>v^vvvvv>^<>vv<^^<<>vvv^>>>vv>^^^^^^vv><^v>v<>>^^<<><<>^v>^v^^<<^^v^^v>^v^>v>>v^^^^^<^v>>vvvv>>^^>>^v^v^<>v^vv^vv^^><>>v>^v^>^^^vv>^^>^v^>^>><>vv^vvvv<^^<<^v>>^<<^><>v><>vv><<><^^vv^^>vv^v^>vvv^v><^^<^v>>><<>^>vv^^vv>v>v^v^^^^<^vv^<>>v>><^vvvvv<v>^><>^>>v^<<^>v^^<>v^<^<^v<^^<>>>>^^>^><>><><>^>v>^<^><<^v<^^>>>^>v>v>v>v^>^>v>>><>v^^^v^vvv><^^>>^>^>v>^^<^^vvvv^^<>^^>v^vv<>^^<^<><>>^^^><^^v<<<>v>^v>^v>^<^^^<^>^^><>^<><>v>><^>>vv^>>>v>><^<><^^>><v^v>vv<^><<<<>>><>>v<^^>>vvv<>^v<<>^><<><>^^><^>v<^^^>^<^^>^^v>>^v>><^>^<^>><<^^>v^>v^^<^<<^^^>vv^>vv>>v>vv<<^v<><><^^^v^v<^<^^>vv>^vvv<^><<^>^v<^^v^v^><<^^^v<^<<>^>v^^^^<>^v^v^>v<^>>^vv<>^><<>^^^v^^><>v<^>>><>^^><>><< +v^<^>>^><>>>vv^v><<>^v^v^^>><><>><^<>^<>^<<<^<>><^^v><<>>v^>^<v><^>^vvv<>^>v<^>^<^>^v>>v>>^^v^^^v^^<><<^^^>>^<><^>v><^v<^^<^v>v>>v>^>v^^>v>^^^v<>^v<>^<v<^>>v>>>><<^>>v>^<>^^<>^v^>^v<<^<>v^^>v>vv>^v^<^>^>vv^<^<>^>v>^vv<<^vv^<<><<>^^vvv>^^>^>^<<>vvv>>vvv>>>v>v<><<><^<><^v>>v^v^<<^<^<>>^<^>>vv>>^^<>v^^><<<^>^vv^<^<^<^v><>^>^v^>>^^<><^^^>v<<>v<^>>v>>v<>>^v>^>>><>v>^>v<^><^>><^v<^v<>v^^^<^<<^v<>><<^<>^^^^^^>^vv>>vv>v^<><><<<<>v<^vv^^<<>v>>v^>>^>^v>v^v^>>>^>>v^>^^>v^<^^v>><^^>^><<>^v<>v<>>>v<>><>v>v<^v^<><^v>>v^>v<^<><^<<>>^<<<<^^vvvv>v^>^v>>^vv<<^>v>^^v<^<^v<^>>v^<^^>v<^>vv^>^<<<^^^v>^^^>v<^<<<<>v^v^>>^vv>^>>>vvv>>^^^^^>^v<>^v^v<<>^<>>v>vvv>^^v>^>v^><<>v>^^<^v^>vvvv>>v>>^^>vv^v^^v><>^^^<<>^^vvv><<^<>>^<<<>>v>>^^^<<^<^<> +^<>v>v^^>><^v^><>>^<>>^>>^vv><<^v>>^vv<^>>^vvv<<^>^><>>v>vv^^v<<^^^>^^^v>v^<<^vv>>^v>vvv>^v^^>v>v^v<>v^^<>^v>>>><^v<^^^>v^><>v^^>v<>vv<>vv<<^vv^v>>>>^v^>^^>v^><><<^^v<<>v^^^>>v<<^^>^v^vv><>vv>><>v<>>>>^>^<>v>v><^<><>>^<>^^v^>^v>v^^^>v^<>v^>>^^vv<^>^^vv>v><<<<>>>v<^^v^v><<<^^^^><>^vv>^>^<^^v>^v>>>v<<^>>^^^<<>>v^><^v^v<><>^^^>v<v^v>>vv>^><^^vvv<^v<>^vvv<><^v<^>><^>><>^^^^>^v<>v^>^>^v<><^^^<>v^v><^<><>>v<<<><<>^>^>v^^v^^<<><>v><><>vv>^<<vv^^>v>>^^^^^^vvvv^<<^v>>vvvv>vv^^v^vv^v<>>^><^^v><^^>^^<^^^>v<^<><<<>^^^^><<^<>v>>^^><<>>vv^^>^<>vv^^^>v>v>><vvv>v>vv>^>v>><>>^>>v<^^<<^>^>^>>><>v^>>vv^v<<^v^^vvv^^>^^vv<<^<>^>^^^vv^>>>^v>^<><<^>^^>^v>>^^<>>^^><^^^<^vv^^v<^<^><<<<>v><>>>>>>^^<^^<^<><>v<<^^vv^^v<<><^^>^>vvv><>^^<<<>^>v^>v>v>^ +v<v<^^^^^v^<>v<^v^^<<^vv^v>^v<^v<>^v<vv<<^^>>>><^>v<^>v<>^<><><<<<^v^><^vv>^^^><<<^<<^^>^^>v>^v>>^>>>v<>>>><<<>v^>v<^vvv<>>^^v>^>v><<<^v>^^<<^>>>v^><^><>^>v^v>^vvv<>>^>^><>^v>>^>vv<^><>>>vvv>>v>>>v<v<>>^^<>v^^v><^^v^v><^v^><^v^<><>v<>vv^v<>^^<>vv<^>v^^vv^^<^v>>v>v^vvvv^<<<^vv^v^^vv<<><^>v>vvv<^v<><<^>>^v><>>v><^^><^><>><<>>vv^^>v<^<^^<^>^<^v>^v><^<<>^^<v^>><>v>>v^vv^>><><>^>><^v^v^>v><>>vv^<>>v<^<<^<>^v>v<<><^^^<>^^vv<>vv><^^vv<>>><>^vvv>v^^>v^v^^<>v<<><<^^^<<^>vvv>>>^<><>>^<^>v^^v>v<>>><<^^vvv<>v^<^>^v^<^<^^<>^^<<<^<<<^v^>^^><^^>v^v^^<^><^^>v>^v<v^^>>><><^<<>^^<^<<^v><^^v^><><>>^v><^v^v^v>vvv><v>>v<><>v^v^v<^^^vvv^<^vv^v>^^>v^v>vv^<^<<>>>>^<^v>>^<<><<<<><<<^>^>^^>><^<^<^v^v<><>^>^<^>^<v<>>><>^^>^v>v^>><>^>><<><^v>v>^ +>vv^^^>v<><>>>>>v>v<^><<><<<^^^^v^<^v<^<>>^v>>>><^v<^<^vvv^^<^v^^<^^^^^v>><^><<<>>><^<^<>>^^v<<>><^^>v<v^v>>^>>^^>^<>vv<><<><^>^v^<>v>^>^vvvv<^>>vv<<>v<<><><<<<^v<><^<>vv>v>vv<^<>^vv<vvv^>^><<<^>^>v^^^^><<^^<<^>^v>v<>v^>v<<>>>^v^<>><^v^v^^>v><<<^v<>>>vv><<><<^^v<^^v^>>v>^><^v<^>^<>^>^^^>v^>>^^v^v>>^<><^^^>>v^^<^^>v^v^^>>vv^>>^v>v>v<<>v<>v<><<<^>>^<^^v>v^<^^vv<<>><>v<^<<>><><><^<>>^^^vv<>>^<^><>v<<>v>^<^v^v<<>v>>^^<<<^^v^v^^<>v>>^^>>>^v<><^v>>>^<^>>^vv><>^^<>>v^^v>>vv<>v>^^<<<^v<>^<<>v>^vv^>^<>>^v^v^>^^><<>^>>><^>>v>^v>^<^>^v>^vv>^>>v>>vv^vv>><<vvv^^>^^>v<^<>^v<^<^>^>^<^v<^<<>v>>^^^^>^v>v^>^^^^^>vv^v^vv^v^^v>^^<^>v<^^^^<^v^^vv<^v<<<^>v^^vv^<<>^><^>>>v^^>^>^>^<><^>^^><<<^^>^>v^<>v>^>^vv>><>^v^v^<<^v<>>v^ +<<<v>>>^>><><^^><<>v>^v<^vv^v>><^<>><^^v^<^<^>>>>>^>><^>^<><<^<><^>><^<<><^>v<^v>^<<>>vv<>vv><^^v^v<vv^><>vv>>><><^>>>>v^vvv^v><<<^^<>v^<^v^<^<^^v>v^v^^<^>v>>vv<^v<>^^v<^vv^>v>^<>^<<>v<<v<^<>vvv>v<^^>v<^<<^>><^v<^^<^>^<>v^><^^v<<><>v>^^^^v>>vv>>v^v>^>>^^vv>>v^vv>v>>^vv>v<^>^v^><>><>><<>><<^v^^vv^>^^v^v>^<><^<<>^<<>>^>v<<><><>v^>^<>>v<^>v^vvv^^>vvv<^<^v^^^>^<>v>^><^^>>^>v^^<>^^^^<^vv>>^vvv<><><<^vv>^^<>>>^<>v<<^^^^v^><<>>>>vv>>>vvv<><^^vvvv^^><^v^v<>vv<>v>^<<>^^>^<>vvv^v>>v>v^<^<^<>v<<><^^<>^v<>>^^v^><>vv>>v>>vv^v<^<>^><^<>><<>>^^v<<^^<<>>^vv>v>^v^v>^^v>>vv^v<>>vv>v<<^^<<^vvv>>vvv<<<<>^>>^<<>v^^<^<<<>v><>v^v>v^v<><>^v<^<><^<<>^v>vv>^^>>v<<^v^vv<><^^^v^^vv^v>>>v>v^^vvvv>>^^v>^^>vv^v>^>^v>>>^vv<<><<>>vv^<<<<^v^><<^^>^>^vv>><<<^>>>^ +<<<><^^v^<>><^>^<<<>v>v><<^^v<><^^>^>^>v><<>v<>^^^<<<<><><<>v<>><>v>v>v><^v<^<>>^^>v^v^v^>>>^<<>>^^><>^v^v^v^^><>vv^>v<<^v>v<>>^vv>vvv^^^v>vvv>>v>>v><^>^^>^><>><>>>^<<<>^^<<<^^^v<>^v<>>>^^>><><<^v^>v<>^>^<^v<>v>^^<><><<^>>vv<^v>v<^>>^^^<^v<<<^v<^^>v^vv<^>v><^<^^<><^^>^v<<<^<>vv^><>^^^^^^v>v^<>^<^<>^v^v>>^>^vvv^^^><>v^^>>^v<><^>vv<>><^^v^<^<<^vvv<^^v>v^<v><<>^v^<^^>^v^<^^^^v<>v^<<>vv><>^v<>v^<^^v<<>>vv^v><><>v<^^>^><<^>vv^^^^>>^^^>^^<><>^<>>^<^>^vv^vvv<<<^<^>^^v^^<<><>v<^^v>v>^v<>vvv>>^>^>^^>v^vv><<>^><>^v>>^v>^^^v<>^v<<>>v>>>v>^^<^><>v>^^<^<>>^>v^v>>>v^>><<<><>><^vv><<^^v<>^><^v>v^v^>>vv^^>v^v>^^^^<>v>^<>v<<>>^^^<^<^^v>^>vv^>^<>v^<<^>^<^>^^<^^vvvv<<>v<>><>^^^<>>^<<>v>^v<^v<^vvvv<<^<<<>>>^v>^^^^>^^<><<<<>>>^^<^vv>^^>^>><>^<^^vv>>>>v^v>><^>^v>^^>v^>^^<><^^>>><<>^v^v<^v^vv>><>vvvvvvv^v<^^^v>v^<<^^>>v>>>>^<<^^v>v^<^<^vvv<^>^vvv^>>>vv>v^<^^vv>^v<<^>v<^v>^vv<>v^>^v>>vv^>><<>v>^<^<^v^v^<^v>><>v^v<<>v>><^^^vv^>^^^v^<^<>v<^>><>>^<>>v<^>^>v^vv<^^^<>v<<><<>^v^<^^>>^>v>v<^v<^<^vv><<^^<^>v^v<<v>vv^^><^><>v>^vv><>^v^v>^vv^>>^v<>><<>v^v>^>v^>vv>>^<^^>v><^>vvv>v^<>^v>^<^^>^<^vvv^^^v<>v^>><^<>^><^><<^<^^>^v>^><>v<<^>^>vv^<^><>v>^>^^<<^v>^<<<^^v<>^^v><^v^v>^vvv^vv>v<>><<v<^>^v<>vv^>><<><^^>><^v<vv^<<<>vv^v>>>v^^v^>><>^^^v>>v^v^^^^^vv<<^^><^^v<<>^<^>v^^<>v<><^<^v^v>^>>^<^^^^<^<>^<<>vv>><>^^<^v>>v<>^^>^><><>^^v>^v>>^^v><^^<^v^<<<vv^<vv<><>>^vv>^>vv<<>vvv>^v^<>^><>>v><>v><^^vvv^^ +<^^^^>^>>^^<>vv><<<^<^><^^^><^^<><<<^<<<>><<>v<>><^^^>^<>^^>^^^>v>>^<>v><^>^<<><^^^^v><^vv<<>^^v>>^^>>v^v><<<^><><^^>vv><<<<>>^vv>^vv>v<<^^<^v<>^vv><>v<^^>^^<^v^vv^>v<>^vv>^^^<<<<<><>>>>v^<>v^^>>><^>^<<^^>>^>^<>^<<<^v^^^>>vv<^>><>^^<>v>><^>>>^<^^<^>><<^vvvv^vv>>vv><<^^^>>><<<>^v<>>><<>^>^v^^v^^<<^v<>>v^v^^v^>^^^><^>><^vv^v<^><<>^v^>>^v^>^>v<^^>^^<^<^^v<<^vvvv>>v<<<<<^^>>v<>^v<<v>>^<^>vv>^^v^>^>vv>^^<^^v<>v<<<^vvvv^^>>^>v^^^^>>^^v>v>^^v>>v^>>>>vv^>v>v>v<>^^v^><<>>>^>^^v^><^v>^>>v>>>>v<<^><<><<<^>vv<<^^v>^v>^vv^^<>^>^vv^v<><^v<><>^<^>v>>^>^v><^>^>^v^v<^>^v<<>>^>>v^^<>vv^>^vv<<<>>><^>v<^<><^^<>v^><^^^>vv>^^v^>>^>v>v<>>>^vv<>^>>^<<^>v>>v>v<^<><<><<><<>^>v^>>^>v><^>^^>^^v<^<><>>v +^vv^>>v<<>^>^^vv^>^v<<<>v^^^^>>^vv^<><><>>>v>v><^><^v<<^>vv^^><^v>v>^><<^><>^>>^>v^<<<>^^<><^^>>>>^><vv<>v>^^<>>>>^v>vv>>>^vv^^<<<<>v>^^>>^^^^><^vv>>v><<<<^v<^^>>>>^>^<^>>>>v^^><<^^>vv<^v>^v<>^v^>>><>^v^<^<^<^^<<<^^<><><>^v><>v><<^vv^>v>^^^vv^>^<>^v^vv>>>><>><>^^>^>^>>^^>>><^>v^<^^^^v<^>>>^>^v^^<^<^>v^>>^v^^>^<>vv>v^^><>v<v><<^<><<^v^>^v^>v^<>vv<>vv^v>vv^vvvvv<><>>^v>^vv>v>>^<<>><^>^^vv^v>>v^^v><>^v<<>>>v^^>><>>^<>v^vvv>^<^^^v>v>>^^v^>^^vvvv^^v<>>>^v^^>>v>>>^<^^>v^v^>>vv<^vvv^>>v>^<<<>>v^^^^^<>^v><<^vvv>^>^^>^v>^<^v^<v<<^v<^vv^>vv^^^<^v^^>>vv<>^^>v<^><>v>v>^>v<v^v^v>vv>v^><^>vv<^v>^>^^v^^>^<><<^v<^vvv^>><^>v<^<^>^<>v^<<>^<^><^vv^^v>^<<>^^^<><^<^^>>^<>><>>v<<<<<<>^^^^<^<><>>vv +<<^^v>^v^>>^>v^vv^>>vv><^^><^v^<^vv^>^>^>>>v^^<<<<<<^<><<>v^v<<>^v>^^><>^^><>v<<^^^<^<<^^^vv>>v^^<>^>v^v^>vv^vvv^vv^^vvvvvvv><<^<>>>^v^>><>^^<^^>^^>v<^^<^vv<<>><><>v>vvv^v<^^^><<<^<>>v^<^<^<>>><<>>v><>vv^v^<><<>^^<>>>^><<>^>v<<<^v>>vv>^^>^vv>>v<^^>>v>^><>v>v^>v<^^vv>^^^>^v>>v<<>^v<>>^<>^^^>v^^<^^^^vv^>v>^^vv<<^^>v>^^<<^v>vvvvv>^^>>v<^<>><^<>^><>vv^<>>^v^^>^^v><^v^>v><>v>^<^vvv<<^^^^^^<><>v^>v>^<<<><^^^<>^>^>^^v^<>^<>v^>^>v><v^v^<><^<<^<><^^<^^v<^^<<^><^^vv^v<^v>><<^>^^><^>^<<><>v^<>^v<^v<>^^^^<^<><^^v^<^v^v^v<<>><<>^<^v^^v^^v^>^^<<^<>>>^v><<<<^>>><^^^^<<<<^^^v>><^vv>>^><>>>><<<>><^v^>v>v>>^><><^v^><>v^>^<>><<<><>vv>^^v^>><^vv>>v>><^v<>^<>^^^v>v>v><^v^>>>^vvv^<<<^^> +>^v^^v<^v<>vvv^v^>v<>v<><>vv>^^^^^^^^>^>>^v^^>v^^>^<>>v>vv>v><>v^v>v^^^>^vvvvv^>>v>>^vv>v^v^<>^<>^>v^<>vv^<<>>>><<>>vvvvvv<^v<>v^>v>^<>v>>v>>^vv><^^<^^>^>>><>>^>^^^>^<^v^>^^^>^v>^^^^>>vvv>^><><>v<<^<^>v<<<^>^<^<<^v^>>^<>vvv>^><>^v^>>v><v^<v^v><><<><<><>^v^<^>>v^v>>^<<>>^^^^v<>v^^>^>>v^vv>>>v<^v>v^>^v<>>><^vvv^>^><<^>>^v<^^^^^v>>>>>^>v<>v^<<^v<^>v<><<<^v^<<^v>>v^<^vv^<<^>v>^^<^<^><<>^>^><^^><>>>v>>v><^^vv<^^v^^^<>vv>>>^^v<<^<^vv>^><^>v^>^><>v<<<>^^<<^^^vv^^v>v><^>^<<>v<^>^>><<<^<vv>><>>^<>^<>><><^<<>>^<>v<>v^v^<<><^^>>><<><<^><^>>vv^>v<^<^><^v>v<<<<<^^<^<<<<^>>^>v<^v^>v>vv<>vv><>^v<>v>v>v^^<><^vv<^<>vvv><>v^v^><<^v<^<>^^v<^^^v>^^>^v +^^>v<><<<^v^<^<^^^v^v<^^<<^<v>v>^>^><^<>v><^>^v>><<<^<>^v^>vv<^><^><>>>^><>^<<<>v>>v>>v^>^>><^>v>>v^^>>^<<><>vv><><>v>vvvv^v>v><<<>>v><^^>><<<><>^v^>vv>>>^>^^vv^v^>v<^>v<^^v>v<vv><>>^<<^v^<<^<<>^^v^>^^<><<>^^>^v<>>>>>v>>><>^^<^v>>>><^^vv^v<^<<<><<<^<>v>>>vvv>^^>>^vvvv><>>>>>^v>>v>v<>>^^>><>v>v<><<<^^vv<<>v^vvv>>>vv>^v^><>v^<>^>^^<^^v^^><><<>>>>><<^>v<>^v>^<v><<>v^>v>>v<^>v><^<^vv><^v^>><>v<^>vv^^>^<<>^>vv^<>^^>^>^^v>v>v^v^^vv^^^^^<>^^v<>v>v>v><>^^>vv^v^^^^<^^<^^>v<>>^<>v<^>^vvv>^v>v>v<>v^>^^vv>^^v^v<>v^v<<^<>^^>>vvv>><<^<<><>vv^^>>v^<<>v^>^<><^<^^><^v>>>^^>^<^^><^>^^>^v><^>v>v<<>v^>v^<<^^><^^<<<>^^vv>>^>^<v>>>>^v<^^^vv>>>vv^>>v<>v^^^^<^v^<^><<<<>^>^>vvv^vv<^>>v>>>vv<>vvv^^^><>^<<<^>