5

I've asked earlier a question about solving the eight queens problem using Java. I got a backtracking algorithm to solve the problem.

I tried to use this algorithm but I don't know what's wrong with my code. It places up to 7 queens only.

Here's Queen Class:

    public class Queen {
    //Number of rows or columns
    public static final int BOARD_SIZE = 8;

    boolean[][] board;
    //Indicate an empty square
    public static final boolean EMPTY = false;
    //Indicate a square which containing a queen
    public static final boolean QUEEN = true;
    //Number of moves
    public static final int MOVES = 4;
    //Horizontal moves
    int[] horizontal;
    //Vertical moves
    int[] vertical;

    public int queens = 0;

    public Queen() {
        //Constructor creates an empty board
        board = new boolean[BOARD_SIZE][BOARD_SIZE];
        for (int row = 0; row < board.length; row++) {
            for (int col = 0; col < board[row].length; col++) {
                board[row][col] = EMPTY;
            }
        }

        horizontal = new int[MOVES];
        vertical = new int[MOVES];
        // up right
        horizontal[0] = -1;
        vertical[0] = 1; 
        // down left
        horizontal[1] = 1;
        vertical[1] = -1;
        // up left
        horizontal[2] = -1;
        vertical[2] = -1;
        // down right
        horizontal[3] = 1;
        vertical[3] = 1;
    }

    public boolean placeQueens (int column) {
        if (column > BOARD_SIZE) {
            return true;
        }
        else {
            boolean queenPlaced = false;
            int row = 1;

            while (!queenPlaced && row < BOARD_SIZE) {
                if (isUnderAttack(row, column)) {
                    ++row;
                }// end if
                else{
                    setQueen(row, column);
                    queenPlaced = placeQueens(column + 1);
                    if (!queenPlaced) {
                        removeQueen(row,column);
                        ++row;
                    }// end if
                }// end else
            }// end while
            return queenPlaced;
        }// end else
    }

    private void removeQueen(int row, int column) {
        board[row][column] = EMPTY;
        System.out.printf("queen REMOVED from [%d][%d]\n", row, column);
    --queens;
    }

    private void setQueen(int row, int column) {
        board[row][column] = QUEEN;
        System.out.printf("queen PLACED in [%d][%d]\n", row, column);
        ++queens;
    }

    public boolean isUnderAttack(int row, int col) {
        boolean condition = false;
        // check row
        for (int column = 0; column < BOARD_SIZE; column++) {
            if ((board[row][column] == true)) {
                condition = true;
            }
        }

        // check column
        for (int row_ = 0; row_ < board.length; row_++) {
            if (board[row_][col] == true) {
                        condition = true;
            }
        }

        // check diagonal
        for (int row_ = row, col_ = col; row_ >= 0 && col_ < 8; row_ += horizontal[0], col_ += vertical[0]) {
            if (board[row_][col_] == true) {
                condition = true;
            }
        }
        for (int row_ = row, col_ = col; row_ < 8 && col_ >= 0; row_ += horizontal[1], col_ += vertical[1]) {
            if (board[row_][col_] == true) {
                condition = true;
            }
        }
        for (int row_ = row, col_ = col; row_ >= 0 && col_ >= 0; row_ += horizontal[2], col_ += vertical[2]) {
            if (board[row_][col_] == true) {
                condition = true;
            }
        }
        for (int row_ = row, col_ = col; row_ < 8 && col_ < 8; row_ += horizontal[3], col_ += vertical[3]) {
            if (board[row_][col_] == true) {
                condition = true;
            }
        }

        return condition;
    }

    public void displayBoard () {
        int counter = 0;
        for (int row = 0; row < board.length; row++) {
            for (int col = 0; col < board[row].length; col++) {
                if (board[row][col] == true) {
                    System.out.printf("|%s|", "x");
                    counter++;
                }
                else {              
                    System.out.printf("|%s|", "o");
                }
            }
            System.out.println();
        }

        System.out.printf("%d queens has been placed\n", counter);
    }
}
Trinimon
  • 13,839
  • 9
  • 44
  • 60
kzidane
  • 753
  • 3
  • 11
  • 29
  • I've just created my efficient back-tracking solution in Python [here](https://stackoverflow.com/a/64114022/941531), in dozens of seconds it finds all solutions for 1-8 queens and in few minutes for 9 queens.. – Arty Sep 29 '20 at 06:53

