Recursive Maze Solver method Issue - java
Given a 2 dimensional char array filled with 0's and 1 where 0 represents a wall and 1 represents a valid path, I have developed a recursive method called findPath(int r, int c) to find the exit in the maze marked with an 'x'. The method takes in the current row and column of the maze and goes through N,E,S,W directions until it finds a valid path and marks that valid path with a '+'. Given an instance where all directions are found to be blocked by a wall, the method then is suppose to backtrack until this is not the case anymore, and then marking that path traveled with an 'F' to symbolize the bad path.
Right now I can't figure out why the findPath method doesn't seem to transverse through all the directions as my display method just shows the program starting from the coordinates I pass in and not moving anywhere from there, why could this be?
Here is my Driver class
public class MazeMain2
{
public static void main(String[]args)
{
char[][] mazeArr = {{'0','0','0','1','0','0','0','0','0','0','0','0','0','0','0'},
{'0','0','0','1','0','0','0','0','1','0','0','0','0','1','0'},
{'0','0','0','1','1','1','1','1','1','1','1','1','0','0','0'},
{'0','0','0','1','0','0','0','0','0','0','0','1','0','0','0'},
{'0','0','0','1','1','1','1','1','0','0','0','1','0','0','0'},
{'0','0','0','0','0','0','0','1','0','0','0','1','0','0','0'},
{'0','0','0','0','1','1','1','1','0','0','0','1','0','0','0'},
{'0','0','0','0','1','0','0','1','0','0','0','1','0','1','0'},
{'0','0','0','0','1','0','0','1','0','0','0','0','0','0','0'},
{'0','0','0','0','1','0','0','0','0','0','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','0','0','0','0','0','1','0','0','0','0'},
{'0','0','0','0','0','0','0','0','0','0','1','0','0','0','0'},
{'0','0','0','0','0','1','0','0','0','0','1','1','1','1','0'},
{'0','0','0','0','0','0','0','0','0','0','1','0','0','0','0'}};
MazeSolver2 mazeS = new MazeSolver2(mazeArr);
mazeS.markEntry();
mazeS.markExit();
mazeS.solve(0, mazeS.start);
}
}
And here is my maze solver class with the findPath method
public class MazeSolver2
{
int start;
int exit;
char[][] maze;
public MazeSolver2(char[][] currentMaze)
{
maze = currentMaze;
}
//Finds where the first 1 is in the top row of the
//maze (entrance)
public void markEntry()
{
for(int x = 0; x < maze.length; x++)
{
if(maze[0][x] == '1')
{
maze[0][x] = 'E';
start = x;
}
}
}
//Finds where the last 1 is in the bottom row of the
//maze (exit)
public void markExit()
{
for(int x = 0; x < maze.length; x++)
{
if(maze[maze.length - 1][x] == '1')
{
maze[maze.length - 1][x] = 'x';
exit = x;
}
}
}
public void solve(int x, int y)
{
if(findPath(x, y))
{
System.out.println(maze[x][y]);
}
else
System.out.println("No solution");
}
public boolean findPath(int r, int c)
{
displayMaze(maze);
//Found the exit
if(maze[r][c] == 'x')
{
return true;
}
if(maze[r][c] == '0' || maze[r][c] == '+' || maze[r][c] == 'F')
{
return false;
}
maze[r][c] = '+';
//If row is currently at zero then don't check north
//direction because it will be outside of the maze
if(r <= 0)
{
if(findPath(r, c++))
{
return true;
}
if(findPath(r++, c))
{
return true;
}
if(findPath(r, c--))
{
return true;
}
}
else
{
//check N, E, S, W directions
if(findPath(r--, c) || findPath(r, c++) ||
findPath(r++, c) || findPath(r, c--))
{
return true;
}
}
//Marking the bad path
maze[r][c] = 'F';
return false;
}
//Displays maze
public void displayMaze(char[][] maze)
{
for(int row = 0; row < maze.length; row++)
{
for(int col = 0; col < maze.length; col++)
{
if(col == 14)
{
System.out.print(maze[row][col]);
System.out.println();
}
else
{
System.out.print(maze[row][col]);
}
}
}
System.out.println();
}
}
Your algorithm has several flow in itself, which I don't feel right to point out. You can search for maze traverse problems, and get many good tutorials.
However, give attention to the method calls. Notice that if findPath(int r, int c) get called with findPath(5, 5) then a call to findPath(r, c++) passes the values findPath(5, 5) again, not with findPath(5, 6).
Because in that case findPath(r, c++) get called with current value of c and after that c++ gets executed.
Same goes for findPath(r, c--) findPath(r++ , c) etc, etc.
A good idea to understand the fact is to print the values int r, int c at the starting of method findPath().
Also play a little with post increments/decrements(x++/--x) and pre increments/decrements(++x/--x).
Hope it helps.
Related
Java tictactoe problems with minmax algorithm
i want to implement the MinMax algorithm for tictactoe. I have two methods min() and max() and a evaluation method, but it doesn't works. For example when i call max(9); Field[bestCol][bestRow]='O'; min(8); Field[bestCol][bestRow]='X'; in the main function the result is OX- --- --- But the best Move for Player 'X' is to put the 'X' in the middle. Here is my Code without the evaluation Method: static char[][] Field = { { '-', '-', '-' }, { '-', '-', '-' }, { '-', '-', '-' } }; static char Player = 'O'; static char Computer = 'X'; static int Depth =9; // searchdepth static int bestRow=0, bestCol=0; // best Move public static int max(int depth) { if (depth == 0) { return evaluateMove(); } int maxValue = Integer.MIN_VALUE; for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { if (Field[i][j] == '-') { Field[i][j] = Computer; int value = min(depth - 1); Field[i][j] ='-'; if (value > maxValue) { maxValue = value; if (depth == Depth) { bestCol=i; bestRow=j; } } } } } return maxValue; } public static int min(int depth) { int minValue = Integer.MAX_VALUE; if (depth == 0) { return evaluateMove(); } for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { if (Field[i][j] == '-') { Field[i][j] = Player; int value = max(depth - 1); Field[i][j] = '-'; if (value < minValue) { minValue = value; bestCol=i; bestRow=j; } } } } return minValue; } Best Regards EDIT: Thanks for your answer. To the first point i have forgotten to change the '*' to '-' Here is my Evaluation Method: public static int evaluateMove() { for(int i=0; i<3; i++) { int countX=0; int countY=0; for(int j=0; j<3; j++) { if(Feld[i][j]==Computer) countX++; if(Feld[i][j]==Player) countY++; } if(countX==3) return 10; if(countY==3) return -10; } for(int j=0; j<3; j++) { // Spalten int countX=0; int countY=0; for(int i=0; i<3; i++) { if(Feld[i][j]==Computer) countX++; if(Feld[i][j]==Player) countY++; if(countX==3) return 10; if(countY==3) return -10; } } return 0; // Unentschieden }
Some things that struck me: you are initializing the empty squares of the playing field with '-', but in the min/max-functions you assume that '*' is an empty square in the min-function, as opposed to the max-function you set the best move at every level instead of the top level, so the deeper levels will overwrite the best result from the top level (so I think you should also check for depth==Depth) I don't know what you do in main, but should also decrement "Depth" after each move, because this defines the top level (and thus the level where the best move should be assigned), and according to your question you decrement the "depth" argument during each call I guess you know that you will only get the optimal result if you recurse until the end of the game (which is another argument for decrementing depth and Depth after every move) You are not checking the diagonals in your evaluateMove function In your second double loop in evaluateMove you check the condition for countX, countY inside the innermost loop (works, but it is irritating that it's different to first double loop => not so good for finding errors) Edit: and finally (drum roll...): In the first move you maximize the gain (for a Computer move ('X')) but you actually perform a Player move ('O'). For the second move vice versa. However, you have to minimize the gain in the first move (which means player wins) and maximize in the second move. That is, what you actually do: public static void ComputeAndExecuteBestMove() { // since Player begins, we minimize the gain value for the first move if ((MaxDepth-Depth) % 2 == 0) { max(Depth); Field[bestCol,bestRow] = Player; } else { min(Depth); Field[bestCol,bestRow] = Computer; } // next move Depth--; } but what you should do: public static void ComputeAndExecuteBestMove() { // since Player begins, we minimize the gain value for the first move if ((MaxDepth-Depth) % 2 == 0) { min(Depth); Field[bestCol,bestRow] = Player; } else { max(Depth); Field[bestCol,bestRow] = Computer; } // next move Depth--; }
Stuck in a recursion maze
Need a push in the right direction for a class assignment. I've read other posts that mentioned creating a variable/method to store the path traveled, but not sure how to get about it... Edited 9/28/16 was able to get to the end point of the maze but still haven't figured out how to print only the path taken; I really need to import java.io.*; import java.util.*; public class Maze { private static int rows, cols, startRow, startCol, nextRow, nextCol; private static int endRow = 3; private static int endCol = 34; private static char[][] mazeBoard; //private static char start = 'S'; private static char end = 'E'; //private boolean finish = false; private char[][] explored = new char[rows][cols]; //construct the maze board public Maze() throws FileNotFoundException { Scanner in = new Scanner(new File("maze.txt")); rows = in.nextInt(); cols = in.nextInt(); startRow = in.nextInt(); startCol = in.nextInt(); //fill out the mazeBoard mazeBoard = new char[rows][cols]; int i = 0; while (in.hasNextLine()) { String inLine = in.nextLine(); if (inLine.isEmpty()) { continue; } for (int j = 0;j < cols; j++) { char nextChar = inLine.charAt(j); mazeBoard[i][j] = nextChar; System.out.print(nextChar); } System.out.println(); i++; } in.close(); } //updated the move method from void to boolean public boolean move(int row, int col, int prevRow, int prevCol) { boolean finish = false; prevRow = row; prevCol = col; //show location System.out.println("row: " + row + " col: " + col); //base case1 to check for out of bounds and not the previous position if (row < 0 || col < 0 || row >= rows || col >= cols || row != prevRow || col != prevCol) { return false; } //base case2 to see if reached exit/end point if (row == endRow && col == endCol) { System.out.println("Found the exit!"); return true; } //base case3 to check for wall if (mazeBoard[row][col] == '+' || mazeBoard[row][col] == '*') { return false; } mazeBoard[row][col] = '*'; //try to move down if (move(row + 1, col, prevRow, prevCol)) { return true; } //try to move right if (move(row, col + 1, prevRow, prevCol)) { return true; } //try to move up if (move(row - 1, col, prevRow, prevCol)) { return true; } //try to move left if (move(row, col - 1, prevRow, prevCol)) { return true; } row = prevRow; col = prevCol; return false; } public static void main(String[] args) throws FileNotFoundException { Maze maze = new Maze(); maze.move(startRow, startCol); } } ==== so I'm not sure how to implement a method to keep track of path traveled, any pointers will be greatly appreciated!
The easy way is to wait until you find the solution. Then simply record the successful moves as you crawl back up that branch of the call tree. Each winning call prepends its move to the front of the return value and passes that back up the stack. This would be something like result = move(rowM + 1, colM); if result != "" return "D" + result; // "D" for a move right else { // Try a move right ... You do have a couple of things to fix. Most of all, you have to block taking a step you've already taken. Right now, when your search hits a dead end, it keeps repeating the final step and backtrack in an infinite recursion. Second, you'll need to implement logic to abort other searches once you've found one solution. Setting a finish doesn't help much; that's a local variable, and you need to communicate to the calling program that you've failed or succeeded. Is that enough to move you to the next step?
Getting every combination of Queens?
public class SomeQueens { static Stack<Integer> s= new Stack<Integer>(); static int Solved = 0; static int current = 0; public static int solve(int n) { // n is 8 while(current < n) { // should I use current < n instead for (int i = current; i < n; i++) { if(validPosition(i)) { s.push(i); current = 0; } } if(!validPosition(current)) { if(s.empty()) { break; } if(!s.empty()) { s.pop(); current++; } } if(s.size() == n) { s.pop(); current++; printSolution(s);// this is a method, but it shouldn't matter for this Solved++; } } return Solved; } public static boolean validPosition(int column) { for( int row = 0; row < s.size(); row++) if(s.get(row) == column || ((column - s.get(row)) == (s.size() - row)) || ((s.get(row) - column) == (s.size() - row)) ) return false; // there's a conflict return true; // no conflict; } //it's called by int num = solve(n); //sop("There're" + num + "sols to the" + n "queens prob"); This is a subsection of my program for NQueens, but I seem to always get: There are 0 solutions to the 8-queens problem. I tried debugging with system.out.prints in the main method, which led me to guess that there would be something wrong in my boolean method, but I don't think it's doing anything wrong. I'm unsure if my while statement is incorrect or if the break inside the while loop is initialized before anything is even done. Thanks for the help and guidance and I'm sorry if my program and explanation makes no sense
Here is why you instantly get a zero: s.push(0); while(s.size() > n) // n is 8 { //... } return Solved; When the program arrives at the while-condition s has a size of one and n is 8. This will instantly fail and cause the method to return a zero. But that's not the only problem with the algorithm. You should seriously rethink it.
8 Non-Attacking Queens Algorithm with Recursion
I'm having trouble coding the 8 queens problem. I've coded a class to help me solve it, but for some reason, I'm doing something wrong. I kind of understand what's supposed to happen. Also, we have to use recursion to solve it but I have no clue how to use the backtracking I've read about, so I just used it in the methods checking if a position is legitimate. My board is String [] [] board = { { "O", "O"... etc etc with 8 rows and 8 columns. If I'm getting anything wrong conceptually or making a grave Java mistake, please say so :D Thanks! public void solve () { int Queens = NUM_Queens - 1; while (Queens > 0) { for (int col = 0; col < 8; col++) { int row = -1; boolean c = false; while (c = false && row < 8) { row ++; c = checkPos (row, col); } if (c == true) { board[row][col] = "Q"; Queens--; } else System.out.println("Error"); } } printBoard (); } // printing the board public void printBoard () { String ret = ""; for (int i = 0; i < 8; i++) { for (int a = 0; a < 8; a++) ret += (board[i][a] + ", "); ret += ("\n"); } System.out.print (ret); } // checking if a position is a legitimate location to put a Queen public boolean checkPos (int y, int x) { boolean r = true, d = true, u = true, co = true; r = checkPosR (y, 0); co = checkPosC (0, x); int col = x; int row = y; while (row != 0 && col != 0 ) { //setting up to check diagonally downwards row--; col--; } d = checkPosDD (row, col); col = x; row = y; while (row != 7 && col != 0 ) { //setting up to check diagonally upwards row++; col--; } d = checkPosDU (row, col); if (r = true && d = true && u = true && co = true) return true; else return false; } // checking the row public boolean checkPosR (int y, int x) { if (board[y][x].contentEquals("Q")) return false; else if (board[y][x].contentEquals("O") && x == 7) return true; else //if (board[y][x].contentEquals("O")) return checkPosR (y, x+1); } // checking the column public boolean checkPosC (int y, int x) { if (board[y][x].contentEquals("Q")) return false; else if (board[y][x].contentEquals("O") && y == 7) return true; else //if (board[y][x].contentEquals("O")) return checkPosR (y+1, x); } // checking the diagonals from top left to bottom right public boolean checkPosDD (int y, int x) { if (board[y][x].contentEquals("Q")) return false; else if (board[y][x].contentEquals("O") && (x == 7 || y == 7)) return true; else //if (board[y][x].contentEquals("O")) return checkPosR (y+1, x+1); } // checking the diagonals from bottom left to up right public boolean checkPosDU (int y, int x) { if (board[y][x].contentEquals("Q")) return false; else if (board[y][x].contentEquals("O") && (x == 7 || y == 0)) return true; else //if (board[y][x].contentEquals("O")) return checkPosR (y-1, x+1); } }
As this is homework, the solution, but not in code. Try to write a method that only handles what needs to happen on a single column; this is where you are supposed to use recursion. Do backtracking by checking if a solution exists, if not, undo your last change (i.e. change the queen position) and try again. If you only focus on one part of the problem (one column), this is much easier than thinking about all columns at the same time. And as Quetzalcoatl points out, you are assigning false to your variable in the first loop. You probably do not want to do that. You should always enable all warnings in your compiler (run javac with -Xlint) and fix them.
You are trying some kind of brute-force, but, as you already mentioned, you have no recursion. Your programs tries to put a queen on the first possible position. But at the end no solution is found. It follows that your first assumption (the position of your first queen) is invalid. You have to go back to this state. And have to assume that your checkPos(x,y) is false instead of true. Now some hints: As mentioned before by NPE int[N] queens is more suitable representation. sum(queens) have to be 0+1+2+3+4+5+6+7=28, since a position has to be unique. Instead of checking only the position of the new queen, you may check a whole situation. It is valid if for all (i,j) \in N^2 with queen(i) = j, there exists no (k,l) != (i,j) with abs(k-i) == abs(l-j)
Recursive Searching in Java
So I've been writing a program for the game boggle. I create a little board for the user to use, but the problem is I don't know how to check if that word is on the board recursively. I want to be able to check if the word the entered is indeed on the board, and is valid. By valid I mean, the letters of the word must be adjacent to each other. For those who have played boggle you'll know what I mean. All I want to do is check if the word is on the board. This is what I have so far .... import java.io.*; public class boggle { InputStreamReader isr = new InputStreamReader(System.in); BufferedReader br = new BufferedReader(isr); private String s = ""; private int [][] lettersNum = new int [5][5]; private char [][] letters = new char [5][5]; private char [] word = new char [45]; // Size at 45, because the longest word in the dictionary is only 45 letters long private char [] temp; public void generateNum() { for (int row = 0; row < 5; row ++) { for (int col = 0; col < 5; col++) { lettersNum [row][col] = (int) (Math.random() * 26 + 65); } } } public void numToChar() { for (int row = 0; row < 5; row ++) { for (int col = 0; col < 5; col++) { letters [row][col] = (char)(lettersNum[row][col]); } } } public void display() { for (int row = 0; row < 5; row ++) { for (int col = 0; col < 5; col++) { System.out.print(letters[row][col]); } System.out.println(""); } } public void getInput() throws IOException { System.out.println("Please enter a word : "); s=br.readLine(); s=s.toUpperCase(); word = s.toCharArray(); } public int search(int row, int col) { if((row <0) || (row >= 5) || (col < 0) || (col >= 5)) { return (0); } else { temp = word; return (1+ search(row +1, col) + search(row -1, col) + search(row, col + 1) + search(row, col-1) + search(row +1, col +1)+ search(row +1, col -1)+ search(row -1, col +1)+ search(row -1, col -1)); } } } The search was my searching algorithm to check if the word is on the board but I don't know if it is correct or if it will work. Furthermore, I don't know how to actually tell the user that the word is valid ! Thanks for all the help :) SO I tried to use what you suggested below but I dont really understand the int [5][5] thing. So this is what I tried, but I keep getting out of bounds errors ! Here is the soruce ... public void locate() { temp = word[0]; for (int row = 0; row <5; row++) { for (int col = 0; col <5; col++) { if(temp == letters[row][col]) { search(row,col); } } } } public int search(int row, int col) { if(letters[row][col-1]==word[count]) // Checks the letter to the left { count++; letters[row][col-1] = '-'; // Just to make sure the program doesn't go back on itself return search(row, col-1); } else if (letters[row][col+1] == word[count])// Checks the letter to the right { count++; letters[row][col+1] = '-';// Just to make sure the program doesn't go back on itself return search(row, col +1); } else if (letters[row+1][col]== word[count])// Checks the letter below { count++; letters[row+1][col] = '-';// Just to make sure the program doesn't go back on itself return search(row +1 , col); } else if (letters[row-1][col]== word[count])// Checks the letter above { count++; letters[row-1][col] = '-';// Just to make sure the program doesn't go back on itself return search(row -1 , col); } else if (letters[row-1][col-1]== word[count])// Checks the letter to the top left { count++; letters[row-1][col-1] = '-';// Just to make sure the program doesn't go back on itself return search(row -1 , col-1); } else if (letters[row-1][col+1]== word[count])// Checks the letter to the top right { count++; letters[row-1][col+1] = '-';// Just to make sure the program doesn't go back on itself return search(row -1 , col+1); } else if (letters[row+1][col-1]== word[count])// Checks the letter to the bottom left { count++; letters[row+1][col-1] = '-';// Just to make sure the program doesn't go back on itself return search(row +1 , col-1); } else if (letters[row+1][col+1]== word[count])// Checks the letter to the bottom right { count++; letters[row+1][col+1] = '-';// Just to make sure the program doesn't go back on itself return search(row +1 , col+1); } return 0; } private int count = 0; (was declared at the top of the class, in case you were wondering where I got the word[count] from
Your current search function doesn't actually do anything. I'm assuming this is homework so, no free lunch ;) The simplest approach would be to have two recursive functions: public boolean findStart(String word, int x, int y) This will do a linear search of the board looking for the first character in word. If your current location doesn't match, you call yourself with the next set of coords. When it finds a match, it calls your second recursive function using word, the current location, and a new, empty 4x4 matrix: public boolean findWord(String word, int x, int y, int[][] visited) This function first checks to see if the current location matches the first letter in word. If it does, it marks the current location in visited and loops through all the adjoining squares except ones marked in visited by calling itself with word.substring(1) and those coords. If you run out of letters in word, you've found it and return true. Note that if you're returning false, you need to remove the current location from visited. You can do this with one function, but by splitting out the logic I personally think it becomes easier to manage in your head. The one downside is that it does do an extra comparison for each first letter in a word. To use a single function you would need to keep track of what "mode" you were in either with a boolean or a depth counter. Edit: Your longest word should only be 16. Boggle uses a 4x4 board and a word can't use the same location twice. Not that this really matters, but it might for the assignment. Also note that I just did this in my head and don't know that I got it 100% right - comments appreciated. Edit in response to comments: Here's what your iterative locate would look like using the method I outline above: public boolean locate(String word) { for (int row = 0; row < 4; row++) { for (int col =0; col < 4; col++) { if (word.charAt(0) == letters[row][col]) { boolean found = findWord(word, row, col, new boolean[4][4]); if (found) return true; } } } return false; } The same thing recursively looks like the following, which should help: public boolean findStart(String word, int x, int y) { boolean found = false; if (word.charAt(0) == letters[x][y]) { found = findWord(word, x, y, new boolean[4][4]); } if (found) return true; else { y++; if (y > 3) { y = 0; x++; } if (x > 3) return false; } return findStart(word, x, y); } So here's findWord() and a helper method getAdjoining() to show you how this all works. Note that I changed the visited array to boolean just because it made sense: public boolean findWord(String word, int x, int y, boolean[][] visited) { if (letters[x][y] == word.charAt(0)) { if (word.length() == 1) // this is the last character in the word return true; else { visited[x][y] = true; List<Point> adjoining = getAdjoining(x,y,visited); for (Point p : adjoining) { boolean found = findWord(word.substring(1), p.x, p.y, visited); if (found) return true; } visited[x][y] = false; } } return false; } public List<Point> getAdjoining(int x, int y, boolean[][] visited) { List<Point> adjoining = new LinkedList<Point>(); for (int x2 = x-1; x2 <= x+1; x2++) { for (int y2 = y-1; y2 <= y+1; y2++) { if (x2 < 0 || x2 > 3 || y2 < 0 || y2 > 3 || (x2 == x && y2 == y) || visited[x2][y2]) { continue; } adjoining.add(new Point(x2,y2)); } } return adjoining; } So now, after you get input from the user as a String (word), you would just call: boolean isOnBoard = findStart(word,0,0); I did this in my head originally, then just went down that path to try and show you how it works. If I were to actually implement this I would do some things differently (mainly eliminating the double comparison of the first letter in the word, probably by combining the two into one method though you can do it by rearranging the logic in the current methods), but the above code does function and should help you better understand recursive searching.