So I have this university assignment to solve Sudoku... I read about Algorithm X and Dancing algorithm, but they didn't help me.
I need to make it with backtracking. I hard-coded some of the indexes in the two dimensional array with numbers on places given from Wikipedia (so I am sure that it's solvable).
The code I got is the following:
public void solveSudoku(int row, int col)
{
// clears the temporary storage array that is use to check if there are
// dublicates on the row/col
for (int k = 0; k < 9; k++)
{
dublicates[k] = 0;
}
// checks if the index is free and changes the input number by looping
// until suitable
if (available(row, col))
{
for (int i = 1; i < 10; i++)
{
if (checkIfDublicates(i) == true)
{
board[row][col] = i;
if (row == 8)
solveSudoku(0, col + 1);
else if (col == 8)
solveSudoku(row + 1, 0);
else
solveSudoku(row, col + 1);
board[row][col] = 0;
}
}
}
// goes to the next row/col
else
{
if (row == 8)
solveSudoku(0, col + 1);
else if (col == 8)
solveSudoku(row + 1, 0);
else
solveSudoku(row, col + 1);
}
}
/**
* Checks if the spot on the certain row-col index is free of element
*
* #param row
* #param col
* #return
*/
private boolean available(int row, int col)
{
if (board[row][col] != 0)
return false;
else
return true;
}
/**
* Checks if the number given is not already used in this row/col
*
* #param numberToCheck
* #return
*/
private boolean checkIfDublicates(int numberToCheck)
{
boolean temp = true;
for (int i = 0; i < dublicates.length; i++)
{
if (numberToCheck == dublicates[i])
{
temp = false;
return false;
}
else if (dublicates[i] == 0)
{
dublicates[i] = numberToCheck;
temp = true;
return true;
}
}
return temp;
}
I am getting StackOverflow on
// goes to the next row/col
else
{
if (row == 8)
solveSudoku(0, col + 1);
else if (col == 8)
solveSudoku(row + 1, 0);
else
solveSudoku(row, col + 1);
}
which means that I have to stop the recursion at some point, but I can't figure it out how!
If you find any other mistakes in the solve() function - let me know. Because I am not sure I understand the "backtracking" thing completely...
You can stop recursion for example if you keep track of the current recursion depth
public void solveSudoku(int row, int col, int recursionDepth) {
// get out of here if too much
if (recursionDepth > 15) return;
// regular code...
// at some point call self with increased depth
solveSudoku(0, col + 1, recursionDepth + 1);
}
And if you find any other mistakes in the solve() function - let me know.
Too much code :)
This is roughly the way I've done this in the past.
Whenever all the definite moves have been taken and there is a choice of equally good next moves:
copy your grid data structure and push it onto a stack.
take the first candidate move and continue solving recursively
Whereever you get stuck:
pop the saved grid off the stack
take the next candidate move.
I made it in a more simple way:
public void solve(int row, int col)
{
if (row > 8)
{
printBoard();
System.out.println();
return;
}
if (board[row][col] != 0)
{
if (col < 8)
solve(row, col + 1);
else
solve(row + 1, 0);
}
else
{
for (int i = 0; i < 10; i++)
if (checkRow(row, i) && checkCol(col, i))
//&& checkSquare(row, col, i))
{
board[row][col] = i;
if (col < 8)
solve(row, col + 1);
else
solve(row + 1, 0);
}
board[row][col] = 0;
}
}
private boolean checkRow(int row, int numberToCheck)
{
for (int i = 0; i < 9; i++)
if (board[row][i] == numberToCheck)
return false;
return true;
}
private boolean checkCol(int col, int numberToCheck)
{
for (int i = 0; i < 9; i++)
if (board[i][col] == numberToCheck)
return false;
return true;
}
I'm not sure why you say that Dancing Links and Algorithm X were not useful.
Do you mean that you were not able to map Sudoku to an instance of the Exact Cover problem that Algorithm X is designed to solve?
Or that it is a too complicated approach for what you need??
If the former is the case, you might want to look at: A Sudoku Solver in Java implementing Knuth’s Dancing Links Algorithm. It's quite clear and explains also the reasoning behind.
N.B. Algorithm X is a backtracking algorithm so, if that's your only requirement, you can definitely use this approach.
Hope this can help.
Related
I am working a problem that seems to be somewhat famous among beginning programmers, the 8 queens puzzle. I have seen several solutions to this problems using 2D arrays, recursion etc, but this problem is an assignment given in CS course book chapter introducing 1D arrays, so the available techniques to solve this problem are limited.
The procedure I have used, is by first creating a 1D array with the size of 64, which makes possible positions to place queens from index 0 to 63. A random position index is then generated, and a test is preformed to check if there is any queens attacking this position. If this position is not attacked by any queens, a queen is placed by setting the board[position] = true. When a queen is placed, the queenCount is incremented, and this process repeats until 8 queens have been placed.
If queens are placed in such a way that it is impossible to place 8, the board resets after 1 millisecond by preforming a timecheck, and retries to place the 8 queens. At the best I am able to place 7 queens, but the last remaining one is never placed. Each attempt is printed, along with queenCount for this attempt. Is it possible to use this approach, or is it a dead end?
Code example below:
package ch7;
public class Chapter_07_E22_EightQueens64bool {
public static void main(String[] args) {
int queenCount = 0;
int attemptCount = 0;
boolean[] board = new boolean[8 * 8];
final long TIME_LIMIT = 1; //Milliseconds
long startTime = System.currentTimeMillis();
while (queenCount < 8) {
int position = placeQueen(board.length);
if(checkPosition(position, board) && !board[position]) {
board[position] = true;
queenCount++;
}
long timeCheck = System.currentTimeMillis();
if (timeCheck - startTime > TIME_LIMIT) {
clearBoard(board);
queenCount = 0;
startTime = System.currentTimeMillis();
}
System.out.println("Attempt #" + ++attemptCount);
System.out.println(queenCount + " queens placed.");
printBoard(board);
}
}
public static void printBoard(boolean[] board) {
for (int i = 0; i < board.length; i++) {
if (board[i])
System.out.print("|Q");
else
System.out.print("| ");
if ((i + 1) % 8 == 0)
System.out.println("|");
}
}
public static int placeQueen(int boardSize) {
return (int)(Math.random() * boardSize);
}
public static boolean[] clearBoard(boolean[] board) {
for (int i = 0; i < board.length; i++)
board[i] = false;
return board;
}
public static boolean checkPosition(int position, boolean[] board) {
return checkTop(position, board) && checkBottom(position, board) && checkLeft(position, board) &&
checkRight(position, board) && checkTopLeft(position, board) && checkTopRight(position, board) &&
checkBottomLeft(position, board) && checkBottomRight(position, board);
}
public static boolean checkTop(int position, boolean[] board) {
// Checks each field above the current position while i >= 8
for (int i = position; i >= 8; i -= 8) {
if (board[i - 8])
return false;
}
return true;
}
public static boolean checkBottom(int position, boolean[] board) {
// Checks each field below the current position while i <= 55;
for (int i = position; i <= 55; i += 8) {
if (board[i + 8])
return false;
}
return true;
}
public static boolean checkRight(int position, boolean[] board) {
// Checks each field to the right of the current position while i % 8 < 7
for (int i = position; i % 8 < 7; i += 1) {
if (board[i + 1])
return false;
}
return true;
}
public static boolean checkLeft(int position, boolean[] board) {
// Checks each field to the left of the current position while i % 8 != 0
for (int i = position; i % 8 != 0; i -= 1) {
if (board[i - 1])
return false;
}
return true;
}
public static boolean checkTopLeft(int position, boolean[] board) {
// Checks each field top left of the current position while i >= 9
for (int i = position; i >= 9; i -= 9) {
if (board[i - 9])
return false;
}
return true;
}
public static boolean checkTopRight(int position, boolean[] board) {
// Checks each field top right of the current position while i >= 7
for (int i = position; i >= 7; i -= 7) {
if (board[i - 7])
return false;
}
return true;
}
public static boolean checkBottomRight(int position, boolean[] board) {
// Checks each field below the current position while i <= 54
for (int i = position; i <= 54; i += 9) {
if (board[i + 9])
return false;
}
return true;
}
public static boolean checkBottomLeft(int position, boolean[] board) {
// Checks each field below the current position while i <= 56
for (int i = position; i <= 56; i += 7) {
if (board[i + 7])
return false;
}
return true;
}
}
First, array of size 8 is perfectly sufficient.
The array index represents the column in which was the queen placed and the value represents the row.
[0, 2, 4, 6, 1, 3, 5, 7]
Means that queen in the first column was placed in the first row, second queen was placed in the 3rd row, 3rd queen in 5th row, etc...
So when you place a new queen, check if the row you add it in, isn't already in the array. This way, you only need to worry about diagonal collisions.
Simplest way of solving the problem is recursion (backtracking). If that is not allowed, you can simulate recursion with a stack. If that is not allowed either, you could use 8 nested loops - ugly.
You can improve your collision checking using a simple trick. It works like this -
Let's say your queen #0 is on row #3.
Which cells does she attack diagonally?
On the first column, it's row #2 and row #4 (-1 and +1)
On the second column, it's row #1 and row #5 (-2 and +2)
On the third column it's row #0 and row #6 (-3 and +3)
So when you add a new queen, you iterate previous queens checking one diagonal with (newIndex - oldIndex) + oldRow == newRow and the other diagonal with (newIndex - oldIndex) - oldRow == newRow
So, considering all this, the checking function could look like
boolean canAdd(List<Integer> p, int newRow) {
if (p.contains(newRow))
return false;
int insertIndex = p.size();
for (int i = 0; i < p.size(); i++) {
if (p.get(i) + (insertIndex - i) == newRow || p.get(i) - (insertIndex - i) == newRow)
return false;
}
return true;
}
While the main recursive function could look like
void solve(List<Integer> p, int index) {
if (index == 8) {
System.out.println(p);
return;
}
for (int i = 0; i < 8; i++) {
if (canAdd(p, i)) {
p.add(i);
solve(p, index + 1);
p.remove(p.size() - 1);
}
}
}
And you could call it like this
solve(new ArrayList<Integer>(), 0);
After working on this problem for a few days, I now have a solution that works that in a reasonable amount of time for N <= 20. It goes like this.
For i < N, initialize queens[i] = i. Each row can only hold 1 value, so no need to check for collisions on the left or right. As long as there is no duplicate values in the array, there will not be any column collisions either.
Use the method to check if a queen at a given point, shares a diagonal with a queen at another given point. The method checks to see if the distance between x1 and x0 is equal to the distance of y1 and y0. If the distance is equal, then the co-ordinates (x0,y0) and (x1,y1) share the same diagonal.
Use another method to invoke shareDiagonal(int x0, int y0, int x1, int y1) to check if a queen at a given row, for example on row 7, collides with a queen on any rows above row 7. As mentioned, only the rows above the given row are checked. The reason is that if you for example are checking row2 for any diagonal collisions, any collision with rows below row 2 will be revealed when checking a row with a higher index value. If a queen on row 2 collides with a queen on row 4, this will be revealed when checking row 4 and the rows above.
A third checking method invokes checkRowForCollision(int[] queens, int row), where each row is traversed checking for collisions on the rows above. Row 1 is checked if there is any collisions with queens on row 0, Row 2 is checked if there is any collisions on row 0 and 1, row 3 is checked if there is any collisions on row 0, 1 and 2, etc..
While there is diagonal collisions between any of the queens, the board shuffles until it shows a solution where no queens attack each other.
Code example below:
package ch7;
public class Chapter_07_E22_EightQueens {
static final int N = 8;
public static void main(String[] args) {
int[] queens = new int[N];
int attempts = 0;
for (int i = 0; i < N; i++)
queens[i] = i;
while (checkBoardForCollision(queens)) {
shuffleBoard(queens);
attempts++;
}
printBoard(queens);
System.out.println("Solution found in " + attempts + " attempts");
}
public static void printBoard(int[] queens) {
for (int row = 0; row < N; row++) {
System.out.printf("%-1c", '|');
for (int column = 0; column < N; column++) {
System.out.printf("%-1c|", (queens[row] == column) ? 'Q' : ' ');
}
System.out.println();
}
}
public static boolean shareDiagonal(int x0, int y0, int x1, int y1) {
int dy = Math.abs(y1 - y0);
int dx = Math.abs(x1 - x0);
return dx == dy;
}
public static boolean checkRowForCollision(int[] queens, int row) {
for (int i = 0; i < row; i++) {
if (shareDiagonal(i, queens[i], row, queens[row]))
return true;
}
return false;
}
public static boolean checkBoardForCollision(int[] queens) {
for (int row = 0; row < queens.length; row++)
if (checkRowForCollision(queens, row))
return true;
return false;
}
public static int[] shuffleBoard(int[] queens) {
for (int i = queens.length - 1; i > 0; i--) {
int j = (int)(Math.random() * (i + 1));
int temp = queens[i];
queens[i] = queens[j];
queens[j] = temp;
}
return queens;
}
}
One of the problems, there may be more though, is in the checkTop method.
public static boolean checkTop(int position, boolean[] board)
{
// Checks each field above the current position while i - 8 > - 1
for (int i = position; i > (i - 8); i -= 8)
{
if ((i - 8) > -1)
{
if (board[i - 8])
return false;
}
}
return true;
}
There are cases when the method doesn't find a slot (board[i - 8] = true) and i reaches the value of 7. After this point, the condition of the for loop (i > (i - 8)) will always be true and the condition of the outermost if inside the loop (if ( (i - 8) > -1) will always be false. This causes the program to infinitely stay in the loop.
Example (i reaches -5):
i = -5;
i > ( i - 8) : -5 > (-5 -8 = -13) (always true)
(i - 8) > -1 : -13 > -1 (false) always false for i <= 7
I'm trying to learn about artificial intelligence and how to implement it in a program. The easiest place to start is probably with simple games (in this case Tic-Tac-Toe) and Game Search Trees (recursive calls; not an actual data structure). I found this very useful video on a lecture about the topic.
The problem I'm having is that the first call to the algorithm is taking an extremely long amount of time (about 15 seconds) to execute. I've placed debugging log outputs throughout the code and it seems like it is calling parts of the algorithm an excessive amount of times.
Here's the method for choosing the best move for the computer:
public Best chooseMove(boolean side, int prevScore, int alpha, int beta){
Best myBest = new Best();
Best reply;
if (prevScore == COMPUTER_WIN || prevScore == HUMAN_WIN || prevScore == DRAW){
myBest.score = prevScore;
return myBest;
}
if (side == COMPUTER){
myBest.score = alpha;
}else{
myBest.score = beta;
}
Log.d(TAG, "Alpha: " + alpha + " Beta: " + beta + " prevScore: " + prevScore);
Move[] moveList = myBest.move.getAllLegalMoves(board);
for (Move m : moveList){
String choice;
if (side == HUMAN){
choice = playerChoice;
}else if (side == COMPUTER && playerChoice.equals("X")){
choice = "O";
}else{
choice = "X";
}
Log.d(TAG, "Current Move: column- " + m.getColumn() + " row- " + m.getRow());
int p = makeMove(m, choice, side);
reply = chooseMove(!side, p, alpha, beta);
undoMove(m);
if ((side == COMPUTER) && (reply.score > myBest.score)){
myBest.move = m;
myBest.score = reply.score;
alpha = reply.score;
}else if((side == HUMAN) && (reply.score < myBest.score)){
myBest.move = m;
myBest.score = reply.score;
beta = reply.score;
}//end of if-else statement
if (alpha >= beta) return myBest;
}//end of for loop
return myBest;
}
Where the makeMove method makes the move if the spot is empty and returns a value (-1 - human win, 0 - draw, 1 - computer win, -2 or 2 - otherwise). Though I believe the error may be in the getAllLegalMoves method:
public Move[] getAllLegalMoves(String[][] grid){
//I'm unsure whether this method really belongs in this class or in the grid class, though, either way it shouldn't matter.
items = 0;
moveList = null;
Move move = new Move();
for (int i = 0; i < 3; i++){
for(int j = 0; j < 3; j++){
Log.d(TAG, "At Column: " + i + " At Row: " + j);
if(grid[i][j] == null || grid[i][j].equals("")){
Log.d(TAG, "Is Empty");
items++;
if(moveList == null || moveList.length < items){
resize();
}//end of second if statement
move.setRow(j);
move.setColumn(i);
moveList[items - 1] = move;
}//end of first if statement
}//end of second loop
}//end of first loop
for (int k = 0; k < moveList.length; k++){
Log.d(TAG, "Count: " + k + " Column: " + moveList[k].getColumn() + " Row: " + moveList[k].getRow());
}
return moveList;
}
private void resize(){
Move[] b = new Move[items];
for (int i = 0; i < items - 1; i++){
b[i] = moveList[i];
}
moveList = b;
}
To sum it all up: What's causing my call, to choose the best move, to take so long? What am I missing? Is there an easier way to implement this algorithm? Any help or suggestions will be greatly appreciated, thanks!
A minimax tree with alpha beta pruning should be visualized as a tree, each node of the tree being a possible move that many turns into the future, and its children being all the moves that can be taken from it.
To be as fast as possible and guarantee you'll only need space linear on number of moves you're looking ahead, you do a depth first search and 'sweep' from one side to another. As in, if you imagine the whole tree being constructed, your program would actually only construct a single strand from lead to root one at a time, and discard any parts of it it is done with.
I'm just going to copy the wikipedia pseudo code at this point because it's really, really succinct and clear:
function alphabeta(node, depth, α, β, Player)
if depth = 0 or node is a terminal node
return score
if Player = MaxPlayer
for each child of node
α := max(α, alphabeta(child, depth-1, α, β, not(Player) ))
if β ≤ α
break (* Beta cut-off *)
return α
else
for each child of node
β := min(β, alphabeta(child, depth-1, α, β, not(Player) ))
if β ≤ α
break (* Alpha cut-off *)
return β
Notes:
-'for each child of node' - Rather than editing the state of the current board, create an entirely new board that is the result of applying the move. By using immutable objects, your code will be less prone to bugs and quicker to reason about in general.
-To use this method, call it for every possible move you can make from the current state, giving it depth -1, -Infinity for alpha and +Infinity for beta, and it should start by being the non-moving player's turn in each of these calls - the one that returns the highest value is the best one to take.
It's very very conceptually simple. If you code it right then you never instantiate more than (depth) boards at once, you never consider pointless branches and so on.
I am not going to profile your code for you, but since this is such a nice coding kata I wrote a small ai for tic tac toe:
import java.math.BigDecimal;
public class Board {
/**
* -1: opponent
* 0: empty
* 1: player
*/
int[][] cells = new int[3][3];
/**
* the best move calculated by eval(), or -1 if no more moves are possible
*/
int bestX, bestY;
int winner() {
// row
for (int y = 0; y < 3; y++) {
if (cells[0][y] == cells[1][y] && cells[1][y] == cells[2][y]) {
if (cells[0][y] != 0) {
return cells[0][y];
}
}
}
// column
for (int x = 0; x < 3; x++) {
if (cells[x][0] == cells[x][1] && cells[x][1] == cells[x][2]) {
if (cells[x][0] != 0) {
return cells[x][0];
}
}
}
// 1st diagonal
if (cells[0][0] == cells[1][1] && cells[1][1] == cells[2][2]) {
if (cells[0][0] != 0) {
return cells[0][0];
}
}
// 2nd diagonal
if (cells[2][0] == cells[1][1] && cells[1][1] == cells[0][2]) {
if (cells[2][0] != 0) {
return cells[2][0];
}
}
return 0; // nobody has won
}
/**
* #return 1 if side wins, 0 for a draw, -1 if opponent wins
*/
int eval(int side) {
int winner = winner();
if (winner != 0) {
return side * winner;
} else {
int bestX = -1;
int bestY = -1;
int bestValue = Integer.MIN_VALUE;
loop:
for (int y = 0; y < 3; y++) {
for (int x = 0; x < 3; x++) {
if (cells[x][y] == 0) {
cells[x][y] = side;
int value = -eval(-side);
cells[x][y] = 0;
if (value > bestValue) {
bestValue = value;
bestX = x;
bestY = y;
if (bestValue == 1) {
// it won't get any better, we might as well stop thinking
break loop;
}
}
}
}
}
this.bestX = bestX;
this.bestY = bestY;
if (bestValue == Integer.MIN_VALUE) {
// there were no moves left, it must be a draw!
return 0;
} else {
return bestValue;
}
}
}
void move(int side) {
eval(side);
if (bestX == -1) {
return;
}
cells[bestX][bestY] = side;
System.out.println(this);
int w = winner();
if (w != 0) {
System.out.println("Game over!");
} else {
move(-side);
}
}
#Override
public String toString() {
StringBuilder sb = new StringBuilder();
char[] c = {'O', ' ', 'X'};
for (int y = 0; y < 3; y++) {
for (int x = 0; x < 3; x++) {
sb.append(c[cells[x][y] + 1]);
}
sb.append('\n');
}
return sb.toString();
}
public static void main(String[] args) {
long start = System.nanoTime();
Board b = new Board();
b.move(1);
long end = System.nanoTime();
System.out.println(new BigDecimal(end - start).movePointLeft(9));
}
}
The astute reader will have noticed I don't use alpha/beta cut-off. Still, on my somewhat dated notebook, this plays through a game in 0.015 seconds ...
Not having profiled your code, I can't say for certain what the problem is. However, you logging each possible move at every node in the search tree might have something to do with it.
I'm having trouble coding the 8 queens problem. I've coded a class to help me solve it, but for some reason, I'm doing something wrong. I kind of understand what's supposed to happen.
Also, we have to use recursion to solve it but I have no clue how to use the backtracking I've read about, so I just used it in the methods checking if a position is legitimate.
My board is String [] [] board = { { "O", "O"... etc etc with 8 rows and 8 columns.
If I'm getting anything wrong conceptually or making a grave Java mistake, please say so :D
Thanks!
public void solve () {
int Queens = NUM_Queens - 1;
while (Queens > 0) {
for (int col = 0; col < 8; col++) {
int row = -1;
boolean c = false;
while (c = false && row < 8) {
row ++;
c = checkPos (row, col);
}
if (c == true) {
board[row][col] = "Q";
Queens--;
}
else
System.out.println("Error");
}
}
printBoard ();
}
// printing the board
public void printBoard () {
String ret = "";
for (int i = 0; i < 8; i++) {
for (int a = 0; a < 8; a++)
ret += (board[i][a] + ", ");
ret += ("\n");
}
System.out.print (ret);
}
// checking if a position is a legitimate location to put a Queen
public boolean checkPos (int y, int x) {
boolean r = true, d = true, u = true, co = true;
r = checkPosR (y, 0);
co = checkPosC (0, x);
int col = x;
int row = y;
while (row != 0 && col != 0 ) { //setting up to check diagonally downwards
row--;
col--;
}
d = checkPosDD (row, col);
col = x;
row = y;
while (row != 7 && col != 0 ) { //setting up to check diagonally upwards
row++;
col--;
}
d = checkPosDU (row, col);
if (r = true && d = true && u = true && co = true)
return true;
else
return false;
}
// checking the row
public boolean checkPosR (int y, int x) {
if (board[y][x].contentEquals("Q"))
return false;
else if (board[y][x].contentEquals("O") && x == 7)
return true;
else //if (board[y][x].contentEquals("O"))
return checkPosR (y, x+1);
}
// checking the column
public boolean checkPosC (int y, int x) {
if (board[y][x].contentEquals("Q"))
return false;
else if (board[y][x].contentEquals("O") && y == 7)
return true;
else //if (board[y][x].contentEquals("O"))
return checkPosR (y+1, x);
}
// checking the diagonals from top left to bottom right
public boolean checkPosDD (int y, int x) {
if (board[y][x].contentEquals("Q"))
return false;
else if (board[y][x].contentEquals("O") && (x == 7 || y == 7))
return true;
else //if (board[y][x].contentEquals("O"))
return checkPosR (y+1, x+1);
}
// checking the diagonals from bottom left to up right
public boolean checkPosDU (int y, int x) {
if (board[y][x].contentEquals("Q"))
return false;
else if (board[y][x].contentEquals("O") && (x == 7 || y == 0))
return true;
else //if (board[y][x].contentEquals("O"))
return checkPosR (y-1, x+1);
}
}
As this is homework, the solution, but not in code.
Try to write a method that only handles what needs to happen on a single column; this is where you are supposed to use recursion. Do backtracking by checking if a solution exists, if not, undo your last change (i.e. change the queen position) and try again. If you only focus on one part of the problem (one column), this is much easier than thinking about all columns at the same time.
And as Quetzalcoatl points out, you are assigning false to your variable in the first loop. You probably do not want to do that. You should always enable all warnings in your compiler (run javac with -Xlint) and fix them.
You are trying some kind of brute-force, but, as you already mentioned, you have no recursion.
Your programs tries to put a queen on the first possible position. But at the end no solution is found. It follows that your first assumption (the position of your first queen) is invalid. You have to go back to this state. And have to assume that your checkPos(x,y) is false instead of true.
Now some hints:
As mentioned before by NPE int[N] queens is more suitable representation.
sum(queens) have to be 0+1+2+3+4+5+6+7=28, since a position has to be unique.
Instead of checking only the position of the new queen, you may check a whole situation. It is valid if for all (i,j) \in N^2 with queen(i) = j, there exists no (k,l) != (i,j) with abs(k-i) == abs(l-j)
Im working on figuring out the maximum number of bishops I can place on a nxn board without them being able to attack each other. Im having trouble checking the Diagonals. below is my method to check the diagonals. The squares where a bishop currently is are marked as true so the method is supposed to check the diagonals and if it returns true then the method to place the bishops will move to the next row.
Im not quite sure whats going wrong, any help would be appreciated.
private boolean bishopAttack(int row, int column)
{
int a,b,c;
for(a = 1; a <= column; a++)
{
if(row<a)
{
break;
}
if(board[row-a][column-a])
{
return true;
}
}
for(b = 1; b <= column; b++)
{
if(row<b)
{
break;
}
if(board[row+b][column-b])
{
return true;
}
}
for(c = 1; b <= column; b++)
{
if(row<c)
{
break;
}
if(board[row+c][column+c])
{
return true;
}
}
return false;
}
for(c = 1; b <= column; b++)
Shouldn't it be
for(c = 1; c <= column; c++)
By the way:
1) Use i, j, k instead of a, b, c, etc. No REAL reason why... it's just convention.
2) You don't have to keep naming new variables. Try something like this:
for(int i = 1; i <= column; i++)
{
...
}
//because i was declared in the for loop, after the } it no longer exists and we can redeclare and reuse it
for(int i = 1; i <= column; i++)
{
...
}
3) Your error checking is incorrect. It should be something like this:
for(int i = 1; i < 8; i++)
{
int newrow = row - i;
int newcolumn = column - i;
if (newrow < 0 || newrow > 7 || newcolumn < 0 || newcolumn > 7)
{
break;
}
if (board[newrow][newcolumn])
{
return true;
}
}
Now when you copy+paste your for loop, you only have to change how newrow and newcolumn are calculated, and everything else (including loop variable name) will be identical. The less you have to edit when copy+pasting, the better. We also attempt all 7 squares so we don't have to change the ending condition - the if check within the loop will stop us if we attempt to go out of bounds in ANY direction.
4) Better still, of course, would be using the for loop only once and passing only the changing thing into it... something like...
private boolean bishopAttackOneDirection(int rowdelta, int coldelta, int row, int column)
{
for(int i = 1; i < 8; i++)
{
int newrow = row + rowdelta*i;
int newcolumn = column + columndelta*i;
if (newrow < 0 || newrow > 7 || newcolumn < 0 || newcolumn > 7)
{
break;
}
if (board[newrow][newcolumn])
{
return true;
}
}
return false;
}
private boolean BishopAttack(int row, int column)
{
return BishopAttackInOneDirection(-1, -1, row, column)
|| BishopAttackInOneDirection(1, -1, row, column)
|| BishopAttackInOneDirection(1, 1, row, column)
|| BishopAttackInOneDirection(-1, 1, row, column);
}
Probably not quite the expected answer, but there is no reason to make life more complex then it is.
Im working on figuring out the maximum number of bishops I can place on a nxn board without them being able to attack each other.
public int getMaximumNumberOfNonAttackingBishopsForSquareBoardSize(final int boardSize) {
if (boardSize < 2 || boardSize > (Integer.MAX_VALUE / 2))
throw new IllegalArgumentException("Invalid boardSize, must be between 2 and " + Integer.MAX_VALUE / 2 + ", got: " + boardSize);
return 2 * boardSize - 2;
}
Source: http://mathworld.wolfram.com/BishopsProblem.html
So I've been writing a program for the game boggle. I create a little board for the user to use, but the problem is I don't know how to check if that word is on the board recursively. I want to be able to check if the word the entered is indeed on the board, and is valid. By valid I mean, the letters of the word must be adjacent to each other. For those who have played boggle you'll know what I mean. All I want to do is check if the word is on the board.
This is what I have so far ....
import java.io.*;
public class boggle {
InputStreamReader isr = new InputStreamReader(System.in);
BufferedReader br = new BufferedReader(isr);
private String s = "";
private int [][] lettersNum = new int [5][5];
private char [][] letters = new char [5][5];
private char [] word = new char [45]; // Size at 45, because the longest word in the dictionary is only 45 letters long
private char [] temp;
public void generateNum()
{
for (int row = 0; row < 5; row ++)
{
for (int col = 0; col < 5; col++)
{
lettersNum [row][col] = (int) (Math.random() * 26 + 65);
}
}
}
public void numToChar()
{
for (int row = 0; row < 5; row ++)
{
for (int col = 0; col < 5; col++)
{
letters [row][col] = (char)(lettersNum[row][col]);
}
}
}
public void display()
{
for (int row = 0; row < 5; row ++)
{
for (int col = 0; col < 5; col++)
{
System.out.print(letters[row][col]);
}
System.out.println("");
}
}
public void getInput() throws IOException
{
System.out.println("Please enter a word : ");
s=br.readLine();
s=s.toUpperCase();
word = s.toCharArray();
}
public int search(int row, int col)
{
if((row <0) || (row >= 5) || (col < 0) || (col >= 5))
{
return (0);
}
else
{
temp = word;
return (1+ search(row +1, col) +
search(row -1, col) +
search(row, col + 1) +
search(row, col-1) +
search(row +1, col +1)+
search(row +1, col -1)+
search(row -1, col +1)+
search(row -1, col -1));
}
}
}
The search was my searching algorithm to check if the word is on the board but I don't know if it is correct or if it will work. Furthermore, I don't know how to actually tell the user that the word is valid !
Thanks for all the help :)
SO I tried to use what you suggested below but I dont really understand the int [5][5] thing. So this is what I tried, but I keep getting out of bounds errors ! Here is the soruce ...
public void locate()
{
temp = word[0];
for (int row = 0; row <5; row++)
{
for (int col = 0; col <5; col++)
{
if(temp == letters[row][col])
{
search(row,col);
}
}
}
}
public int search(int row, int col)
{
if(letters[row][col-1]==word[count]) // Checks the letter to the left
{
count++;
letters[row][col-1] = '-'; // Just to make sure the program doesn't go back on itself
return search(row, col-1);
}
else if (letters[row][col+1] == word[count])// Checks the letter to the right
{
count++;
letters[row][col+1] = '-';// Just to make sure the program doesn't go back on itself
return search(row, col +1);
}
else if (letters[row+1][col]== word[count])// Checks the letter below
{
count++;
letters[row+1][col] = '-';// Just to make sure the program doesn't go back on itself
return search(row +1 , col);
}
else if (letters[row-1][col]== word[count])// Checks the letter above
{
count++;
letters[row-1][col] = '-';// Just to make sure the program doesn't go back on itself
return search(row -1 , col);
}
else if (letters[row-1][col-1]== word[count])// Checks the letter to the top left
{
count++;
letters[row-1][col-1] = '-';// Just to make sure the program doesn't go back on itself
return search(row -1 , col-1);
}
else if (letters[row-1][col+1]== word[count])// Checks the letter to the top right
{
count++;
letters[row-1][col+1] = '-';// Just to make sure the program doesn't go back on itself
return search(row -1 , col+1);
}
else if (letters[row+1][col-1]== word[count])// Checks the letter to the bottom left
{
count++;
letters[row+1][col-1] = '-';// Just to make sure the program doesn't go back on itself
return search(row +1 , col-1);
}
else if (letters[row+1][col+1]== word[count])// Checks the letter to the bottom right
{
count++;
letters[row+1][col+1] = '-';// Just to make sure the program doesn't go back on itself
return search(row +1 , col+1);
}
return 0;
}
private int count = 0; (was declared at the top of the class, in case you were wondering where I got the word[count] from
Your current search function doesn't actually do anything. I'm assuming this is homework so, no free lunch ;)
The simplest approach would be to have two recursive functions:
public boolean findStart(String word, int x, int y)
This will do a linear search of the board looking for the first character in word. If your current location doesn't match, you call yourself with the next set of coords. When it finds a match, it calls your second recursive function using word, the current location, and a new, empty 4x4 matrix:
public boolean findWord(String word, int x, int y, int[][] visited)
This function first checks to see if the current location matches the first letter in word. If it does, it marks the current location in visited and loops through all the adjoining squares except ones marked in visited by calling itself with word.substring(1) and those coords. If you run out of letters in word, you've found it and return true. Note that if you're returning false, you need to remove the current location from visited.
You can do this with one function, but by splitting out the logic I personally think it becomes easier to manage in your head. The one downside is that it does do an extra comparison for each first letter in a word. To use a single function you would need to keep track of what "mode" you were in either with a boolean or a depth counter.
Edit: Your longest word should only be 16. Boggle uses a 4x4 board and a word can't use the same location twice. Not that this really matters, but it might for the assignment. Also note that I just did this in my head and don't know that I got it 100% right - comments appreciated.
Edit in response to comments:
Here's what your iterative locate would look like using the method I outline above:
public boolean locate(String word)
{
for (int row = 0; row < 4; row++)
{
for (int col =0; col < 4; col++)
{
if (word.charAt(0) == letters[row][col])
{
boolean found = findWord(word, row, col, new boolean[4][4]);
if (found)
return true;
}
}
}
return false;
}
The same thing recursively looks like the following, which should help:
public boolean findStart(String word, int x, int y)
{
boolean found = false;
if (word.charAt(0) == letters[x][y])
{
found = findWord(word, x, y, new boolean[4][4]);
}
if (found)
return true;
else
{
y++;
if (y > 3)
{
y = 0;
x++;
}
if (x > 3)
return false;
}
return findStart(word, x, y);
}
So here's findWord() and a helper method getAdjoining() to show you how this all works. Note that I changed the visited array to boolean just because it made sense:
public boolean findWord(String word, int x, int y, boolean[][] visited)
{
if (letters[x][y] == word.charAt(0))
{
if (word.length() == 1) // this is the last character in the word
return true;
else
{
visited[x][y] = true;
List<Point> adjoining = getAdjoining(x,y,visited);
for (Point p : adjoining)
{
boolean found = findWord(word.substring(1), p.x, p.y, visited);
if (found)
return true;
}
visited[x][y] = false;
}
}
return false;
}
public List<Point> getAdjoining(int x, int y, boolean[][] visited)
{
List<Point> adjoining = new LinkedList<Point>();
for (int x2 = x-1; x2 <= x+1; x2++)
{
for (int y2 = y-1; y2 <= y+1; y2++)
{
if (x2 < 0 || x2 > 3 ||
y2 < 0 || y2 > 3 ||
(x2 == x && y2 == y) ||
visited[x2][y2])
{
continue;
}
adjoining.add(new Point(x2,y2));
}
}
return adjoining;
}
So now, after you get input from the user as a String (word), you would just call:
boolean isOnBoard = findStart(word,0,0);
I did this in my head originally, then just went down that path to try and show you how it works. If I were to actually implement this I would do some things differently (mainly eliminating the double comparison of the first letter in the word, probably by combining the two into one method though you can do it by rearranging the logic in the current methods), but the above code does function and should help you better understand recursive searching.