8 Bishops to occupy whole board [Backtracking] - java

I have a task to write a program which sets up 8 bishops in chess board to occupy whole board. It should end up when first solution is found and print everything out. Here's my written code in Java, and I struggle with finishing it using backtracking ( that place is commented in the code).
/*
* 0 - not occupied square
* 1 - bishop standing square
* 2 - occupied square (diagonal)
*/
public class BishopsBT {
public int [][] solution;
final int N = 8; // number of squares in column and row (chess board)
final int solved = 120; //Sum of 1's and 2's in case of all occupied board
int sum; //current sum of board
public BishopsBT(){
solution = new int [N][N] ;
}
public void solve() {
if(placeBishops(0)){
//print the result
clear(); // clears all 2's
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
System.out.print(" " + solution[i][j]);
}
System.out.println();
}
} else{
System.out.println("NO SOLUTION EXISTS");
}
}
public boolean placeBishops (int bishop){
for (int row = 0; row < N; row++) {
// check if bishop can be placed
if (canPlace(solution, row, bishop)) {
// place the bishop
solution[row][bishop] = 1;
}
}
if (allSpaceOccupied()) {
return true;
} else {
// SOME BACKTRACKING CODE HERE
return false;
}
}
// check if bishop can be placed at matrix[row][column]
public boolean canPlace(int[][] matrix, int row, int column) {
// we need to check all diagonals
// whether no bishop is standing there
for (int i = row, j = column; i >= 0 && j >= 0; i--, j--) {
if (matrix[i][j] == 1) {
return false;
}
}
for (int i = row, j = column; i >= 0 && j < matrix.length; i--, j++) {
if (matrix[i][j] == 1) {
return false;
}
}
for (int i = row, j = column; i < matrix.length && j >= 0; i++, j--) {
if (matrix[i][j] == 1) {
return false;
}
}
for (int i = row, j = column; i < matrix.length && j < matrix.length; i++, j++) {
if (matrix[i][j] == 1) {
return false;
}
}
// if we are here that means we are safe to place Bishop
return true;
}
public boolean allSpaceOccupied() {
// clears previously occupied space
clear();
// occupies new space
for (int i = 0; i < solution.length; i++) {
for ( int j = 0; j < solution.length; j++) {
if (solution[i][j] == 1) diagonalOccupy(i,j);
}
}
sum = 0;
// counts sum of occupied space
for (int i = 0; i < solution.length; i++) {
for ( int j = 0; j < solution.length; j++) {
sum += solution [i][j];
}
}
if (sum == solved) return true;
// else
return false;
}
public void diagonalOccupy(int row, int column) {
// writes 2 in each bishop's occupied square
for (int i = row, j = column; i >= 0 && j >= 0; i--, j--) {
if (solution[i][j] == 0) {
solution[i][j] = 2;
}
}
for (int i = row, j = column; i >= 0 && j < solution.length; i--, j++) {
if (solution[i][j] == 0) {
solution[i][j] = 2;
}
}
for (int i = row, j = column; i < solution.length && j >= 0; i++, j--) {
if (solution[i][j] == 0) {
solution[i][j] = 2;
}
}
for (int i = row, j = column; i < solution.length && j < solution.length; i++, j++) {
if (solution[i][j] == 0) {
solution[i][j] = 2;
}
}
}
// clears all 2's on the board
public void clear() {
for (int i = 0; i < solution.length; i++) {
for ( int j = 0; j < solution.length; j++) {
if (solution[i][j] == 2) solution[i][j] = 0;
}
}
}
public static void main(String[] args) {
BishopsBT q = new BishopsBT();
q.solve();
}
}
The thing is that at the moment my program puts bishops in first column and this layout does not occupy all space. Of course, I could simply put everything in third column and problem is solved. However, I have to use backtracking and have no idea how. If you have any ideas or tips, I would be really glad to hear them.

