Search code examples
javaarraysprintingsolvermaze

2-D Maze Solver: Final Maze Won't Print


I am working on a program that will solve find a path in a maze. The maze is represented by 0's, 1's and an E to represent the Exit. The maze is represented by a 20x30 (0's represent the path, 1's represent walls). I am using a stack to keep track of a previous usable location.

I think I have most of the code figured out, but when I run it and enter the starting position, the final maze doesn't print out.

My code is as follows:

import java.util.*;
import java.io.*;
public class MazeGenerator {

//main
 public static void main(String[] args) throws IOException {

        Scanner sc = new Scanner(System.in);
        int userRow, userCol;

        MazeGenerator maze = new MazeGenerator();
        maze.fillArray();
        maze.print();

        System.out.println();

        //asking for user starting position
        System.out.print("What row would you like to start in?: " );
        userRow = sc.nextInt();
        while(userRow > 29 || userRow < 0) {
            System.out.print("INVALID INPUT! PLEASE ENTER VALUES BETWEEN 0 - 
29 INCLUSIVE: " );
            userRow = sc.nextInt();
        }
        System.out.println();

        System.out.print("What column would you like to start in? ");
        userCol = sc.nextInt();
        while(userCol > 19 || userCol < 0) {
            System.out.print("INVALID INPUT! PLEASE ENTER VALUES BETWEEN 0 - 
19 INCLUSIVE: " );
            userCol= sc.nextInt();
        }


        System.out.println("\n\nFind a path using a stack: ");
        //maze.userStart(userRow,userCol);

        maze.setUserRow(userRow);
        maze.setUserColumn(userCol);


        maze.solveStack();
        //solveStack(maze);
 }

//methods for creating maze
public static final int ROW = 30;
public static final int COLUMN = 20;
public int userRow = 0;
public int userColumn = 0;
private static String[][] maze = new String[ROW][COLUMN];

public void fillArray() throws IOException {
    File file = new File("maze.txt");
    FileReader reader = new FileReader(file);
    BufferedReader buff = new BufferedReader(reader);

    for(int counter1 = 0; counter1 < ROW; counter1++) {

        String l = buff.readLine();

        for(int counter2 = 0; counter2 < COLUMN; counter2++) {

            maze[counter1][counter2] = String.valueOf(l.charAt(counter2));
        }
    }

    buff.close();
}

public void print() throws IOException {

    System.out.printf("%-4s", ""); //spaces column
    for (int counter = 0; counter < COLUMN; counter++){

         System.out.printf("%-4d",counter); //print the column number

    }
    System.out.println();

    for(int counter1 = 0; counter1 < maze.length; counter1++) { //loop for 
printing rows

        System.out.printf("%-4d",counter1); //print row number

        for(int counter2 = 0; counter2 < maze[counter1].length; counter2++) 
{ //loop for printing columns

            System.out.printf("%-4s", maze[counter1][counter2]); //printing 
values of maze
        }
        System.out.println(); // new line
    }
}

public int getWidth(){
    return maze[0].length;
}

public int getHeight(){
    return maze.length;
}


public void setUserRow (int userRow) {
    this.userRow = userRow;
}

public void setUserColumn (int userColumn) {
    this.userColumn = userColumn;
}

public int getUserRow() {
    return userRow;
}

public int getUserColumn() {
    return userColumn;
}

public String mark(int row, int col, String value) {
    assert(inMaze(row,col)); 
    String temp = maze[row][col];
    maze[row][col] = value;
    return temp;
    }

public String mark (MazePosition pos, String value) {
    return mark(pos.row(), pos.col(), value); 
}

public boolean isMarked(int row, int col) {
    assert(inMaze(row,col)); 
    return (maze[row][col].equals("+"));
}

public boolean isMarked(MazePosition pos) {
    return isMarked(pos.row(), pos.col());
}

public boolean Clear(int row, int col) {
    assert(inMaze(row,col)); 
    return (maze[row+1][col+1] != "1" && maze[row+1][col+1] != "+");
}

public boolean Clear(MazePosition pos) {
     return Clear(pos.row(), pos.col());
 }

//true if cell is within maze 
public boolean inMaze(int row, int col) {
    if (row >= 0 && col >= 0 && row < getWidth() && col < getHeight() ) {
        return true; 
    }
    return false;
}

//true if cell is within maze 
public boolean inMaze(MazePosition pos) {
    return inMaze(pos.row(), pos.col());
} 

public boolean Done( int row, int col) {
    return (maze[row][col].equals("E"));
}

public boolean Done(MazePosition pos) {
    return Done(pos.row(), pos.col());
}

public String[][] clone() {

    String[][] copy = new String[ROW][COLUMN]; 

    for (int counter1 = 0; counter1 < ROW; counter1++) {

        for (int counter2 = 0; counter2 < COLUMN; counter2++) {

            copy[counter1][counter2] = maze[counter1][counter2];
        }
    }
    return copy; 
    }

public void restore(String[][] savedMaze) {
    for (int i=0; i< ROW; i++) 
        for (int j=0; j<COLUMN; j++)
        maze[i][j] = savedMaze[i][j];
    }

public MazeGenerator clone(MazeGenerator m) {
    MazeGenerator maze = new MazeGenerator();
    maze = m;
    return maze;
}

//**************************************************
//this solution uses a stack to keep track of possible
//states/positions to explore; it marks the maze to remember the
//positions that it's already explored.
public void solveStack() throws IOException {

//save the maze
//MazeGenerator savedMaze = new MazeGenerator();
//savedMaze.clone(m);
String[][] savedMaze = clone();

//declare the locations stack 
Stack<MazePosition> candidates = new Stack<MazePosition>(); 

//insert the start 
candidates.push(new MazePosition(userRow,userColumn)); 

MazePosition current, next;
while (!candidates.empty()) {

    //get current position
    current = candidates.pop();

    if (Done(current)) { 
        break;
    }

    //mark the current position 
    mark(current, "+");

    //put its neighbors in the queue
    next = current.north(); 
    if (inMaze(next) && Clear(next)) candidates.push(next);

    next = current.east(); 
    if (inMaze(next) && Clear(next)) candidates.push(next);

    next = current.west(); 
    if (inMaze(next) && Clear(next)) candidates.push(next);

    next = current.south(); 
    if (inMaze(next) && Clear(next)) candidates.push(next);
}

if (!candidates.empty()) {
    System.out.println("You got it!");
}
else System.out.println("You're stuck in the maze!");

//savedMaze.print();
print();

restore(savedMaze);

}

class MazePosition {
    public int row; 
    public int col;

    public MazePosition(int row, int col) {
        this.row = row; 
        this.col = col;
    }

    public int row() { return row; }

    public int col() { return col; }

    public void print() {
        System.out.println("(" + row + "," + col + ")");
    }

    //positions
    public MazePosition north() {
        return new MazePosition(row-1, col);
    }

    public MazePosition south() {
        return new MazePosition(row+1, col);
    }

    public MazePosition east() {
        return new MazePosition(row, col+1);
    }

    public MazePosition west() {
        return new MazePosition(row, col-1);
    }
}; 

    }

Solution

  • Without the benefit of a maze.txt, I created one based on your description. Here's what I found...

    Short answer:

    Your program hits an infinite loop searching for the exit, so it never reaches the code to print it out.

    Long answer:

    I see 3 problems on 2 lines of code:

    1) A simple typo:

    if (row >= 0 && col >= 0 && row < getWidth() && col < getHeight() ) {
    

    getHeight() and getWidth() should be swapped:

    if (row >= 0 && col >= 0 && row < getHeight() && col < getWidth() ) {
    

    2) In one spot, you're using 1-based indices, when Java uses 0-based indices:

    In this line here:

    return (maze[row+1][col+1] != "1" && maze[row+1][col+1] != "+");
    

    Array indices in java start at 0. Your row and col variables also start at 0. But you're adding one to them thereby converting them into 1-based indices. So, you'd want:

    return (maze[row][col] != "1" && maze[row][col] != "+");
    

    3) You're using != like !equals(), but in Java, == is not the same as .equals()

    In the above line of code, you're comparing two Strings with the != operator. But that doesn't work like the String.equals() method, so your Clear() method always returns true.

    This is the crux of your stated problem. The search routine, finding every cell clear, works its way into a corner, and then searches the same two adjacent cells forever.

    So, what you really want is:

    return (!maze[row][col].equals("1") && !maze[row][col].equals("+"));