My question is boolean isLive = false; why is this assigned as false? I have seen very similer examples but I never quet understand it. could anyone explain what this line is doing?
/**
* Method that counts the number of live cells around a specified cell
* #param board 2D array of booleans representing the live and dead cells
* #param row The specific row of the cell in question
* #param col The specific col of the cell in question
* #returns The number of live cells around the cell in question
*/
public static int countNeighbours(boolean[][] board, int row, int col)
{
int count = 0;
for (int i = row-1; i <= row+1; i++) {
for (int j = col-1; j <= col+1; j++) {
// Check all cells around (not including) row and col
if (i != row || j != col) {
if (checkIfLive(board, i, j) == LIVE) {
count++;
}
}
}
}
return count;
}
/**
* Returns if a given cell is live or dead and checks whether it is on the board
*
* #param board 2D array of booleans representing the live and dead cells
* #param row The specific row of the cell in question
* #param col The specific col of the cell in question
*
* #returns Returns true if the specified cell is true and on the board, otherwise false
*/
private static boolean checkIfLive (boolean[][] board, int row, int col) {
boolean isLive = false;
int lastRow = board.length-1;
int lastCol = board[0].length-1;
if ((row >= 0 && row <= lastRow) && (col >= 0 && col <= lastCol)) {
isLive = board[row][col];
}
return isLive;
}
That's simply the default value, which may be changed if the test (if clause) is verified.
It defines the convention that cells outside the board aren't live.
This could have been written as :
private static boolean checkIfLive (boolean[][] board, int row, int col) {
int lastRow = board.length-1;
int lastCol = board[0].length-1;
if ((row >= 0 && row <= lastRow) && (col >= 0 && col <= lastCol)) {
return board[row][col];
} else {
return false;
}
}
First we assign boolean value as 'false' (ensuring default condition)
Then if valid condition is found we change the value, else default false will be returned.
boolean isLive = false;
It is a default value assigned to the boolean variable.
Just like:
int num = 0;
boolean isLive = false;
This is the default value of a boolean variable. If you declare as an instance variable it is automatically initialized to false.
why is this assigned as false?
Well, we do this, just to start with a default value, then we can change later on to true value, based on certain condition.
if ((row >= 0 && row <= lastRow) && (col >= 0 && col <= lastCol)) {
isLive = board[row][col];
}
return isLive;
So, in above code, if your if condition is false, then it is similar to returning a false value. Because, the variable isLive is not changed.
But if your condition is true, then the return value will depend upon the value of board[row][col]. If it is false, return value will still be false, else true.
Related
Within a game on Gomoku a player has to get 5 in a row to win. Detecting diagonal win is a problem.
I have tried the code below which searches a 2d matrix from top right until it finds a player token we are looking for e.g. 1, it then proceeds to search from that point diagonally to find a winning row. This works fine providing the first '1' the algorithm comes across is a part of the winning line. If it is not, and just a random piece, the algorithm returns false as it does not continue searching.
How would Itake the last played move of the game and only search the diagonals relating to that move? Or possibly edit provided code to search the whole board.
public boolean is_diagonal_win_left(int player) {
int i = 0;
for (int col = board_size-1; col > (win_length - 2); col--) {
for (int row = 0; row < board_size-(win_length-1); row++) {
while (board_matrix[row][col] == player) {
i++;
row++;
col--;
if (i == win_length) return true;
}
i = 0;
}
}
return false;
}
//solved
public boolean is_diagonal_win_right(int player, int r, int c) {
int count = 0;
int row = r;
int col = c;
while ((row != 0) && (col != 0)) {
row--;
col--;
}
while ((row <= board_size - 1) && (col <= board_size - 1)) {
if (board_matrix[row][col] == player) count++;
row++;
col++;
}
return count == win_length;
}
You are correct: searching the board for the first counter is invalid; searching the entire board is a waste of time. Start at the most recent move. Let's call that position (r, c); the player's token is still player. Check in each of the eight functional directions to see how long is the string of player. For instance, you check the NW-SE diagonal like this:
count = 1 // We just placed one counter
row = r-1; col = c-1
while ( (row >= 0) and (col >= 0) and
(board_matrix[row][col] == player) )
count += 1
row = r+1; col = c+1
while ( (row < board_size) and (col < board_size) and
(board_matrix[row][col] == player) )
count += 1
// Note: gomoku rules require exactly 5 in a row;
// if you're playing with a"at least 5", then adjust this to >=
if (count == win_length) {
// Process the win
}
I'm working on a Connect Four game for the console in Java. I have problems with the winning conditions, as I don't know how to program them. Here is my code my Main:
public class Main {
public static char[] playerNumber = new char[]{'1', '2'};
public static char[] Badge = new char[]{'X', 'O'};
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int moves = 7 * 6;
int whichPlayer = 0;
for (int i = 0; i < 10; i++) {
System.out.println(" FOUR IN A ROW");
System.out.println("-------------------------------------------------------");
System.out.println("Welcome to the amazing game Four In A Row:");
System.out.println("Enter a number between 0 and 6 for choosing a column.");
System.out.println();
Board board = new Board();
board.fillBoard();
board.presentBoard();
do {
// 1. get a badge
char Player = playerNumber[whichPlayer];
char badge = Badge[whichPlayer];
// 2. make a turn
board.makeTurn(badge, Player);
board.presentBoard();
// 3. Tjek om der er vinder
if (board.checkWinHorizontal() || board.checkWinVertical()) {
System.out.println("Player " + Player + " has won!");
break;
}
// 4. change the player
whichPlayer = 1 - whichPlayer;
// 5. decrease moves
--moves;
if (moves == 0) {
System.out.println("Game over, nobody has won.");
System.out.println("Do you want to play again? 'Y' or 'N':");
String newGame = scanner.nextLine();
if (newGame.equals("Y") || newGame.equals("y")) {
break;
}
if (newGame.equals("N") || newGame.equals("n")) {
System.out.println("Thanks for the game!");
return;
}
}
// 6. repeat
} while (true);
}
}
And here is my code for my Board class:
public class Board {
char[][] board = new char[6][7];
int column;
// Fills the empty spaces
public void fillBoard() {
for (int i = 0; i < 6; i++) {
for (int j = 0; j < 7; j++) {
board[i][j] = ' ';
}
}
}
// Prints the board
public void presentBoard() {
for (int i = 0; i < 6; i++) {
System.out.print(" | ");
for (int j = 0; j < 7; j++) {
System.out.print(board[i][j] + " | ");
}
System.out.println();
System.out.print(" -----------------------------");
System.out.println();
}
}
// Turn
public void makeTurn(char badge, char Player) {
Scanner scanner = new Scanner(System.in);
do {
// 1. Ask for a column
System.out.println("Player " + Player + " turn: ");
column = scanner.nextInt();
// 2. Check if it's between 0 and 6
if (column > 6) {
System.out.println("That is not a valid number. Please enter a number between 0 and 6: ");
continue;
}
// 3. Place a badge
for (int i = 6 - 1; i >= 0; i--) {
if (board[i][column] == ' ') {
board[i][column] = badge;
return;
}
}
// If column is full
System.out.println("Column " + column + " is full. Try another column:");
} while (true);
}
// Check for vertical win
public boolean checkWinVertical() {
return verticalWin(5, column);
}
// Check for horizontal win
public boolean checkWinHorizontal() {
return horizontalWin(5,column);
}
// Conditions for vertical win
private boolean verticalWin(int x, int y) {
char charToCheck = board[x][y];
if (board[x-1][y] == charToCheck &&
board[x-2][y] == charToCheck &&
board[x-3][y] == charToCheck) {
return true;
}
return false;
}
// Conditions for horizontal win
private boolean horizontalWin(int x, int y) {
char charToCheck = board[x][y];
if (board[x][y+1] == charToCheck &&
board[x][y+2] == charToCheck &&
board[x][y+3] == charToCheck) {
return true;
}
return false;
}
I have succeeded in getting the game recognize a win horizontally and vertically at the bottom row of my array, but I don't know how to make the game recognize for the whole array. I'm only concentrating about the horizontal and vertical, as the diagonal is too complicated for me. And I don't know if this is the right approach or there is a better one.
Thanks!
Here's another solution. It's the same general idea as previously mentioned: loop through each row/column, checking for a streak of 4 in a row. Maybe this implementation will provide some other insight. Below, I've shown an example method checking the horizontal streaks. For vertical, you would iterate over the rows in the inner for loop instead.
public boolean checkWin(char badge) {
return checkHorizontalStreaks(board, badge)
|| checkVerticalStreaks(board, badge);
}
private boolean checkHorizontalStreaks(char[][] board, char badge) {
for (int row = 0; row < board.length; row++) {
// loop throught each row
int currentStreak = 0;
for (int col = 0; col < board[row].length; col++) {
// loop through each column in the row
if (board[row][col] == badge) {
// keep the streak of 'badge' going
currentStreak++;
if (currentStreak == 4) {
// winner
return true;
}
} else {
// restart the streak
currentStreak = 0;
}
}
}
return false;
}
And then update your Main class with
if (board.checkWin(badge)) {
System.out.println("Player " + Player + " has won!");
break;
}
I'd wager there is a more efficient way to determine a winner (perhaps by treating the grid as a graph and traversing it with some special logic). However, I suspect this may be enough for what you need. I'll spare you the output, but it worked with a few different test cases.
Possibly you could check all the adjacent fields around the last played field, so after the user did his turn. So for checking upwards you could do this:
public boolean checkUp(int rowPlayed, int columnPlayed){
boolean checked = false;
if(rowplayed + 1 <= maxrows){ //Checks if you didn't hit the top
if(board[rowPlayed+1][columnPlayed] != null){
if(board[rowPlayed+1][columnPlayed].getPlayer() == currentPlayer){
checked = true;
}
}
}
return checked;
}
and for example implemented like this:
public void checkWin(int rowPlayed, int columnPlayed){
boolean checkingWin = true;
int countWin = 0;
while(checkingWin){
if(checkUp(rowPlayed + countWin, columnPlayed)){
countWin++;
}
else{
checkingWin = false;
}
if(countWin == 4){
checkinWin = false;
//Insert win confirmation here
}
}
}
It's partially pseudo code because I don't know exactly how you handle things in your code, nor do I know if this is the best way to do it. But I hope it was of help for you.
This is a long answer and I'll go around the houses a bit so you can see how I reached my solution (which also expands to diagonal checking at the end).
I would use the last piece added as a starting point and work from there since checking all combinations is exhaustive and unnecessary.
Given the row and column of the last piece added I need to decide what I need to achieve.
I already know that the current row and column has the piece of the colour I'm looking for so I can ignore that.
For horizontal matching, I want to check I want to checking pieces to left and right in the same row have the same colour, and stop if the colour is different or there is no piece.
So imagine the following board (# = empty, R = Red piece, Y = Yellow piece:
6 # # # # # # # #
5 # # # # # # # #
4 # # # # # # # #
3 # # # # # # # #
2 # # # # # # # #
1 # # # # # # # #
0 Y R R R Y Y Y R
0 1 2 3 4 5 6 7
The last move was Yellow, row 0, col 4.
So I want to check left and right from [0][4] and see if the total number of consecutive pieces of the colour is 3, (not 4) since I know [0][4] is Yellow and can be discounted.
Based on this I can take a recursive approach where I check the adjacent to one side, then recursively do the same thing as long as I keep matching pieces of the same colour or do not encounter an empty slot.
I'll start of with a check to the right (to demonstrate):
private static final int COLS = 7;
private static final int ROWS = 6;
public enum Piece {RED, YELLOW}; // null is empty
private Piece[][] board = new Piece[ROWS][COLS]; // the board
private int checkRight(Piece piece, int row, int col) {
// assume valid row for now
col++; // moving col to the right
if (col >= COLS || board[row][col] != piece) {
// We're outside the limits of the column or the Piece doesn't match
return 0; // So return 0, nothing to add
} else {
// otherwise return 1 + the result of checkRight for the next col
return 1 + checkRight(piece, row, col);
}
}
Now I can perform the same to the left.
private int checkLeft(Piece piece, int row, int col) {
// assume valid row for now
col--; // moving col to the left
if (col < 0 || board[row][col] != piece) {
// We're outside the limits of the column or the Piece doesn't match
return 0; // So return 0, nothing to add
} else {
// otherwise return 1 + the result of checkLeft for the next col
return 1 + checkLeft(piece, row, col);
}
}
And to check a winner for horizontal, I could do this:
public boolean checkWinner(Piece piece, int row, int col) {
// if the sum is 3, we have a winner (horizontal only).
return checkRight(piece, row, col) + checkLeft(piece, row, col) == 3;
}
Ugh, there's a lot of repetition isn't there?
We can condense the two methods into one by introducing a new parameter direction which can change if we move col positive or negative through the values 1 and -1 respectively:
private int check(Piece piece, int row, int col, int direction) {
col += direction; // direction is either 1 (right) or -1 (left)
if (col < 0 || col >= COLS || board[row][col] != piece) {
return 0;
} else {
return 1 + check(piece, row, col);
}
}
Update checkWinner() for this new parameter:
private static final int POSITIVE = 1; // right at the moment
private static final int NEGATIVE = -1; // left at the moment
public boolean checkWinner(Piece piece, int row, int col) {
// if the sum is 3, we have a winner (horizontal only).
return check(piece, row, col, POSITIVE) + check(piece, row, col, NEGATIVE) == 3;
}
Now I could implement the same sort of logic for vertical, but instead stay on the same col and change the row. I will skip this part in detail and move onto a solution which includes this and diagonal checking.
This has been done using an enum called CheckType storing values for which row and col should change and is used by the check() method. e.g. for HORIZONTAL the column changes by 1 or -1 (depending upon the direction specified when check() is called) and the row remains 0.
public class Board {
public enum Piece {
RED, YELLOW
};
private enum CheckType {
HORIZONTAL(0, 1), VERTICAL(1, 0), DIAGNONAL_UP(1, 1), DIAGNONAL_DOWN(-1, 1);
int row;
int col;
CheckType(int row, int col) {
this.row = row;
this.col = col;
}
}
private static final int POSITIVE = 1;
private static final int NEGATIVE = -1;
private static final int ROWS = 6;
private static final int COLS = 7;
private Piece[][] board = new Piece[ROWS][COLS];
private boolean hasWinner = false;
public boolean hasWinner() {
return hasWinner;
}
private void checkWinner(Piece piece, int row, int col) {
// check all values of enum CheckType for a winner
// so HORIZONTAL, VERTICAL, etc..
int enumIndex = 0;
while (!hasWinner && enumIndex < CheckType.values().length) {
hasWinner = check(piece, row, col, POSITIVE, CheckType.values()[enumIndex])
+ check(piece, row, col, NEGATIVE, CheckType.values()[enumIndex]) == 3;
enumIndex++;
}
}
private int check(Piece piece, int row, int col, int direction, CheckType type) {
row += type.row * direction;
col += type.col * direction;
if (row >= ROWS || row < 0 || col >= COLS || col < 0 || board[row][col] != piece) {
return 0;
} else {
return 1 + check(piece, row, col, direction, type);
}
}
// for completeness, adding a Piece
public boolean add(Piece piece, int col) {
int row = 0;
while (row < ROWS && board[row][col] != null) {
row++;
}
if (row < ROWS) {
board[row][col] = piece;
// check for winner after successful add
checkWinner(piece, row, col);
}
return row < ROWS;
}
}
Hope this helps.
For a school project I have to complete a Conways game of life with recourse to some provided skeleton code.
My problem is that all of my cells seem to initialise as dead (and thus do not come alive) when I use the visualiser - I'm not looking for direct answer on the whole project, just some direction on where my code is broken (Apologise for the awful formatting, its my first time on here):
Below is the Cell.class and below that is the CellGrid - the visualiser was provided.
package simulation;
/**
* This class represents a single Cell in the grid.
*
* Complete this class as part of the core of the assessment.
* You must implement the constructor, isAlive, setAlive and isAliveNextStep.
*/
public class Cell
{
// true if the cell is alive and false if it is dead
private boolean alive;
/**
* Cell constructor - all cells should start out dead
*/
public Cell()
{
alive = false;
}
/**
* Accessor method for alive
*
* #return true if the cell is currently alive; false otherwise
*/
public boolean isAlive()
{
if (alive == true)
{
return true;
}
else
return false;
}
/**
* Mutator method for alive
*
* #param alive - the new state of the cell
*/
public void setAlive(boolean alive)
{
if (alive == true)
alive = false;
else alive = true;
}
/**
* Determine whether this cell should be alive in the next step,
* given the number of surrounding neighbours.
*
* See the assignment specification sheet to determine the rules
* for living and dead cells.
*
* #param numNeighbours - the number of living cells surrounding this cell
* #return true if the cell should be alive; false otherwise
*/
public boolean isAliveNextStep(int numNeighbours)
{
if (numNeighbours <= 2)
return false;
if (numNeighbours == 3)
return true;
if (numNeighbours == 4 && alive == true)
return true;
if (numNeighbours == 5)
return false;
if (numNeighbours > 5)
return true;
else return false;
}
}
CellGrid class:
package simulation;
/**
* This class represents an n x n grid of Cells.
*
* Complete this class as part of the core of the assessment.
* You must implement the constructor, simulateStep, isValidCoordinate,
* countNeighbours, getCell and setCell.
*/
public class CellGrid
{
// Store the cells of the game in this 2D array
private Cell[][] cells;
/**
* Constructor for a CellGrid. Populates the grid with cells that will be
* either living or dead. Consider using Math.random() in order to generate
* random numbers between 0.0 and 1.0, in conjunction with lifeChance.
*
* #param size - the size of the grid will be size x size
* #param lifeChance - the probability of each cell starting out
* alive (0.0 = 0%, 1.0 = 100%)
*/
public CellGrid(int size, double lifeChance)
{
cells = new Cell[size][size];
for (int i = 0; i < size; i++)
{
for (int j = 0; j < size; j++)
{
cells[i][j] = new Cell();
if (Math.random() < lifeChance);
{
cells[i][j].setAlive(false);
}
}
}
}
/**
* Run one step in the simulation. This has 2 stages in the following order:
*
* 1. (Core) Update all cells in the grid according to the rules given in the
* assignment specification sheet.
*
* 2. (Extension) Evolve the cells by calculating their new genes - also
* see the assignment specification sheet.
*/
public void simulateStep()
{
for (int i = 0; i < cells.length; i++)
{
for (int j = 0; j < cells.length; j++)
{
int Neighbours = countNeighbours(i, j);
cells[i][j].isAliveNextStep(Neighbours);
}
}
}
/**
* Check if the given coordinates are inside the grid of cells.
*
* #param x - the x coordinate (column) of the cell
* #param y - the y coordinate (row) of the cell
* #return true if the given coordinates are inside the grid of cells; false
* otherwise.
*/
public boolean isValidCoordinate(int x, int y)
{
int validc = 0; //*variable to check for validity of coordinate by traversal *//
for (int i = 0; i < cells.length; i++)
{
for (int j = 0; j > cells.length; j++)
{
if (x == i+1 && y == j+1)
{
validc = 1;
}
}
}
if (validc == 1)
{
return true;
}
else return false;
}
/**
* Count the number of living neighbours in the 8 cells surrounding the
* given coordinates.
*
* #param x - the x coordinate (column) of the cell
* #param y - the y coordinate (row) of the cell
* #return the number of living neighbours of the cell at the given
* coordinates; or 0 if the coordinates are invalid.
*/
public int countNeighbours(int x, int y)
{
int N = 0;
for (int i = 0; i < cells.length; i++)
{
for (int j = 0; j > cells.length; j++)
{
if (i-1 >= 0 && j-1 >= 0 && cells[i-1][j-1].equals(true))
N++;
if (i-1 >= 0 && cells[i-1][j].equals(true))
N++;
if (i-1 >= 0 && j+1 <= cells.length && cells[i-1][j+1].equals(true))
N++;
if (i >= 0 && j-1 >=0 && cells[i][j-1].equals(true))
N++;
if (i >= 0 && j >= 0 && cells[i][j].equals(true))
N++;
if (i >= 0 && j+1 <= cells.length && cells[i][j+1].equals(true))
N++;
if (i+1 <= cells.length && j-1 >= 0 && cells[i+1][j-1].equals(true))
N++;
if (i+1 <= cells.length && j >= 0 && cells[i+1][j].equals(true))
N++;
if (i+1 <= cells.length && j+1 <= cells.length && cells[i+1][j+1].equals(true))
N++;
}
}
return N;
}
/**
* Get the cell at the given coordinates.
*
* #param x - the x coordinate (column) of the cell
* #param y - the y coordinate (row) of the cell
* #return the cell at the given coordinates; or null if the coordinates are
* invalid
*/
public Cell getCell(int x, int y)
{
if (x < cells.length && y < cells.length)
return cells[x][y];
else return null;
}
/**
* Set the cell at the given coordinates to the cell provided, if the
* coordinates are valid.
*
* #param x - the x coordinate (column) of the cell
* #param y - the y coordinate (row) of the cell
* #param cell - the new cell to put at the coordinates given.
*/
public void setCell(int x, int y, Cell cell)
{
cells[x][y] = getCell(x,y);
}
}
Your setAlive method is incorrect.
public void setAlive(boolean alive){
if (alive == true)
alive = false;
else alive = true;
}
Due to variable shadowing, you never really change the field alive. It should look like this:
public void setAlive(boolean alive){
this.alive = alive;
}
I have attempted to complete my homework project and am seeking help finding a bug. I am using a backtracking algorithm to find all the solutions to an N-queens problem. My main concern is my conflict method-which is inside a stack class. Its purpose is to detect if the Queen object (parameter 1 of conflict method) being passed is in the same row, column, or diagonal as any other queens on the board. The queen object passed into the conflict method is stored inside the Queen class and its location is recorded with the help of an instance of the Point class. My code uses two methods in the Queen class that I created, public int getRow(), and public int getColumn(). Both return an int. Second parameter is a 2d array (or array of arrays) named board. Queens already on the board are denoted in this array with a boolean value of true. Boolean values of false indicate an empty square on the board.
Solution.n is a reference to a static int variable in another class. Its value denotes the edge of the board. Example...for the 8-Queens problem we create a 2d array with size 8. Solution.n is decremented by 1 to equal the last index of the 2d array.
Here is the code:
public boolean conflict(Queen x, boolean [][] board) //conflict method
{
if(checkColumn(x, board) == false)
return true; //conflict
else if(checkRow(x, board) == false)
return true; //conflict
else if(checkDiagonal(x, board) == false )
return true; //conflict
else
return false; //no conflict on board
}
private boolean checkColumn(Queen x, boolean [][] board)//returns true when column is safe
{
int col = x.getColumn();
for(int row = 0; row <= Solution.n; row++)
{
if(board[row][col] == true) //queen is in this column
{
return false;
}
}
return true;
}
private boolean checkRow(Queen x, boolean [][] board) //returns true when row is safe
{
int row = x.getRow();
for(int col = 0; col <= Solution.n; col++)
{
if(board[row][col] == true) //queen is in this row
{
return false;
}
}
return true;
}
private boolean checkDiagonal(Queen location, boolean [][] board) //returns true when diagonal is safe
{
int row, col;
row = location.getRow() - 1;
col = location.getColumn() - 1;
while(row >=0 && col >= 0) //iterate down-left
{
if(board[row][col] == true) //queen found?
{
return false;
}
row--;
col--;
}
row = location.getRow() - 1;
col = location.getColumn() + 1;
while(row != -1 && col <= Solution.n) //iterate down-right
{
if(board[row][col] == true) //queen found?
{
return false;
}
row--;
col++;
}
row = location.getRow() + 1;
col = location.getColumn() + 1;
while(row <= Solution.n && col <= Solution.n) //iterate up-right
{
if(board[row][col] == true) //queen found?
{
return false;
}
row++;
col++;
}
row = location.getRow() +1;
col = location.getColumn()-1;
while(row <= Solution.n && col != -1) //iterate up-left
{
if(board[row][col] == true) //queen found?
{
return false;
}
row++;
col--;
}
return true;
}
I am convinced this snippet of code contains a bug, but if i'm wrong then I apologize for wasting your time :P
Your help would be greatly appreciated. Thanks! :D
You have several small bugs in there - for example, you have loops that go from 0 to Solution.n, inclusive, while they should go to Solution.n-1. Most of the errors, however, can be eliminated by picking a more suitable data structure.
Think about it: you don't need a full NxN board to decide the placement of a queen:
There's one queen per row, so queen's number is its row.
There's one queen per column, so you need an array of boolean[N] to know which rows are taken.
There's one queen per ascending diagonal, so you need an array of boolean[2N-1] to know which ascending diagonals are taken.
There's one queen per descending diagonal, so you need an array of boolean[2N-1] to know which descending diagonals are taken.
boolean[] columns = new boolean[N];
boolean[] ascending = new boolean[2*N-1];
boolean[] descending = new boolean[2*N-1];
At this point you've got all you need: instead of a square boolean[N][N] array you need three linear arrays of boolean. This lets you do your checks much faster, too:
int c = x.getColumn();
int r = x.getRow();
boolean conflict = columns[c]
|| ascending[r+c]
|| descending[N-r+c];
That's it - no loops required! Now you can code your backtracking algorithm using these three arrays instead of a square board.
This answer won't solve your problem, since I'm not convinced your error is in the code you pasted, but here's your code, written a bit closer to how I might write it:
// returns true when column is safe
private boolean checkColumn(Queen x, boolean [][] board)
{
int col = x.getColumn();
for(int row = 0; row <= Solution.n; row++)
{
if(board[row][col]){ return false; }
}
return true;
}
// returns true when row is safe
private boolean checkRow(Queen x, boolean [][] board)
{
int row = x.getRow();
for(int col = 0; col <= Solution.n; col++)
{
if(board[row][col]){ return false; }
}
return true;
}
// returns true if the position is valid given the board size
// (as defined by Solution)
private boolean validPosition(int row, int col)
{
if(0 > row || row > Solution.n){ return false; }
if(0 > col || col > Solution.n){ return false; }
return true;
}
// returns true when diagonal is safe
private boolean checkDiagonal(Queen x, boolean [][] board)
{
int row, col;
// Down Left
row = x.getRow(); // "Start" on current position
col = x.getColumn();
while(true)
{
row--; col--; // Take a step in the direction
if(!validPosition(row, col)){ break; } // Stop if we've left the board
if(board[row][col]){ return false; } // Check whether it's occupied
}
// Down Right
row = x.getRow();
col = x.getColumn();
while(true)
{
row--; col++;
if(!validPosition(row, col)){ break; }
if(board[row][col]){ return false; }
}
// Up Right
row = x.getRow();
col = x.getColumn();
while(true)
{
row++; col++;
if(!validPosition(row, col)){ break; }
if(board[row][col]){ return false; }
}
// Up Left
row = x.getRow();
col = x.getColumn();
while(true)
{
row++; col--;
if(!validPosition(row, col)){ break; }
if(board[row][col]){ return false; }
}
return true;
}
public boolean conflict(Queen x, boolean [][] board) //conflict method
{
if ( checkColumn(x, board) == false){ return true; }
else if( checkRow(x, board) == false){ return true; }
else if(checkDiagonal(x, board) == false){ return true; }
else { return false; }
}
}
It simplifies a lot of the logic, adds a helper function validPosition(), and cleans up some of the tests and loops.
Im trying to make a program to solve the eight Queens problem but i keep getting and exception error every time i run the code this is what i have. im a little confused on what to do. any help to the direction will be greatly appreciated.
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException:-1 at
Queens.isUnderAttack(Queens.java:132) at
Queens.placeQueens(Queens.java:78) at
Queens.main(Queens.java:155)
public class Queens
{
//squares per row or column
public static final int BOARD_SIZE = 8;
//used to indicate an empty square
public static final int EMPTY = 0;
//used to indicate square contains a queen
public static final int QUEEN = 1;
private int board[][]; //chess board
public Queens()
{
//constructor: Creates an empty square board.
board = new int[BOARD_SIZE][BOARD_SIZE];
}
//clears the board
//Precondition: None
//Postcondition: Sets all squares to EMPTY
public void clearBoard()
{
//loops through the rows
for(int row = 0; row < BOARD_SIZE; row++)
{
//loops through the columns
for (int column = 0; column < BOARD_SIZE; column++)
{
board[row][column] = EMPTY;
}
}
}
//Displays the board
//precondition: None
//postcondition: Board is written to standard output;
//zero is an EMPTY square, one is a square containing a queen (QUEEN).
public void displayBoard()
{
for (int row = 0; row < BOARD_SIZE; row++)
{
System.out.println("");
for (int column = 0; column < BOARD_SIZE; column++)
{
System.out.print(board[row][column] + " ");
}
}
}
//Places queens in columns of the board beginning at the column specified.
//Precondition: Queens are placed correctly in columns 1 through column-1.
//Postcondition: If a solution is found, each column of the board contains one queen and
//method returns true; otherwise, returns false (no solution exists for a queen anywhere in column specified).
public boolean placeQueens(int column)
{
if(column >= BOARD_SIZE)
{
return true; //base case
}
else
{
boolean queenPlaced = false;
int row = 1; // number of square in column
while( !queenPlaced && (row < BOARD_SIZE))
{
//if square can be attacked
**if (!isUnderAttack(row, column))**
{
setQueen(row, column); //consider next square in column
queenPlaced = placeQueens(column+1);
//if no queen is possible in next column,
if(!queenPlaced)
{
//backtrack: remover queen placed earlier
//and try next square in column
removeQueen(row, column);
//++row;
}
}
row++;
}
return queenPlaced;
}
}
//Sets a queen at square indicated by row and column
//Precondition: None
//Postcondition: Sets the square on the board in a given row and column to Queen.
private void setQueen(int row, int column)
{
board[row][column] = QUEEN;
}
//removes a queen at square indicated by row and column
//Precondition: None
//Postcondition: Sets the square on the board in a given row and column to EMPTY.
private void removeQueen(int row, int column)
{
board[row][column] = EMPTY;
}
//Determines whether the square on the board at a given row and column is
//under attack by any queens in the columns 1 through column-1.
//Precondition: Each column between 1 and column-1 has a queen paced in a square at
//a specific row. None of these queens can be attacked by any other queen.
//Postcondition: If the designated square is under attack, returns true: otherwise return false.
private boolean isUnderAttack(int row, int column)
{
for (int y=0; y<BOARD_SIZE; y++)
{
if (board[row][y] == QUEEN || // possible horizontal attack
board[row-column+y][y] == QUEEN || // diagonal NW
**board[row+column-y][y] == QUEEN) // diagonal SW**
return true;
}
return false;
}
private int index(int number)
{
//Returns the array index that corresponds to a row or column number.
//Precondition: 1 <= number <= BOARD_SIZE.
//Postcondition: Returns adjusted index value
return number -1 ;
}
//main to test program
public static void main(String[] args)
{
Queens Q = new Queens();
**if(Q.placeQueens(0))**
{
System.out.println(Q);
}
else
{
System.out.println("Not Possible");
}
}
}
private boolean isUnderAttack(int row, int column)
{
for (int y = 0; y < BOARD_SIZE; y++)
{
if (board[row][y] == QUEEN)
return true; // possible horizontal attack
int x1 = row - column + y;
if (0 <= x1 && x1 < BOARD_SIZE && board[x1][y] == QUEEN)
return true; // diagonal NW
int x2 = row + column - y;
if (0 <= x2 && x2 < BOARD_SIZE && board[x2][y] == QUEEN)
return true; // diagonal SW
}
return false;
}
In your loop in 'isUnderAttack()', this is not good:
board[row-column+y][y]
board[row+column-y][y]
As 'y' goes from '0' to 'board size', it will mean indexes out of the bounds of your array (unless row and column is both 0) - as the error message clearly stated.
The loop should be corrected with the appropriate indexes, or by adding conditions to check that the indexing is in bounds:
int rowIndex = row-column+y;
if(rowIndex>=0 && rowIndex<BOARD_SIZE) {
if(board[row-column+y][y] == QUEEN) {
return true;
}
}
And of course the same for the other diagonal...
Damn, it is slow to type code on an android phone, even with a qwerty...
The value of either of these is going below zero
row-column+y
row+column-y
One of the Scenarios which is causing the error
Consider this case,board[row+column-y][y] == QUEEN
assume row=1,column=0 and y is 4 ,the index become -ve which is causing the error