3
\$\begingroup\$

I developed a maze navigator in Java for a project for my school. It works fine, and it gets through the maze just fine. The program prints to the screen each time it loops through the maze to set the next position. Note: there is only one path because I haven't implemented a multiple path algorithm yet. Is there any way to make this more elegant/efficient? The main things I'm looking to reduce are (if possible):

  • Switch/Case Statements
  • Memory (re-printing to the screen each time)
  • Code Improvements that made the program more efficient/elegant

Any and all suggestions/improvements are welcome.

public class MazeAI {
    //maze layout below
    static int[][] maze = 
     {{1,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
      {1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1},
      {1,0,1,1,1,1,1,1,1,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,0,1,1,1,1,0,1,1,1,1,1,1,0,1,1,1,1,1,1,1},
      {1,0,1,1,1,1,1,1,1,0,1,0,1,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1,1,1,1,1,0,1,1,1,1,1,1,1},
      {1,0,1,1,1,1,1,1,1,0,1,0,1,0,1,0,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,1,1,1,1},
      {1,0,1,1,1,1,1,1,1,0,1,0,1,0,1,0,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,1,1,1,1,1,1,1,1,0,1,1,1,1},
      {1,0,0,0,0,0,0,0,0,0,1,0,1,0,1,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,0,1,1,1,1},
      {1,1,1,1,1,1,1,1,1,1,1,0,1,0,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,1,1,1,1},
      {1,1,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
      {1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,0,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
      {1,1,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,0,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1},
      {1,1,1,0,1,0,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,1,0,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1},
      {1,1,1,0,1,0,1,1,1,1,1,1,1,1,1,1,1,1,0,1,0,1,0,1,1,1,1,1,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,0,1},
      {1,1,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,0,1},
      {1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,0,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,0,1},
      {1,1,1,0,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,1,0,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,1,1,1,1,1,1,1,1,1,1,0,1},
      {1,1,1,0,0,0,0,1,1,0,0,0,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,0,1},
      {1,1,1,1,1,1,0,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,0,0,0,0,0,0,0,1},
      {1,1,0,0,0,0,0,1,1,0,1,1,1,1,1,1,0,0,0,0,1,1,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,1,1,1,1,1,1,1},
      {1,1,0,1,1,1,1,1,1,0,1,1,1,1,1,1,0,1,1,0,1,1,0,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1},
      {1,1,0,0,1,1,1,1,1,0,1,1,1,1,1,1,0,1,1,0,1,1,0,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1},
      {1,1,1,0,0,0,1,1,1,0,1,0,0,0,0,0,0,1,1,0,1,1,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1},
      {1,1,1,1,1,0,0,0,0,0,1,0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
      {1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,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,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
    };
    public static void main() {
        MazeAI m = new MazeAI();
        m.runAI(23,11); //where S is
    }

    void printMaze() {
        System.out.println("    MAZE     ");
        System.out.println();
        for(int i = 0; i < maze.length; i++) {
            String output = "";
            for(int j = 0; j < 50; j++) {
                switch(maze[i][j]) {
                    case 0: output += " "; break;
                    case 1: output += "@"; break;
                    case 2: output += "S"; break;
                    case 3: output += "E"; break;
                }
            }
            System.out.println(output);
        }
        System.out.println();
    }    

    void printPath(int[][] array, boolean last) {
        System.out.println("    PATH     ");
        System.out.println();
        if(last) {
            array[1][1] = 4;
        }
        for(int i = 0; i < array.length; i++) {
            String output = "";
            for(int j = 0; j < 50; j++) {
               switch(array[i][j]) {
                   case 0: output += " "; break;
                   case 1: output += "@"; break;
                   case 2: output += "S"; break;
                   case 3: output += "E"; break;
                   case 4: output += "^"; break;
                   case 5: output += "v"; break;
                   case 6: output += "<"; break;
                   case 7: output += ">"; break;
               }
            }
            System.out.println(output);
        }
        System.out.println();
    }

    void runAI(int i, int j) { //S is at (i,j) -> (9,11) | E is at (0,1)
        try { 
            printMaze(); 
            Thread.sleep(3000); 
            System.out.print('\f');
        } catch (Exception e) { 
            e.printStackTrace();
        }
        int[][] arr = maze;
        int[] currentPos = {i,j};
        boolean running = true;
        while(running) {
            if(foundEnd(currentPos)) {
                running  = false;
                printPath(arr, true);
                break;
            }
            if(canMoveUp(arr, currentPos)) {
                arr[currentPos[0]][currentPos[1]] = 4;
                currentPos[0] -= 1;
            } else if(canMoveDown(arr, currentPos)) {
                arr[currentPos[0]][currentPos[1]] = 5;
                currentPos[0] += 1;
            } else if(canMoveLeft(arr, currentPos)) {
                arr[currentPos[0]][currentPos[1]] = 6;
                currentPos[1] -= 1;
            } else if(canMoveRight(arr, currentPos)) {
                arr[currentPos[0]][currentPos[1]] = 7;
                currentPos[1] += 1;
            }
            printPath(arr, false);
            try {
                Thread.sleep(150);
            } catch (Exception e) {
                e.printStackTrace();
            }
            System.out.print('\f');
        }
    }

    boolean canMoveUp(int[][] arr, int[] pos) {
        try {
            if(arr[pos[0] - 1][pos[1]] == 0) {
                return true;
            } else {
                return false;
            }
        } catch (java.lang.ArrayIndexOutOfBoundsException e) {
            return false;
        }
    }

    boolean canMoveDown(int[][] arr, int[] pos) {
        try {
            if(arr[pos[0] + 1][pos[1]] == 0) {
                return true;
            } else {
                return false;
            }
        } catch (java.lang.ArrayIndexOutOfBoundsException e) {
            return false;
        }
    }

    boolean canMoveRight(int[][] arr, int[] pos) {
        try {
            if(arr[pos[0]][pos[1] + 1] == 0) {
                return true;
            } else {
                return false;
            }
        } catch (java.lang.ArrayIndexOutOfBoundsException e) {
            return false;
        }
    }

    boolean canMoveLeft(int[][] arr, int[] pos) {
        try {
            if(arr[pos[0]][pos[1] - 1] == 0) {
                return true;
            } else {
            return false;
            }
        } catch (java.lang.ArrayIndexOutOfBoundsException e) {
            return false;
        }
    }

    boolean foundEnd(int[] pos) {
        if(pos[0] == 1 && pos[1] == 1) {
            return true;
        } else {
            return false;
        }
    }
}
\$\endgroup\$
  • \$\begingroup\$ You know about genetic algorithms? \$\endgroup\$ – Peter Rader Jan 10 at 17:12
2
\$\begingroup\$

Good job so far! I got some remarks, hopefully you'll find them useful.

Try Different Algorithms :)

See this nice Wikipedia entry for a list of possible algorithms to solve a maze:

https://en.wikipedia.org/wiki/Maze_solving_algorithm

Reuse code

This switch block appears 1.5 times in your code. Consider making it a method.

               case 0: output += " "; break;
               case 1: output += "@"; break;
               case 2: output += "S"; break;
               case 3: output += "E"; break;
               case 4: output += "^"; break;
               case 5: output += "v"; break;
               case 6: output += "<"; break;
               case 7: output += ">"; break;

Remove unnecessary code

You use this:

   if(arr[pos[0]][pos[1] - 1] == 0) {
        return true;
   } else {
   return false;
   }

Which can be re-written to:

    return arr[pos[0]][pos[1] - 1] == 0;

Which is much clearer to me :)

AIOOBE vs bounds check

You currently let the canMove throw an ArrayIndexOutOfBoundsException. Some consider this bad practice, because this is 'normal' flow. You should check before if your indices are valid.

String concatenation

Try to prevent String concatenation by using the + operator. It creates many unnecessary intermediate objects.

See also here: https://redfin.engineering/java-string-concatenation-which-way-is-best-8f590a7d22a8

Consider using char directly

Your memory-model model is an int[][]. Your code uses 'magic values' that test int values. char is also well-suited to use as values in your grid, and you can then directly print and test these char values. Constructing the grid can start from a list of Strings with toCharArray() and your maze in code looks exactly like the output on the console

(Or else, at least create readable constants for the ints in the if statements)

Consider coding the directions in an enum :

enum Direction {
  UP(0,-1), LEFT(-1,0), RIGHT(1,0), DOWN(0,1);

  int dx;
  int dy;

  Direction(dx, dy)
  {
     this.dx=dx;
     this.dy=dy;
  }
}

for (Direction d : Direction.values())
{
   if (canMove(arr, currentPos, direction))
   {
       markMove(arr, currentPos, direction);
   }
}

Something like this:

  boolean canMove(int[][] arr, int[] pos, Direction d) {
        try {
            return arr[pos[0] + d.dx][pos[1] + d.dy] == 0
        } catch (java.lang.ArrayIndexOutOfBoundsException e) {
            return false;
        }
    }
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.