I am currently trying to learn the topic of Backtracking in Java. It is really really confusing for me because I am stuck.
The problem is to find ways in which N Queens can be placed in NxN Chess board so that none of the Queens can attack each other. A queen can attack in the same row, same column and diagonally. My code goes like this:
import java.util.Scanner;
class Main {
public static void putZero(int[][] board,int n){
for(int i = 0;i<n;i++){
for(int j=0;j<n;j++){
board[i][j]=0;
}
}
}
public static void printBoard(int[][] board,int n){
for(int i = 0;i<n;i++){
for(int j=0;j<n;j++){
System.out.print(board[i][j]);
}
System.out.print("\n");
}
System.out.print("\n\n\n");
}
public static void SolveNQ(int n){
int[][] board = new int[n][n];
putZero(board,n);
if(SolveQUtil(board,0,n)==true){
printBoard(board,n);
}
}
public static boolean isSafe(int row, int col, int[][] board,int n){
int i,j;
for(i=0;i<col;i++){
if(board[row][i]==1)
return false;
}
for(i=row,j = col; i >= 0 && j >= 0; i--, j--){
if(board[i][j]==1)
return false;
}
for (i = row, j = col; j >= 0 && i < n; i++, j--)
if (board[i][j] == 1)
return false;
return true;
}
public static boolean SolveQUtil(int[][] board, int col, int n){
if(col>=n){
return true;
}
else
for(int i=0;i<n;i++){
if(isSafe(i,col,board,n)==true){
board[i][col]=1;
boolean a = SolveQUtil(board,col+1,n);
if(a==true)
return true;
else
board[i][col]=0;
}
}
return false;
}
public static void main(String[] args){
Scanner scan = new Scanner(`enter code here`System.in);
int n = scan.nextInt();;
SolveNQ(n);
}
}
It is producing the result I want, but I am not understanding how this works. In my method SolveQUtil(), the method is called again which is "recursive". When col = 0 is called, the Q1 is placed at [0,0] as there are no existing queens. But when col = 1 is called recursively, it searches for the suitable place and returns 'true'. Now, isn't the SolveNQ() supposed to print the solution every time true is returned? When does it return false? How is this working? I am a beginner and can anyone please explain this to me, step by step? Thank you in advance.
SolveNQ, which does the printing, is not called recursively; SolveQUtil, which SolveNQ calls, and which does not print anything, is recursive.
I have made a class where a 6x10 2D array is generated to act as a board.
A random starting location is then generated in the constructor.I only want adjacent moves to be possible.
For example, if the random location has been generated as (2,3) then for example the user enters (1,2) it would be a valid move, but (6,1) would be an invalid move.
Then if the user enters say (1,2), they can then go to any adjacent cell from (1,2).
I have included the class below, and the adjacent method I tried to make to test it, but I'm a bit confused on how I am approaching this.
import java.util.Arrays;
import java.util.Random;
public class Test {
public static final int ROWS = 6;
public static final int COLUMNS = 10;
public int[][] board;
public static void main(String[] args)
{
Test t = new Test();
t.getBoard();
t.makeMove(6,1); //I want this to be an invalid move.
t.getBoard();
t.makeMove(1,2); // this should be a valid move
t.getBoard();
}
public Test()
{
board = new int[ROWS][COLUMNS];
createRandomLocation();
}
public void createRandomLocation()
{
Random rand = new Random();
int x = rand.nextInt(6);
int y = rand.nextInt(10);
board[x][y] = 1;
}
public void makeMove(int x,int y){
if (Math.abs(x-cur_x)==0 || Math.abs(y-cur_y)==0) {
board[x][y] = 1;
}
public String getBoard() {
for (int i = 0; i < board.length; i++) {
for (int j = 0; j < board[i].length; j++) {
System.out.print(board[i][j] + " ");
}
System.out.println();
}
System.out.println();
return Arrays.deepToString(board);
}
}
Adjacent:
/*public boolean isMoveAllowed(int [][] array,int x, int y){
boolean adjacent = false;
int trueCount = 0;
if(array[x-1][y-1] == 0) trueCount++; //topleft
if(array[x-1][y] == 0) trueCount++; //top
if(array[x-1][y+1] == 0) trueCount++;//topright
if(array[x][y+1] == 0) trueCount++;//right
if(array[x][y-1] == 0) trueCount++;//left
if(array[x+1][y-1] == 0) trueCount++;//bottomleft
if(array[x+1][y] == 0) trueCount++;//bottom
if(array[x+1][y+1] == 0) trueCount++; //bottomright
if (trueCount == 8)
{
adjacent = true;
}
return adjacent;
}*/
Your problem description has the answer baked into it already. You want any move from (a,b) to (c,d) to be legal if the distance between a and c, and b and d, is zero or one. So if you see Math.abs(a-c)>1, that's an illegal move. So: have the current position stored in some variables, and compare them to the desired new location:
public static void main(String[] args)
{
Board b = new Board(6, 10);
try {
b.tryMove(6,1);
} catch(IllegalMoveException e) {
// do whatever you need to do to inform the user that move is illegal
}
}
With the Board class responsible for tracking coordinates:
class Board {
protected int cur_x, cur_y, rows, cols;
public Board(int rows, int cols) {
this.rows = rows;
this.cols = cols;
this.setRandomPosition();
}
public void setRandomPosition() {
cur_x = (int) Math.round(Math.random() * cols);
cur_y = (int) Math.round(Math.random() * rows);
}
public void tryMove(int x, int y) throws IllegalMoveException {
if (Math.abs(x-cur_x)>1 || Math.abs(y-cur_y)>1) {
throw new IllegalMoveException(...);
}
// bounds check omitted here, but: ensure that
// 0<=x<cols and 0<=y<rows, otherwise throw an
// IllegalMoveException as well.
cur_x = x;
cur_y = y;
}
// with getters for the current x and y, etc.
}
It would be much easier to test for a true case rather than a false case like you currently have, the isMoveAllowed method should look something like this:
public boolean isMoveAllowed(int[][] array, int x, int y) {
return ((array[x + 1][y] == 1) ||
(array[x - 1][y] == 1) ||
(array[x][y + 1] == 1) ||
(array[x][y - 1] == 1));
}
This will return true if the move is adjacent to the current player position
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.