Your solution assumes that all bishops must be placed in different rows. This is not true for all solutions. (There is a solution where all bishops are in the third or fourth column. You are not looking for all solutions, but if you were, you'd be missing out on many solutions by this assumption.)
You also don't need the canPlace check: There is no restriction that the bishops can't threaten each other. (This might be a valid technique to speed up the search, but again, you'll miss out on some solutions when you apply it. If you want to use it, there's no need to check all diagonal cells for already placed bishops; it is enough to check whether the current cell has been marked as "occupied" or threatened.)
If you are going to use a brute force approach with backtracking, you could test all possible combinations of bishops. That's C(64, 8) or 4,426,165,368 combinations.
You can cut down on the possibilities drastically, but not by assuming that bishops must be in diferent rows. Instead, note that your solution consists of two independent solutions. A bishop on a white square can only threaten white squares and a bishop on a black square can only threaten black squares. So find a solution to place four bishops on the board that threaten all white squares. Then
(If you want to find all solutions, find all k sub-solutions and combine them to k² complete solutions.)
This separation of cases cuts down the possible arrangements to test to C(32, 8), or 35,960. Your strategy to consider only configurations where there is exaclty one bishop per row checks 8^8 (about 16 million) possibilities. It misses some solutions and checks meny configurations where not four bishops are on white squares and four on black squares.
The principle of backtracking was given in the other answer. If you label the 32 white squares like this:
01 02 03 04
05 06 07 08
09 10 11 12
13 14 15 16
17 18 19 20
21 22 23 24
25 26 27 28
29 30 31 32
you can use an recursive approach like this one (in pseudo-Java):
bool place(int i, int start) {
if (i == 8) {
if (allOccupied()) {
print();
return true;
}
} else {
for (int j = start, j < 32; j++) {
int row = j / 4;
int col = 2 * (j % 4) + row % 2;
// add bishop at (col, row)
// save occupancy matrix
// add threat by (col, row) to matrix
if (place(i + 1, j + 1)) return true;
// revert matrix to saved matrix
// remove bishop from (col, row)
}
}
return false;
}
and start it with
place(0, 0);

You should do something like this :
public boolean placeBishops (int bishop){
if(bishop == 8){
if(allSpaceOccupied()){
//Print the board here, i.e found the solution
//also check the indexing of the bishop,
//i have assumed that they start from 0
return true;
}else{
return false;
}
}
for (int row = 0; row < N; row++) {
// check if bishop can be placed
if (canPlace(solution, row, bishop)) {
// place the bishop
solution[row][bishop] = 1;
boolean found = placeBishops(bishop+1);
if(found == true) return true;
solution[row][bishop] = 0;
}
}
return false;
}
we can check if a place is good for a paticular bishop or not, and accordingly increment the bishop count, if we do not find the solution going down that path, we reset the solution array for the current bishop index and the corresponding row for that bishop, so that we can look for another possible solution.

Related

Display the corresponding horizontal and vertical histograms in java

I just found a good question about arrays in java and I'd like to solve it
This is the question and expected output Example:
I've already written a correct way to print horizontally.
My approach to write vertically is:
public static void verticalHistogram(int[] array, int maximum) {
int one=0, two=0 , three=0, four=0, five=0;
for (int i=0; i< array.length; i++) {
if(array[i] < 20) {
one +=1;
}
else if (array[i] >= 20 && array[i] <= 39 ) {
two +=1;
}
else if (array[i] >= 40 && array[i] <= 59 ) {
three +=1;
}
else if (array[i] >= 60 && array[i] <= 79 ) {
four +=1;
}
else {
five +=1;
}
}
int arr[] = {one,two,three,four,five};
for (int i = 0; i < maximum; i++) {
for (int j = 0; j < 5; j++) {
if (arr[j] > i) {
System.out.print("* ");
} else {
System.out.print(" ");
}
}
System.out.println();
}
System.out.println("00-19 20-39 40-59 60-79 80-100 \n");
}
Overally your approach is correct:
First you create a histogram array from the input array. (this is what you already have)
You get the maximum value of the histogram array to know how many rows to print (you need to write it)
For each row starting from the maximum row and for each element in histogram, print the * if the histogram of the adequate cell should be visible, e.g.
for (int row = maximum; row > 0; --row) {
for (int j = 0; j < 5; j++) {
// if value of hist[j] >= row then print a star else dont print it
}
}

Sudoko grid conversion from 9*9 to all grid size

I have coded for Sudoku puzzle in Java. The thing is my code has limitation for giving inputs for 9*9 grid. How do I make my code adaptable for all the grids. Please have patience. I am new to java.
What changes do I need to make so that the code can run on all grid sizes?The grid is square not a rectangle.
class Solution {
public void solveSudoku(char[][] board) {
if(solveSudoku2(board)) {
return;
}
}
public boolean solveSudoku2(char[][] board) {
boolean isEmpty = true;
int row = -1;
int col = -1;
int n = board.length;
//this code is used to check if there exists any empty cell in sudoku board
//if there is any empty cell, that means we are not done yet and we need to solve it further,
// so we cannot return true at any point until all the cells are full
//by empty cell, I mean cells having '.' as the value
for(int i = 0; i < board.length; i++) {
for(int j = 0; j < board[0].length; j++) {
if(board[i][j] == '.') {
row = i;
col = j;
isEmpty = false;
break;
}
}
if(!isEmpty) {
break;
}
}
if(isEmpty) {
return true;
}
//loop for all the numbers and start placing in the empty cells
//numbers start from 1 to n
for(int num = 1; num <= n; num++) {
//convert number to char
char char_num = (char)(num + '0');
//check if the number we are adding satisfies all the sudoku rules,
// if it does, then we place that number in the cell
if(checkSafe(board,char_num,row,col)) {
board[row][col] = (char)(num + '0');
//using this number in place row,col, we check for all the other empty places and see if the board is returning true or not
// if the board is not filled that means that we need to use other number in row,col place.
//hence backtrack.
if(solveSudoku2(board)) {
return true;
} else {
board[row][col] = '.';
}
}
}
return false;
}
public boolean checkSafe(char[][] board, char num, int row, int col) {
//checkk if num is present in the row
for(int i = 0; i< board.length; i++ ) {
if(board[row][i] == num) {
return false;
}
}
for(int j = 0; j < board[0].length; j++) {
if(board[j][col] == num) {
return false;
}
}
int checknum = (int)Math.sqrt(board.length);
//check for the current grid. grid will be basically checknum*checknum matrix. where every matrix will start from startrow to startrow + checknum having checknum length.
// so, we we have row = 0, then matrix will start from 0 to 2, i.e. the first 3x3 matrix.
// however, we have row = 2, then also the matrix will start from 0 to 2 - the first 3x3 matrix.
//however, if row = 3, then we will start our matrix from 3 and cotinute upto 5.
int startrow = row - row % checknum;
int startcol = col - col % checknum;
for(int k = startrow; k < startrow + checknum; k++) {
for(int l = startcol; l < startcol + checknum; l++) {
if(board[k][l] == num) {
return false;
}
}
}
return true;
}
}

Looping through connect four grid

I am working on a Connect Four project, but am struggling with the win check. I think it has something to do with how I am looping over the grid. It works horizontally but not vertically, and it kinda works diagonally.
public boolean gameStatus(MyBoard gameBoard, int columnPosition, CellState gameToken) {
int rowPosition = 0;
for (int i = 0; i < gameBoard.getWidth(); i++)
for (int j = 0; j < gameBoard.getHeight(); j++)
if (gameBoard.get(i, columnPosition) != CellState.FREE)
rowPosition = i;
if (checkColumn(gameBoard, columnPosition, gameToken, rowPosition))
return true;
}
public boolean checkColumn(MyBoard gameBoard, int columnPosition, CellState gameToken, int rowPosition) {
int tokenCounter = 1;
if ((rowPosition + 4) <= 6)
for (int i = rowPosition + 1; i <= rowPosition + 3; i++)
if (gameToken == gameBoard.get(i, columnPosition))
tokenCounter++;
else
break;
if (tokenCounter == 4)
return true;
return false;
}
I think this only checks the last row which is non-empty.
Java doesn't care about indentation, so without braces, if and for only use the statement after them. This means your if (checkColumn... only runs once, not once for each column.
You might want to try something like
public boolean gameStatus(MyBoard gameBoard, int columnPosition, CellState gameToken) {
int rowPosition = 0;
for (int i = 0; i < gameBoard.getWidth(); i++) {
for (int j = 0; j < gameBoard.getHeight(); j++) {
if (gameBoard.get(i, columnPosition) != CellState.FREE) {
rowPosition = i;
}
}
if (checkColumn(gameBoard, columnPosition, gameToken, rowPosition)) {
return true;
}
}
In general. I'd advise against writing if, for and while statements without braces. The two characters it saves is not worth the bugs you may accidentally introduce

Java: Game of Life - issue with neighbours

I'm new to this forum so I hope I'm posting this question in the right way - otherwise, please let me know.
I'm trying to write the code for a simple Game of Life animation in Java, and most of it seems to work as intended.
However, there is a problem with one of the neighbour 'rules' that is supposed to "kill" a cell if it has less than 2 neighbours, meaning that cells can have one or no neighbours and still survive - can be seen here: http://peecee.dk/upload/view/435109. All other rules seem to work fine.
Can anyone help me figure out why it ignores the rule (Live cells are equal to '1', dead to '0'.):
if (this.state[i][j] == 1 &&
liveNeighbours(i, j) > 3 || liveNeighbours(i, j) < 2) {
this.tempState[i][j] = 0;
Thanks a ton in advance!
The code is as follows:
import java.util.*;
public class GameOfLife {
private int[][] state;
private int[][] tempState;
//Constructor that creates n x n grid of randomly placed live cells
public GameOfLife(int n) {
this.state = new int[n+2][n+2];
this.tempState = new int[n+2][n+2];
createRandomBoard(n);
}
//Sets up the initial state
public void createRandomBoard(int n) {
//Creates (n+2) x (n+2) grid of dead cells
for (int i = 0; i < n+2; i++) {
for (int j = 0; j < n+2; j++) {
this.state[i][j] = 0;
}
}
//Creates n x n grid of randomly placed live cells. Live cells are equal to '1', dead to '0'.
for (int i = 1; i < n + 1; i++) {
for (int j = 1; j < n + 1; j++) {
int a = (int)Math.round(Math.random());
this.state[i][j] = a;
}
}
drawBoard();
}
//Draws the live cells as dots based on current state
public void drawBoard() {
StdDraw.show(50);
StdDraw.clear();
for (int i = 1; i < this.state.length-2; i++) {
for (int j = 1; j < this.state.length-2; j++) {
StdDraw.setXscale(1,this.state.length-3);
StdDraw.setYscale(1,this.state.length-3);
StdDraw.setPenRadius((double)1/this.state.length);
if (this.state[i][j] == 1) {
StdDraw.point(i, j);
}
}
}
StdDraw.show(50);
}
//Determines which cells live or die in the next state
public void nextState() {
//Copies the state array to a temporary state(array) during killing/reviving
for (int i = 1; i < this.state.length-2; i++) {
for (int j = 1; j < this.state.length-2; j++) {
this.tempState[i][j] = this.state[i][j];
}
}
//Kills cells with more than 3 or less than 2 neighbours and revives dead cells with 3 neighbours
for (int i = 1; i < this.state.length-2; i++) {
for (int j = 1; j < this.state.length-2; j++) {
if (this.state[i][j] == 1 && liveNeighbours(i, j) > 3 || liveNeighbours(i, j) < 2) {
this.tempState[i][j] = 0;
}
else if (this.state[i][j] == 0 && liveNeighbours(i, j) == 3) {
this.tempState[i][j] = 1;
}
}
}
//Copies the modified temporary state array to the original state(array) again
for (int i = 1; i < this.state.length-2; i++) {
for (int j = 1; j < this.state.length-2; j++) {
this.state[i][j] = this.tempState[i][j];
}
}
drawBoard();
}
//Counts the number of live neighbours to a cell
private int liveNeighbours(int x, int y) {
int numLiveNeighbours = 0;
for (int i = x-1; i < x+2; i++) {
for (int j = y-1; j < y+2; j++) {
if (this.state[i][j] == 1) {
numLiveNeighbours++;
}
}
}
numLiveNeighbours --;
return numLiveNeighbours;
}
public String toString() {
return Arrays.deepToString(this.state);
}
public int[][] getState() {
return this.state;
}
}
Your condition doesn't seem to express what you want. You need to change it to:
if (this.state[i][j] == 1 && (liveNeighbours(i, j) > 3 || liveNeighbours(i, j) < 2))
Check operators precedence rules in Java. You were killing those cells being alive and having more than 3 neighbours or those cells with less than two of them.
With this change you will be killing those cells alive and with more than 3 or less than 2 neighbours.
I think your liveNeighbours has a little flaw too: Your are counting (x,y) neighbours and (x,y) itself. You should change it for:
private int liveNeighbours(int x, int y) {
int numLiveNeighbours = 0;
for (int i = x-1; i < x+2; i++) {
for (int j = y-1; j < y+2; j++) {
if (this.state[i][j] == 1 && (x != i || j != y)) {
numLiveNeighbours++;
}
}
}
return numLiveNeighbours;
}

Why does method backtrack not work when called from within method

When I call method backtrack a second time from within it (backtrack) because I need to go back two moves, it does not work. Does anyone have any idea? Here is my code:
// width of board
static final int SQUARES = 8;
// board
static boolean[][] board = new boolean[SQUARES][SQUARES];
// represents values for number of squares eliminated if queen is placed in square
static int[][] elimination = new int[SQUARES][SQUARES];
// store position of queens
static boolean[][] position = new boolean[SQUARES][SQUARES];
// store row
static int[] row = new int[8];
// store column
static int[] column = new int[8];
// Write a program to solve the Eight Queens problem
public static void main(String[] args)
{
Arrays.fill(row, -1);
Arrays.fill(column, -1);
// reset elimination table
fillElim();
// count queens on board
short counter = 0;
// while board is not full
while(counter < 8) {
// place next queen on board
placeQueen(-1, -1);
// reset elimination table
fillElim();
// backtrack and fill board back to this point
while(isFull() && counter < 7)
backtrack(counter);
counter++;
} // end while
System.out.println("Queens on board: " + counter);
printBoard();
for(int i = 0; i < row.length; i++)
System.out.println(column[i] + "/" + row[i]);
} // end method main
// Print elimination table
public static void printE()
{
for(int i[] : elimination) {
for(int j = 0; j < i.length; j++)
System.out.printf("%-3d", i[j]);
System.out.println();
} // end for
} // end printE
public static void printBoard()
{
for(int i = 0; i < board.length; i++) {
for(int j = 0; j < board.length; j++) {
if(board[i][j] && position[i][j])
System.out.print("o ");
else if(board[i][j])
System.out.print("x ");
else
System.out.print("% ");
} // end inner for
System.out.println();
} // end outer for
} // end method printBoard
// Write method to calculate how many squares are eliminated if queen is placed in that square
public static void fillElim()
{
// if any squares that could be eliminated already are eliminated, subtract 1
for(int i = 0; i < elimination.length; i++) {
for(int j = 0; j < elimination[i].length; j++) {
elimination[i][j] = openSquares(i, j);
} // end inner for
} // end outer for
} // end method fillElimination
// Number of squares eliminatable by placing queen in any given square
public static int openSquares(int row, int column)
{
// if square is already eliminated, it cannot be used
if(board[row][column])
return 0;
// total number of squares elimintable from any given square, count square itself
int total = 1 + openHorizontal(row) + openVertical(column) + openUpSlope(row, column) + openDownSlope(row, column);
return total;
} // end method openSquares
// Return number of open squares in a row
public static int openHorizontal(int row)
{
// total of row
int total = 0;
for(boolean b : board[row]) {
// if square is "true" (open), increment total open squares
if(!b)
total++;
} // end for
// return total not counting current square
return total - 1;
} // end method openHorizontal
// Return number of open squares in a column
public static int openVertical(int column)
{
// total of column
int total = 0;
// if square is "true" (open), increment total open squares
for(boolean[] b : board) {
// if square is "true" (open), increment total open square
if(!b[column])
total++;
} // end for
// return total not counting current square
return total - 1;
} // end method openVertical
// Return number of open squares in a column
public static int openDownSlope(int x, int y)
{
// total of downward-sloping diagonal
int total = 0;
// if square is "true" (open), increment total open squares
for(int i = 0; i < board.length; i++) {
// test all values before use to prevent array index errors
// all squares to the top right of the checking square
if(x+i >= 0 && x+i < board.length && y+i >= 0 && y+i < board.length) {
// else increment total
if(!board[x+i][y+i])
total++;
} // end if
// all squares to the bottom left of the checking square
if(x-i >= 0 && x-i < board.length && y-i >= 0 && y-i < board.length) {
// else increment total
if(!board[x-i][y-i])
total++;
} // end if
} // end for
// return total not counting current square
return total - 2;
} // end method openDownSlope
// Return number of open squares in a column
public static int openUpSlope(int x, int y)
{
// total of upward-sloping diagonal
int total = 0;
// if square is "true" (open), increment total open squares
for(int i = 0; i < board.length; i++) {
// test all values before use to prevent array index errors
// all squares to the top right of the checking square
if(x+i >= 0 && x+i < board.length && y-i >= 0 && y-i < board.length) {
// else increment total
if(!board[x+i][y-i])
total++;
} // end if
// all squares to the bottom left of the checking square
if(x-i >= 0 && x-i < board.length && y+i >= 0 && y+i < board.length) {
// else increment total
if(!board[x-i][y+i])
total++;
} // end if
} // end for
// return total not counting current square
return total - 2;
} // end method openDownSlope
// Are all squares on the board filled?
public static boolean isFull()
{
for(boolean b[] : board) {
for(boolean bb : b) {
if(!bb)
return false;
} // end inner for
} // end outer for
// if this point is reached, board is full
return true;
} // end method isFull
// Place a queen on the board
public static void placeQueen(int lastRow, int lastCol)
{
int[] bestSquare = bestMove(lastRow, lastCol);
System.out.println("&&&&&&");
for(int i = 0; i < row.length; i++)
System.out.println(row[i] + "/" + column[i]);
System.out.println("&&&&&&");
// assign queen to board
board[bestSquare[0]][bestSquare[1]] = true;
printBoard();
System.out.println();
// clear blocked squares from board
elimSquares(bestSquare[0], bestSquare[1]);
// reset elimination table
fillElim();
// store squares
for(int i = 0; i < row.length; i++) {
if(row[i] == -1) {
row[i] = bestSquare[0];
column[i] = bestSquare[1];
break;
} // end if
} // end for
// mark queen's position
position[bestSquare[0]][bestSquare[1]] = true;
printBoard();
} // end method placeQueen
// Return lowest number in elimination table
public static int[] bestMove(int lastRow, int lastCol)
{
// store lowest number - set to impossibly low
int low = 100;
// store coordinates
int[] move = {-1, -1};
// store limit of use
int limit;
if(lastRow == -1)
limit = 0;
else
limit = elimination[lastRow][lastCol];
// if lastRow is not -1, search for duplicate numbers after current square
if(lastRow != -1) {
// test for equal elimination numbers farther down on board
for(int i = lastRow; i < board.length; i++) {
for(int j = lastCol+1; j < board[i].length; j++) {
if(!board[i][j] && elimination[i][j] == limit) {
move[0] = i;
move[1] = j;
return move;
}
} // end inner for
} // end outer for
} // end if
// test for any available squares left on board
for(int i = 0; i < board.length; i++) {
for(int j = 0; j < board[i].length; j++) {
if(!board[i][j] && elimination[i][j] > limit && elimination[i][j] < low)
low = elimination[i][j];
} // end inner for
} // end outer for
// get move coordinates for square, if needed to get best square after two backtracks
for(int i = 0; i < board.length; i++) {
for(int j = 0; j < board[i].length; j++) {
if(!board[i][j] && elimination[i][j] == low) {
move[0] = i;
move[1] = j;
return move;
} // end if
} // end inner for
} // end outer for
return move;
} // end method bestMove
public static void elimSquares(int row, int column)
{
// total number of squares elimintable from any given square, count square itself
elimHorizontal(row);
elimVertical(column);
elimUpSlope(row, column);
elimDownSlope(row, column);
} // end method openSquares
// Eliminate row
public static void elimHorizontal(int row)
{
// eliminate row
for (int i = 0; i < board[row].length; i++)
board[row][i] = true;
} // end method elimHorizontal
// Eliminate column
public static void elimVertical(int column)
{
// eliminate column
for(boolean[] b : board)
b[column] = true;
} // end method elimVertical
// Eliminate downward slope
public static void elimDownSlope(int x, int y)
{
// loop through downward slope
for(int i = 0; i < board.length; i++) {
// test all values before use to prevent array index errors
// eliminate all squares to the bottom right of the checking square
if(x+i >= 0 && x+i < board.length && y+i >= 0 && y+i < board.length)
board[x+i][y+i] = true;
// eliminate all squares to the top left of the checking square
if(x-i >= 0 && x-i < board.length && y-i >= 0 && y-i < board.length)
board[x-i][y-i] = true;
} // end for
} // end method elimDownSlope
// Eliminate upward slope
public static void elimUpSlope(int x, int y)
{
// loop through upward slope
for(int i = 0; i < board.length; i++) {
// test all values before use to prevent array index errors
// eliminate all squares to the bottom right of the checking square
if(x+i >= 0 && x+i < board.length && y-i >= 0 && y-i < board.length)
board[x+i][y-i] = true;
// eliminate all squares to the top left of the checking square
if(x-i >= 0 && x-i < board.length && y+i >= 0 && y+i < board.length)
board[x-i][y+i] = true;
} // end for
} // end method elimDownSlope
// If not found solution and board is full
public static void backtrack(int lastMove)
{
// store last move
int lastRow = row[lastMove];
int lastCol = column[lastMove];
// clear board
resetBoard();
// go back 1 move
goBack(lastMove);
// refill board
for(int i = 0; i < row.length; i++) {
// escape if out of bounds
if(row[i] == -1)
break;
// replace queens
board[row[i]][column[i]] = true;
// fill elimination table
elimSquares(row[i], column[i]);
} // end for
// while no open squares, go back one more row
// keep track of times looped
int counter = 0;
while(!openSpaces(lastRow, lastCol)) {
System.out.println("backtrack " + counter);
backtrack(lastMove-1);
counter++;
} // end while
// set queen in square
placeQueen(lastRow, lastCol);
} // end method backtrack
// Clear board
public static void resetBoard()
{
// clear board
for(boolean[] b : board)
for(int j = 0; j < b.length; j++)
b[j] = false;
} // end method resetBoard
// Go back 1 move
public static void goBack(int lastMove)
{
// remove queen from last position
position[row[lastMove]][column[lastMove]] = false;
// remove last move from table
row[lastMove] = -1;
column[lastMove] = -1;
} // end method goBack
// Return number of open, untested spaces on board
public static boolean openSpaces(int lastRow, int lastCol)
{
// store number of open, untested squares
int squares = 0;
// store limit of use
int limit = elimination[lastRow][lastCol];
// store next limit for use if no more squares at limit
int nextLimit = limit + 1;
// test for equal elimination numbers farther down on board
for(int i = lastRow; i < board.length; i++) {
for(int j = lastCol+1; j < board[i].length; j++) {
if(!board[i][j] && elimination[i][j] == limit)
squares++;
} // end inner for
} // end outer for
// test for any available squares left on board
for(int i = 0; i < board.length; i++) {
for(int j = 0; j < board[i].length; j++) {
if(!board[i][j] && elimination[i][j] >= nextLimit)
squares++;
} // end inner for
} // end outer for
return squares != 0;
} // end method openSpaces
This calls method goBack; method placeQueen, which calls method bestMove; and a few others. These three mentioned methods may also have an error, I do not know for sure:
// Go back 1 move
public static void goBack(int lastMove)
{
// remove queen from last position
position[row[lastMove]][column[lastMove]] = false;
// remove last move from table
row[lastMove] = -1;
column[lastMove] = -1;
} // end method goBack
// Place a queen on the board
public static void placeQueen(int lastRow, int lastCol)
{
int[] bestSquare = bestMove(lastRow, lastCol);
System.out.println("&&&&&&");
for(int i = 0; i < row.length; i++)
System.out.println(row[i] + "/" + column[i]);
System.out.println("&&&&&&");
// assign queen to board
board[bestSquare[0]][bestSquare[1]] = true;
printBoard();
System.out.println();
// clear blocked squares from board
elimSquares(bestSquare[0], bestSquare[1]);
// reset elimination table
fillElim();
// store squares
for(int i = 0; i < row.length; i++) {
if(row[i] == -1) {
row[i] = bestSquare[0];
column[i] = bestSquare[1];
break;
} // end if
} // end for
// mark queen's position
position[bestSquare[0]][bestSquare[1]] = true;
printBoard();
} // end method placeQueen
// Return lowest number in elimination table
public static int[] bestMove(int lastRow, int lastCol)
{
// store lowest number - set to impossibly low
int low = 100;
// store coordinates
int[] move = {-1, -1};
// store limit of use
int limit;
if(lastRow == -1)
limit = 0;
else
limit = elimination[lastRow][lastCol];
// if lastRow is not -1, search for duplicate numbers after current square
if(lastRow != -1) {
// test for equal elimination numbers farther down on board
for(int i = lastRow; i < board.length; i++) {
for(int j = lastCol+1; j < board[i].length; j++) {
if(!board[i][j] && elimination[i][j] == limit) {
move[0] = i;
move[1] = j;
return move;
}
} // end inner for
} // end outer for
} // end if
// test for any available squares left on board
for(int i = 0; i < board.length; i++) {
for(int j = 0; j < board[i].length; j++) {
if(!board[i][j] && elimination[i][j] > limit && elimination[i][j] < low)
low = elimination[i][j];
} // end inner for
} // end outer for
// get move coordinates for square, if needed to get best square after two backtracks
for(int i = 0; i < board.length; i++) {
for(int j = 0; j < board[i].length; j++) {
if(!board[i][j] && elimination[i][j] == low) {
move[0] = i;
move[1] = j;
return move;
} // end if
} // end inner for
} // end outer for
return move;
} // end method bestMove
I think that placeQueen is somehow being called before backtrack within the backtrack method.
P.S. This is not the same question as https://stackoverflow.com/questions/20111154/use-elimination-heuristic-to-solve-eight-queens-puzzle. There I was asking what I needed to do; here I am asking why my method did not work.
There is btw. a simpler way to solve the queens problem.
This program will print out all 92 solutions.
public class Queens {
static int counter = 0;
static int[] pos = new int[8];
static void printBoard(){
for(int p: pos) {
for(int i = 0; i < p; i++) System.out.print(".");
System.out.print("Q");
for(int i = p+1; i < 8; i++) System.out.print(".");
System.out.println();
}
System.out.println();
}
static boolean threatened(int x, int y){
for (int i = 0; i < y; i++){
int d = y - i;
if(pos[i] == x || pos[i] == x - d || pos[i] == x + d) {
return true;
}
}
return false;
}
static void place(int y) {
for(int x = 0; x < pos.length ; x++){
if(!threatened(x, y)){
pos[y] = x;
if(y == 7){
printBoard();
counter++;
} else{
place(y + 1);
}
}
}
}
public static void main(String[] args){
place(0);
System.out.print("found " + counter + " solutions");
}
}

Categories

Resources