3 Answers3

5

In Java arrays are 0-indexed, meaning that the first item is at index 0. You seem to have not entirely grasped this crucial fact, which has resulted in you writing code with many off-by-one errors.

One problem is here:

int row = 1;

It should be:

int row = 0;

A second problem is here:

if (column > BOARD_SIZE) {
    return true;
}

It should be this:

if (column >= BOARD_SIZE) {
    return true;
}

You haven't posted the rest of your code, but I'm willing to bet that there is a third error in your code when you call the placeQueens method. If I know what sort of person you are, then you probably did this:

queen.placeQueens(1);

But it should be this:

queen.placeQueens(0);

With all these changes it works as expected. The final result is:

|x||o||o||o||o||o||o||o|
|o||o||o||o||o||o||x||o|
|o||o||o||o||x||o||o||o|
|o||o||o||o||o||o||o||x|
|o||x||o||o||o||o||o||o|
|o||o||o||x||o||o||o||o|
|o||o||o||o||o||x||o||o|
|o||o||x||o||o||o||o||o|
8 queens has been placed

See it working online: ideone

Mark Byers
  • 811,555
  • 193
  • 1,581
  • 1,452
  • 3
    Well you were nearly there. You got the recursive algorithm correct, which is the hardest part of this problem. You just need to remember to use 0-indexing. – Mark Byers Nov 15 '12 at 14:20
0

There are some hardcodes in the method isUnderAttack :

// check diagonal the place the usage of 8 with the BOARD_SIZE

use:

col_ < BOARD_SIZE   

instead of

col_ < 8

and it could be better to make the BOARD_SIZE not static but make it as an input parameter, to make the code as more generic and do test for the boardSize = 4 or 12

-1

I wrote a generic code, which is working for any count of Queens.

The result is represented in 0 or 1. The 1 is a Queen, 0 - is empty square.

static int[][] setupEightQueens(int queensNum) {
    if (queensNum <= 0)
        return new int[][] { {} };
    int[][] chessField = new int[queensNum][queensNum];
    int n = chessField.length;
    int startJ = 0;
    for (int i = 0; i < n; i++) {
        for (int j = startJ; j < n; j += 2) {
            chessField[j][i] = 1;
            i++;
        }
        i--;
        startJ++;
    }
    return chessField;
}

output for the tested 4, 8, 11 count of queens:

__________________________
queens: 4
1 0 0 0
0 0 1 0
0 1 0 0
0 0 0 1
__________________________
queens: 8
1 0 0 0 0 0 0 0
0 0 0 0 1 0 0 0
0 1 0 0 0 0 0 0
0 0 0 0 0 1 0 0
0 0 1 0 0 0 0 0
0 0 0 0 0 0 1 0
0 0 0 1 0 0 0 0
0 0 0 0 0 0 0 1
__________________________
queens: 11
1 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 1 0 0 0 0
0 1 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 1 0 0 0
0 0 1 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 1 0 0
0 0 0 1 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 1 0
0 0 0 0 1 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 1
0 0 0 0 0 1 0 0 0 0 0


Community
  • 1
  • 1
  • `if (queensNum <= 0)` That doesn't look like valid syntax. – CertainPerformance Jul 15 '18 at 04:32
  • I've corrected it. The resut for test with n=4 is not corret. That's why we need to add a function to check the possible crossing with other Queen. – Arman Melkumyan Jul 16 '18 at 01:18
  • Still doesn't look correct - see your code in your answer, it says `if (queensNum <= 0)` – CertainPerformance Jul 16 '18 at 01:24
  • Please check again. – Arman Melkumyan Jul 16 '18 at 01:43
  • 1
    Your result for 4 queens is also obviously incorrect. – Turksarama Jul 16 '18 at 01:46
  • 1
    I see that the result 4 is not correct. I need to use a function go back and re-place the queens in new position. But algorithms main goal is to reduce the steps on traversing the items of the array of columns and rows by jumping to ntext.next element like this j += 2 and immediately do i++ to go to the next row, and when you use a startJ - it's a start possible place for queen. This way is reducing the steps of traversing. but you need to check the isUnderAttack. -if true. then reset and start from lastStartColumnInInxed and row = 0; – Arman Melkumyan Jul 16 '18 at 01:54