I struggled for a long time with your canMove() method. I find the compact nature of this code very hard to trace errors in recursion, or maybe I am a bit slow . I any case I stretched out your canMove method:
your canMove():
static boolean canMove(char[][] g, int col, int row)
{
for(int i=0; i<4; i++)
{
for(int j=0; j<4; j++)
{
if(g[i][j] == 'Q' && j == row) // Same row
return false;
if(g[i][j] == 'Q' && i == col) // Same col
return false;
if(g[i][j] == 'Q' && (i-j) == (col-row)) // Diagonal
return false;
}
}
return true; // Legal move
}
my canMove():
public static boolean canMove(char [][]grid, int col, int row)
{
if(col == 0) return true; //first queen
int i, j;
//scan column rows for a queen; go up to the columnth queen
for(i = 0; i < col; i++)
if(grid[i][row] == 'Q') return false;
//up and left; once, b/c the queen is at this position
i = col-1;
j = row - 1;
//keep going up and left and check for a queen in this diagonal
while(i > -1 && j > -1 && grid[i][j] == ' ')
{
i -= 1;
j -= 1;
}
if(i < 0 || j < 0) //out of bounds
{
//up and right; once, b/c the queen is at this position
i = col-1;
j = row + 1;
//now keep going up and right and check for a queen in this diagonal
while(i >= 0 && j < numQueens && grid[i][j] == ' ')
{
i -= 1;
j += 1;
}
//no queen in the diagonals nor in this column (out of bounds); this is a partial solution
if(i < 0 || j >= numQueens) return true;
}
return false;
}
I realize it is a much longer than yours but to me its easier to trace logic errors.
I added this method to represent an initial state of the board:
public static void initGrid()
{
for(int i = 0; i < numQueens; i++)
for(int j = 0; j < numQueens; j++)
grid[i][j] = ' ';
}
I also added this method to make the output more 'pretty':
public static void printBoard(char [][]B)
{
int i, j;
for(i = 0; i < numQueens; i++)
{
for(j = 0; j < numQueens; j++)
{
if(B[i][j] == 'Q') System.out.print(" " + 'Q'); //printf("%3c", 'Q');
else System.out.print(" " + '-');//printf("<", '-');
}
System.out.println("\n");//printf("\n\n");
}
}
So the only major change was the canMove() method. The run time of the algorithm is also unchanged.
Final result
public class QueensFour
{
static int numQueens = 12;
static char[][] grid = new char[numQueens][numQueens];
static Queue result = new LinkedList<String>();;
static int queensPlaced = 0;
public static void main(String[] args)
{
int col = 0; // Use 0 to 3
initGrid();
boolean complete = solve(grid,col);
if(complete)
{
printResult();
printBoard(grid); /* I added this method to make the solution more visible */
}
}
public static void initGrid()
{
for(int i = 0; i < numQueens; i++)
for(int j = 0; j < numQueens; j++)
grid[i][j] = ' ';
}
static boolean solve(char[][] grid, int col)
{
for(int row = 0; row < numQueens; row++)
{
grid[col][row] = 'Q'; //place a queen here
//test for partial soluton
if( canMove(grid, col, row) )
{
addToResult(col, row);
/* we have place the last queen; numQueens - 1 since we our arrays start at zero */
if(col == numQueens - 1) return true;
if(!solve(grid, col+1)) removeFromResult();//partial solution thus far try placing another queen
else return true;
}
grid[col][row] = ' '; /* removing queen: queen could not be placed in this row try placing in the next row */
}
return false;
}
public static boolean canMove(char [][]grid, int col, int row)
{
if(col == 0) return true; //first queen
int i, j;
//scan column rows for a queen; go up to the columnth queen
for(i = 0; i < col; i++)
if(grid[i][row] == 'Q') return false;
//up and left; once, b/c the queen is at this position
i = col-1;
j = row - 1;
//keep going up and left and check for a queen in this diagonal
while(i > -1 && j > -1 && grid[i][j] == ' ')
{
i -= 1;
j -= 1;
}
if(i < 0 || j < 0) //out of bounds
{
//up and right; once, b/c the queen is at this position
i = col-1;
j = row + 1;
//now keep going up and right and check for a queen in this diagonal
while(i >= 0 && j < numQueens && grid[i][j] == ' ')
{
i -= 1;
j += 1;
}
//no queen in the diagonals nor in this column (out of bounds); this is a partial solution
if(i < 0 || j >= numQueens) return true;
}
return false;
}
static void addToResult(int col, int row)
{
String resultValue = "[" + col + "," + row + "]";
result.add(resultValue);
}
static void removeFromResult()
{
try {
result.remove();
}
catch(Exception e)
{
System.out.println("Error in Dequeue");
}
}
/* I added this method to make the solution more visible */
public static void printBoard(char [][]B)
{
int i, j;
for(i = 0; i < numQueens; i++)
{
for(j = 0; j < numQueens; j++)
{
if(B[i][j] == 'Q') System.out.print(" " + 'Q'); //printf("<", 'Q');
else System.out.print(" " + '-');//printf("<", '-');
}
System.out.println("\n");//printf("\n\n");
}
}
static void printResult()
{
while(!(result.isEmpty()))
{
try {
String move = result.remove().toString();
System.out.println(move);
}
catch(Exception e)
{
System.out.println("Error in Dequeue");
}
}
}
}
Backtracking is uUuUUUuuGgGgGGggLLLLLLLyyyYYYYYYYyY!
Perfection of means and confusion of ends seem to characterize our age. Albert Einstein :confused: