// ADD ANY NEEDED IMPORTS HERE public class MazeSolver { /////////////////// // INNER CLASSES // /////////////////// public static class Choice { final static int RIGHT = 1; final static int DOWN = 2; final static int LEFT = 3; final static int UP = 4; // ADD ANY ADDITIONAL CONSTANTS DESIRED HERE int direction; // <-- LIMIT YOURSELF TO ONLY THIS INSTANCE VARIABLE FOR THIS INNER CLASS private Choice(int direction) { // ADD CODE HERE } public static Choice firstChoice() { // ADD CODE HERE } public Choice nextChoice() { // ADD CODE HERE } public boolean unconsideredChoicesExist() { // ADD CODE HERE } public String toString() { // ADD CODE HERE } } public static class StackOfChoices implements Iterable { final int WALL = 1; final int EMPTY = 0; // ADD ANY ADDITIONAL CONSTANTS DESIRED HERE private Stack choices; // <-- LIMIT YOURSELF TO ONLY THESE 3 INSTANCE VARIABLES FOR THIS INNER CLASS private int[][] maze; // private boolean[][] visited; // // YOU MAY FIND THE NEXT METHOD HELPFUL: private int[][] copyOf(int[][] a) { int[][] b = new int[a.length][a[0].length]; for (int r = 0; r < a.length; r++) { for (int c = 0; c < a[0].length; c++) { b[r][c] = a[r][c]; } } return b; } // HAVING AND USING THE NEXT 2 METHODS WILL HELP // SIMPLIFY YOUR CODE. FLESH THEM OUT SO THEY BEHAVE // AS DESCRIBED: private int endingRow() { // ADD CODE HERE TO RETURN THE ROW INDEX OF // WHERE ONE ENDS UP IF ONE STARTS AT ROW=0 COL=1 // AND MAKES THE CHOICES IN THIS STACK OF CHOICES // IN THE ORDER THEY WERE ADDED TO THE STACK } private int endingCol() { // ADD CODE HERE TO RETURN THE COLUMN INDEX OF // WHERE ONE ENDS UP IF ONE STARTS AT ROW=0 COL=1 // AND MAKES THE CHOICES IN THIS STACK OF CHOICES // IN THE ORDER THEY WERE ADDED TO THE STACK } public StackOfChoices(int[][] maze) { // ADD CODE HERE } public boolean isEmpty() { // ADD CODE HERE } public int size() { // ADD CODE HERE } public void push(Choice choice) { // ADD CODE HERE } public Choice peek() { // ADD CODE HERE } public Choice pop() { // ADD CODE HERE } public Iterator iterator() { // ADD CODE HERE } public boolean isSolution() { // ADD CODE HERE } public boolean mightHaveSolutionWith(Choice c) { // ADD CODE HERE } // DO NOT MODIFY ANY OF THE CODE FROM THIS POINT DOWN. // THAT SAID, MAKE SURE YOU LOOK AT IT CAREFULLY AND UNDERSTAND IT. // THAT KNOWLEDGE WILL HELP YOU AS YOU FLESH OUT THE INCOMPLETE METHODS ABOVE public String toString() { final String WALL_STR = "\u2591"; // i.e., the unicode character for a lightly-shaded block final String EMPTY_STR = " "; final String VISITED_STR = "\u2022"; // i.e., the unicode character for a small dot final String START_STR = "S"; final String FINISH_STR = "F"; String[][] mazeToShow = new String[this.maze.length][this.maze[0].length]; int row,col; // fill mazeToShow with strings for walls and (initially) empty corridors for (row = 0; row < this.maze.length; row++) for (col = 0; col < this.maze[0].length; col++) mazeToShow[row][col] = (this.maze[row][col] == WALL ? WALL_STR : EMPTY_STR); // add strings for any corridors visited by making the choices made so far row = 0; col = 1; // start of maze is required to be at this row/col position for (Choice choice : choices) { switch (choice.direction) { case Choice.RIGHT : col++; break; case Choice.DOWN : row++; break; case Choice.LEFT : col--; break; case Choice.UP : row--; break; } mazeToShow[row][col] = VISITED_STR; } // add strings for start and finish mazeToShow[0][1] = START_STR; mazeToShow[this.maze.length-1][this.maze[0].length-2] = FINISH_STR; // convert the array of strings to a single printable string s String s = ""; for (row = 0; row < this.maze.length; row++) { for (col = 0; col < this.maze[0].length; col++) { s += mazeToShow[row][col]; } s += "\n"; } return s; } } private StackOfChoices stackOfChoicesMade; private Stack stackOfSolutions; public MazeSolver(int[][] grid) { stackOfChoicesMade = new StackOfChoices(grid); stackOfSolutions = new Stack(); } public boolean solutionFound() { return (stackOfChoicesMade.isSolution()); } public void solve() throws InterruptedException { // THIS METHOD USES THE BACKTRACKING ALGORITHM (WITH A STACK) Choice choice = Choice.firstChoice(); while (true) { if (stackOfChoicesMade.mightHaveSolutionWith(choice)) { stackOfChoicesMade.push(choice); //System.out.println(stackOfChoicesMade); // <-- uncomment this line to see the choices made so far choice = Choice.firstChoice(); } else if (choice.unconsideredChoicesExist()) { choice = choice.nextChoice(); } else { if (stackOfChoicesMade.isEmpty()) // Here, you intend to pop to backtrack if you can. break; // If you can't (because the stack is empty), you are done! choice = stackOfChoicesMade.pop().nextChoice(); // If the pop is safe, pick up where you // left off with your last choice. // (i.e., choose the next choice after that one) } if (solutionFound()) { reactToSolutionFound(); choice = stackOfChoicesMade.pop(); // normally we check to make sure -- but it's safe to pop.. why? choice = choice.nextChoice(); // keep going to try to find other solutions } } } public void reactToSolutionFound() { stackOfSolutions.push(stackOfChoicesMade.toString()); } public static void solveMaze(int[][] maze) throws InterruptedException { MazeSolver solver = new MazeSolver(maze); System.out.println("NEW MAZE:\n\n" + solver.stackOfChoicesMade); solver.solve(); System.out.println(solver.stackOfSolutions.size() + " solutions(s) found:\n"); for ( String solution : solver.stackOfSolutions) { System.out.println(solution); } } public static void main(String[] args) throws InterruptedException { int[][] solvableMaze = {{1,0,1,1,1,1,1,1,1,1,1}, {1,0,1,0,0,1,1,0,0,0,1}, {1,0,1,1,0,1,0,0,1,0,1}, {1,0,1,0,0,0,0,1,1,0,1}, {1,0,0,0,1,1,0,1,0,0,1}, {1,1,1,0,1,0,0,1,0,1,1}, {1,0,0,0,1,1,0,1,0,0,1}, {1,0,1,0,1,0,0,0,1,0,1}, {1,1,1,1,1,1,1,1,1,0,1}}; solveMaze(solvableMaze); int[][] multipleSolutionMaze = {{1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}, {1,0,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,1,0,1}, {1,1,1,0,1,1,1,0,1,0,1,1,1,0,1,1,1,1,1,0,1}, {1,0,0,0,1,0,0,0,1,0,1,0,1,0,0,0,0,0,1,0,1}, {1,0,1,1,1,0,1,1,1,0,1,0,1,0,1,1,1,0,1,0,1}, {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,1}, {1,0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,0,1}, {1,0,1,0,1,0,1,0,0,0,1,0,0,0,0,0,0,0,1,0,1}, {1,0,1,0,1,0,1,1,1,1,1,1,1,0,1,1,1,0,1,0,1}, {1,0,0,0,1,0,0,0,0,0,0,0,1,0,1,0,0,0,1,0,1}, {1,1,1,0,1,0,1,1,1,1,1,1,1,0,1,1,1,1,1,0,1}, {1,0,0,0,0,0,1,0,1,0,1,0,0,0,0,0,1,0,0,0,1}, {1,0,1,1,1,0,1,0,1,0,1,0,1,0,1,1,1,1,1,0,1}, {1,0,0,0,1,0,1,0,1,0,1,0,1,0,0,0,0,0,1,0,1}, {1,0,1,0,1,0,1,0,1,0,1,1,1,1,1,0,1,0,1,0,1}, {1,0,1,0,1,0,1,0,0,0,1,0,0,0,1,0,1,0,0,0,1}, {1,0,1,1,1,0,1,0,1,1,1,1,1,0,1,0,1,1,1,0,1}, {1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,1,0,1}, {1,0,1,1,1,1,1,0,1,0,1,1,1,0,1,1,1,0,1,0,1}, {1,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,1}, {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1}}; solveMaze(multipleSolutionMaze); int[][] unsolvableMaze = {{1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}, {1,0,0,0,0,0,1,0,1,0,0,0,0,0,1,0,1,0,0,0,1}, {1,0,1,0,1,1,1,0,1,0,1,0,1,1,1,0,1,0,1,0,1}, {1,0,1,0,0,0,1,0,1,0,1,0,1,0,0,0,0,0,1,0,1}, {1,0,1,0,1,0,1,0,1,1,1,0,1,0,1,1,1,1,1,1,1}, {1,0,1,0,1,0,1,0,1,0,0,0,0,0,0,0,0,0,1,0,1}, {1,0,1,1,1,0,1,0,1,0,1,1,1,1,1,0,1,1,1,0,1}, {1,0,1,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,1}, {1,0,1,1,1,0,1,0,1,1,1,0,1,1,1,1,1,1,1,0,1}, {1,0,1,0,1,0,0,0,0,0,1,0,1,0,0,0,0,0,1,0,1}, {1,0,1,0,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1}, {1,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,1}, {1,0,1,0,1,1,1,1,1,0,1,0,1,0,1,0,1,1,1,0,1}, {1,0,0,0,0,0,0,0,1,0,1,0,1,0,1,0,0,0,0,0,1}, {1,0,1,0,1,1,1,1,1,0,1,1,1,0,1,0,1,0,1,0,1}, {1,0,1,0,0,0,1,0,0,0,0,0,1,0,0,0,1,0,1,0,1}, {1,0,1,1,1,0,1,1,1,1,1,0,1,0,1,0,1,0,1,0,1}, {1,0,0,0,1,0,0,0,0,0,1,0,1,0,1,0,1,0,1,0,1}, {1,0,1,1,1,1,1,0,1,1,1,0,1,1,1,0,1,0,1,1,1}, {1,0,1,0,0,0,0,0,1,0,0,0,0,0,1,0,1,0,0,0,1}, {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1}}; solveMaze(unsolvableMaze); } }