Explanation of 8-Queen solution Java code. - java

I found a 8-Queen solution that I was able to compile and run in Eclipse. I believe this solution follows the backtracking approach and meat of the work is done in the solution and unsafe functions, but I am having a hard time understanding the code paths in there. Can someone please help me understand what this code is doing.
My Source - http://rosettacode.org/wiki/N-queens_problem#Java
I verified the output against the 92 solutions published on other sources. Looks good. So I know the code works.
I have tried to format it and add some basic notes to clear things up -
private static int[] b = new int[8];
private static int s = 0;
public static void main(String[] args) {
// solution from - http://rosettacode.org/wiki/N-queens_problem#Java
new QueenN();
}
public QueenN() {
solution();
}
public void solution() {
int y = 0;
b[0] = -1;
while (y >= 0) {
do {
b[y]++;
} while ((b[y] < 8) && unsafe(y));
if (b[y] < 8) {
if (y < 7) {
b[++y] = -1;
} else {
putboard();
}
} else {
y--;
}
}
}
// check if queen placement clashes with other queens
public static boolean unsafe(int y) {
int x = b[y];
for (int i = 1; i <= y; i++) {
int t = b[y - i];
if (t == x || t == x - i || t == x + i) {
return true;
}
}
return false;
}
// printing solution
public static void putboard() {
System.out.println("\n\nSolution " + (++s));
for (int y = 0; y < 8; y++) {
for (int x = 0; x < 8; x++) {
if (b[y] == x)
System.out.print("|Q");
else
System.out.print("|_");
}
System.out.println("|");
}
}
End.

Let's try to understand the code step by step. First of all, we call the function solution(), which is what leads to the execution of the puzzle answer.
Solution funcion:
public void solution() {
int y = 0;
b[0] = -1;
while (y >= 0) {
do {
b[y]++; //if last cell was unsafe or we reached the end of the board, we go for the next row.
} while ((b[y] < 8) && unsafe(y)); //Checks whether it's the last cell and if it's an unsafe cell (clashing)
if (b[y] < 8) { //We found a safe cell. Hooray!
if (y < 7) { //Did we place the last queen?
b[++y] = -1; //Nope, let's allocate the next one.
} else {
putboard(); //Yup, let's print the result!
}
} else { //If not a single safe cell was found, we reallocate the last queen.
y--;
}
}
}
On the first while, you're going to iterate through each cell in a row (or column, however you prefer it. It's just a rotation matter). On each cell you make the unsafe(y) check, which will return true in case the cell you're placing the queen in is clashing with other queen-occupied cells (as you've already found out in the comment).
Next step, once we've found a safe cell in which to place the actual queen (y), we make a security check: if we have not found a single safe cell for that queen, we have to reallocate last queen.
In case the cell was found and was correct, we check whether it was the last queen (y < 7). If it is so, we proceed to print the result. Otherwise, we just re-start the while loop by placing b[++y] = -1.
Unsafe function:
public static boolean unsafe(int y) {
int x = b[y]; //Let's call the actual cell "x"
for (int i = 1; i <= y; i++) { //For each queen before placed BEFORE the actual one, we gotta check if it's in the same row, column or diagonal.
int t = b[y - i];
if (t == x || t == x - i || t == x + i) {
return true; //Uh oh, clash!
}
}
return false; //Yay, no clashes!
}
This function checks whether the queen we're using clashes with any of the allocated queens before this one. The clashes might happen diagonally, vertically or horizontally: That is why there is a triple OR check before the "return true" statement.
Putboard function:
public static void putboard() {
System.out.println("\n\nSolution " + (++s));
for (int y = 0; y < 8; y++) {
for (int x = 0; x < 8; x++) {
if (b[y] == x)
System.out.print("|Q");
else
System.out.print("|_");
}
System.out.println("|");
}
}
I'm not gonna explain this one that deep, because it is simply a fairly simply line printing function which you can find out how it works by yourself when executing the solution!
Hope this helps.
Cheers!

Related

For-loop involved in Diagonal Check for Connect Four

So I am currently coding Connect 4 on Netbeans. I have the vertical and horizontal check already made but I am having trouble with the diagonal check, specifially the for loops. Currently my code for this,
public static boolean checkDiagnol(String[][] board, int counter, String playerMoving, int lastPlacedTileRow, int col) {
for (int i = lastPlacedTileRow-1; q = col-1; i >= 0, q >=0; i--,q--){
if (board[i][q] == playerMoving) {
counter += 1;
} else {
break;
}
if (counter > 4) {
return true;
}
}
for (int i = lastPlacedTileRow + 1, q = col +1; i < board.length, q < board[0].length; i++,q++) {
if (board[i][q] == playerMoving) {
counter += 1;
} else {
break;
}
if (counter > 4) {
return true;
}
}
return false;
}
lastPlacedTileRow is the row of the last placed tile, col is the column chosen by the user, counter is a counter used to check if there are 4 tiles in a row, and playerMoving is the current players tile.
The current problem I have is that my for loops give errors. This is my first time using two variables in a single for loop so I am not sure how it is supose to be arranged.
Thanks for the help
Syntax
You have put a semicolon instead of a comma in the first for loop.
for (int i = lastPlacedTileRow-1; q = col-1; i >= 0, q >=0; i--,q--){
this should be
for (int i = lastPlacedTileRow-1, q = col-1; i >= 0, q >=0; i--,q--){
Logic
I think variable i should be counted down (or up) in both the loops because we have to check below the lastPlacedTileRow in both cases.

Detect Infinite Loop?

I'm working on a Sudoku solver program. The idea is that the user inputs the Sudoku puzzle and the program solves it for them.
The program works fine when entering any normal puzzle. However, there are some puzzles that are impossible to solve. Here is one example that I entered: http://i.imgur.com/5L8pF8Q.png
The input is perfectly legal, but top right square cannot be filled in since all numbers 1-9 have been used in that row and column.
If I hit "Solve", my program freezes as it enters an infinite loop.
So my question here is, how can I prevent this from happening?
I tried implementing the "boolean flag" approach, but on second thought I realized that it's probably not feasible.
Here is my solver method:
public boolean solve(int i, int j) {
for (int a = 0; a < 9; a++) {
for (int b = 0; b < 9; b++) {
if (sudokuArray[a][b] == 0) {
for (int k = 1; k <= 9; k++) {
sudokuArray[a][b] = k;
if (checkNumber(a, b, k) && solve(a, b)) {
return true;
}else {
sudokuArray[a][b] = 0;
}
}
return false;
}
}
}
return true;
}
The checkNumber() method checks if number k can be legally inserted in row a, column b and returns true/false accordingly.
Ideas? Tips?
Thanks.
PS: Added checkNumber() as requested:
public boolean checkNumber(int i, int j, int num) {
for (int a = 0; a < 9; a++) {
if (a != i) {
if (sudokuArray[a][j] == num) {
return false;
}
}
if (a != j) {
if (sudokuArray[i][a] == num) {
return false;
}
}
}
for (int a = (i / 3) * 3; a < (i / 3) * 3 + 3; a++) {
for (int b = (j / 3) * 3; b < (j / 3) * 3 + 3; b++) {
if ((a != i) && (b != j)) {
if (sudokuArray[a][b] == num) {
return false;
}
}
}
}
return true;
}
This is just an idea (i would comment but this account is too new). Try making it so that if all numbers from 0-9 return false, then it returns an error of some sort. For example if it hasn't found an answer by 9, then move up to 10. If the program detects a 10, do some kind of System.out.println("Unsolvable") or something along those lines. Sorry if I'm confusing you by the way. I've been told I'm bad at explaining things.

java:generalized 8 queen to work for any initial state using depth first search [duplicate]

i am try to implement 8 queen using depth search for any initial state it work fine for empty board(no queen on the board) ,but i need it to work for initial state if there is a solution,if there is no solution for this initial state it will print there is no solution
Here is my code:
public class depth {
public static void main(String[] args) {
//we create a board
int[][] board = new int[8][8];
board [0][0]=1;
board [1][1]=1;
board [2][2]=1;
board [3][3]=1;
board [4][4]=1;
board [5][5]=1;
board [6][6]=1;
board [7][7]=1;
eightQueen(8, board, 0, 0, false);
System.out.println("the solution as pair");
for(int i=0;i<board.length;i++){
for(int j=0;j<board.length;j++)
if(board[i][j]!=0)
System.out.println(" ("+i+" ,"+j +")");
}
System.out.println("the number of node stored in memory "+count1);
}
public static int count1=0;
public static void eightQueen(int N, int[][] board, int i, int j, boolean found) {
long startTime = System.nanoTime();//time start
if (!found) {
if (IsValid(board, i, j)) {//check if the position is valid
board[i][j] = 1;
System.out.println("[Queen added at (" + i + "," + j + ")");
count1++;
PrintBoard(board);
if (i == N - 1) {//check if its the last queen
found = true;
PrintBoard(board);
double endTime = System.nanoTime();//end the method time
double duration = (endTime - startTime)*Math.pow(10.0, -9.0);
System.out.print("total Time"+"= "+duration+"\n");
}
//call the next step
eightQueen(N, board, i + 1, 0, found);
} else {
//if the position is not valid & if reach the last row we backtracking
while (j >= N - 1) {
int[] a = Backmethod(board, i, j);
i = a[0];
j = a[1];
System.out.println("back at (" + i + "," + j + ")");
PrintBoard(board);
}
//we do the next call
eightQueen(N, board, i, j + 1, false);
}
}
}
public static int[] Backmethod(int[][] board, int i, int j) {
int[] a = new int[2];
for (int x = i; x >= 0; x--) {
for (int y = j; y >= 0; y--) {
//search for the last queen
if (board[x][y] != 0) {
//deletes the last queen and returns the position
board[x][y] = 0;
a[0] = x;
a[1] = y;
return a;
}
}
}
return a;
}
public static boolean IsValid(int[][] board, int i, int j) {
int x;
//check the queens in column
for (x = 0; x < board.length; x++) {
if (board[i][x] != 0) {
return false;
}
}
//check the queens in row
for (x = 0; x < board.length; x++) {
if (board[x][j] != 0) {
return false;
}
}
//check the queens in the diagonals
if (!SafeDiag(board, i, j)) {
return false;
}
return true;
}
public static boolean SafeDiag(int[][] board, int i, int j) {
int xx = i;
int yy = j;
while (yy >= 0 && xx >= 0 && xx < board.length && yy < board.length) {
if (board[xx][yy] != 0) {
return false;
}
yy++;
xx++;
}
xx = i;
yy = j;
while (yy >= 0 && xx >= 0 && xx < board.length && yy < board.length) {
if (board[xx][yy] != 0) {
return false;
}
yy--;
xx--;
}
xx = i;
yy = j;
while (yy >= 0 && xx >= 0 && xx < board.length && yy < board.length) {
if (board[xx][yy] != 0) {
return false;
}
yy--;
xx++;
}
xx = i;
yy = j;
while (yy >= 0 && xx >= 0 && xx < board.length && yy < board.length) {
if (board[xx][yy] != 0) {
return false;
}
yy++;
xx--;
}
return true;
}
public static void PrintBoard(int[][] board) {
System.out.print(" ");
for (int j = 0; j < board.length; j++) {
System.out.print(j);
}
System.out.print("\n");
for (int i = 0; i < board.length; i++) {
System.out.print(i);
for (int j = 0; j < board.length; j++) {
if (board[i][j] == 0) {
System.out.print(" ");
} else {
System.out.print("Q");
}
}
System.out.print("\n");
}
}
}
for example for this initial state it give me the following error:
Exception in thread "main" java.lang.StackOverflowError
i am stuck, i think the error is infinite call for the method how to solve this problem.
any idea will be helpful,thanks in advance.
note:the broad is two dimensional array,when i put (1) it means there queen at this point.
note2:
we i put the initial state as the following it work:
board [0][0]=1;
board [1][1]=1;
board [2][2]=1;
board [3][3]=1;
board [4][4]=1;
board [5][5]=1;
board [6][6]=1;
board [7][1]=1;
[EDIT: Added conditional output tip.]
To add to #StephenC's answer:
This is a heck of a complicated piece of code, especially if you're not experienced in programming Java.
I executed your code, and it outputs this over and over and over and over (and over)
back at (0,0)
01234567
0
1 Q
2 Q
3 Q
4 Q
5 Q
6 Q
7 Q
back at (0,0)
And then crashes with this
Exception in thread "main" java.lang.StackOverflowError
at java.nio.Buffer.<init>(Unknown Source)
...
at java.io.PrintStream.print(Unknown Source)
at java.io.PrintStream.println(Unknown Source)
at Depth.eightQueen(Depth.java:56)
at Depth.eightQueen(Depth.java:60)
at Depth.eightQueen(Depth.java:60)
at Depth.eightQueen(Depth.java:60)
at Depth.eightQueen(Depth.java:60)
...
My first instinct is always to add some System.out.println(...)s to figure out where stuff is going wrong, but that won't work here.
The only two options I see are to
Get familiar with a debugger and use it to step through and analyze why it's never stopping the loop
Break it down man! How can you hope to deal with a massive problem like this without breaking it into digestible chunks???
Not to mention that the concept of 8-queens is complicated to begin with.
One further thought:
System.out.println()s are not useful as currently implemented, because there's infinite output. A debugger is the better solution here, but another option is to somehow limit your output. For example, create a counter at the top
private static final int iITERATIONS = 0;
and instead of
System.out.println("[ANUMBERFORTRACING]: ... USEFUL INFORMATION ...")
use
conditionalSDO((iITERATIONS < 5), "[ANUMBERFORTRACING]: ... USEFUL INFORMATION");
Here is the function:
private static final void conditionalSDO(boolean b_condition, String s_message) {
if(b_condition) {
System.out.println(s_message);
}
}
Another alternative is to not limit the output, but to write it to a file.
I hope this information helps you.
(Note: I edited the OP's code to be compilable.)
You asked for ideas on how to solve it (as distinct from solutions!) so, here's a couple of hints:
Hint #1:
If you get a StackOverflowError in a recursive program it can mean one of two things:
your problem is too "deep", OR
you've got a bug in your code that is causing it to recurse infinitely.
In this case, the depth of the problem is small (8), so this must be a recursion bug.
Hint #2:
If you examine the stack trace, you will see the method names and line numbers for each of the calls in the stack. This ... and some thought ... should help you figure out the pattern of recursion in your code (as implemented!).
Hint #3:
Use a debugger Luke ...
Hint #4:
If you want other people to read your code, pay more attention to style. Your indentation is messed up in the most important method, and you have committed the (IMO) unforgivable sin of ignoring the Java style rules for identifiers. A method name MUST start with a lowercase letter, and a class name MUST start with an uppercase letter.
(I stopped reading your code very quickly ... on principle.)
Try to alter your method IsValid in the lines where for (x = 0; x < board.length - 1; x++).
public static boolean IsValid(int[][] board, int i, int j) {
int x;
//check the queens in column
for (x = 0; x < board.length - 1; x++) {
if (board[i][x] != 0) {
return false;
}
}
//check the queens in row
for (x = 0; x < board.length - 1; x++) {
if (board[x][j] != 0) {
return false;
}
}
//check the queens in the diagonals
if (!SafeDiag(board, i, j)) {
return false;
}
return true;
}

How can I check if ships are overlapping in battleships game? Confused with algorithm

I'm not a great programmer so I was wondering if someone could help me. In my battleships game I have ships made from the Rect class, but I need to check if they are overlapping. This is what I have so far.
EDIT: What exactly is wrong: I have two ships one of size 2 and 5. So say ship 1 has (0,0)(0,1) coordinates and ship 2 has (0,1) to (5,1).It works great for checking both coordinates of ship one on point(0,1), but that is it. I hope this make sense. so if I check (0,0) and (0,1) on (1,1) it shows no eror
public boolean contains(Ship ship) {
int currentX = ship.getX();
int currentY = ship.getY();
int testX = xCoord;
int testY = yCoord;
if (rotated) { //if ship is horizontal enter
for (int j = 0; j < sizeOfShip; j++) {
for (int k = 0; k < ship.getSize(); k++) {
if (testX == currentX && testY == currentY) {
return false;
}
testX++;
}
if (ship.rotated)
currentX++;
else {
currentY++;
}
}
}
//
if (!rotated) {
for (int j = 0; j < sizeOfShip; j++) {
for (int k = 0; k < ship.getSize(); k++) {
if (testX == currentX && testY == currentY) {
return false;
}
testY++;
}
if (ship.rotated)
currentX++;
else {
currentY++;
} }
}
return true;
}
I think the problem lies here (the same goes for the other if):
...
testX++;
}
if (ship.rotated)
currentX++;
else {
currentY++;
}
...
I assume testX is this ships x value. You are incrementing testX in every iteration in the inner loop and the input parameters value (currentX) in the outer loop. At the same time you are never resetting the value. Lets say this ship have a length of 5 and the input parameter a length of 2 and both are horizontal. After 3 iterations of the outer loop testX have been incremented by 6.
I think you want to swap the increments around and reset the currentX/Y value after each inner iteration:
for (int j = 0; j < sizeOfShip; j++) {
for (int k = 0; k < ship.getSize(); k++) {
if (testX == currentX && testY == currentY) {
return false;
}
if (ship.rotated)
currentX++;
else {
currentY++;
}
}
currentX = ship.getX();
currentY = ship.getY();
testX++;
}
This have to be done for both ifs. I cannot try this, so try it out and tell me if I have made a mistake. :)
On a different note. You can replace
}
//
if (!rotated) {
...
with
}
else {
...
The problem is that e.g. for a ship (0,1)(5,1) you need to check all the values (0,1)(1,1)(2,1)(3,1)(4,1)(5,1) against the all the other ship's similar values e.g. (0,0)(0,1) (no more since it's the small ship).
You need to modify your for-loops to do this for you. I suggest printing out those currentX/currentY values to make sure that they are doing this. In particular I don't think you want to be incrementing currentX/Y every iteration but rather currentX in one for-loop and currentY in the other.
Cheers.

How do we simplify this kind of code in Java? Something like macros in C?

public static boolean diagonals(char[][] b, int row, int col, int l) {
int counter = 1; // because we start from the current position
char charAtPosition = b[row][col];
int numRows = b.length;
int numCols = b[0].length;
int topleft = 0;
int topright = 0;
int bottomleft = 0;
int bottomright = 0;
for (int i=row-1,j=col-1;i>=0 && j>=0;i--,j--) {
if (b[i][j]==charAtPosition) {
topleft++;
} else {
break;
}
}
for (int i=row-1,j=col+1;i>=0 && j<=numCols;i--,j++) {
if (b[i][j]==charAtPosition) {
topright++;
} else {
break;
}
}
for (int i=row+1,j=col-1;i<=numRows && j>=0;i++,j--) {
if (b[i][j]==charAtPosition) {
bottomleft++;
} else {
break;
}
}
for (int i=row+1,j=col+1;i<=numRows && j<=numCols;i++,j++) {
if (b[i][j]==charAtPosition) {
bottomright++;
} else {
break;
}
}
return topleft + bottomright + 1 >= l || topright + bottomleft + 1 >= l; //in this case l is 5
}
After I was done posting the code above here, I couldn't help but wanted to simplify the code by merging the four pretty much the same loops into one method.
Here's the kind of method I want to have:
public int countSteps(char horizontal, char vertical) {
}
Two parameters horizontal and vertical can be either + or - to indicate the four directions to walk in. What I want to see if possible at all is i++; is generalized to i horizontal horizontal; when horizontal taking the value of +.
What I don't want to see is if or switch statements, for example:
public int countSteps(char horizontal, char vertical) {
if (horizontal == '+' && vertical == '-') {
for (int i=row-1,j=col+1;i>=0 && j<=numCols;i--,j++) {
if (b[i][j]==charAtPosition) {
topright++;
} else {
break;
}
}
} else if (horizontal == '+' && vertical == '+') {
for (int i=row+1,j=col+1;i>=0 && j<=numCols;i++,j++) {
if (b[i][j]==charAtPosition) {
topright++;
} else {
break;
}
}
} else if () {
} else {
}
}
Since it is as tedious as the original one. Note also that the comparing signs for the loop condition i>=0 && j<=numCols; for example, >= && <= have correspondence with the value combination of horizontal and vertical.
Sorry for my bad wording, please let me know if anything is not clear.
You can easily convert the loops to something like:
int doit(int i_incr, int j_incr) {
int cornerIncrement = 0;
for (int i=row+i_incr, j=col+j_incr; i>=0 && j>=0; i+=i_incr, j+=j_incr) {
if (b[i][j]==charAtPosition) {
cornerIncrement++;
} else {
break;
}
}
return cornerIncrement;
}
And then repeat 4 times...
int increment = doit(+1, -1); // Or (-1, +1) etc
topLeft += increment; // Or bottomLeft/topRight/bottomRight
So you have these two loops:
for (int i=row-1,j=col-1;i>=0 && j>=0;i--,j--) {
if (b[i][j]==charAtPosition) {
topleft++;
} else {
break;
}
}
for (int i=row-1,j=col+1;i>=0 && j<=numCols;i--,j++) {
if (b[i][j]==charAtPosition) {
topright++;
} else {
break;
}
}
First, turn your counters into an array, i.e. topleft -> counter[0] and topright -> counter[1]
Then, turn the difference between the code into variables, so you have:
for(direction = 0; direction < 2; direction++) {
int offset = direction * 2 - 1; // This is what I mean by doing some math
for(int i=row-1,j=col+offset;i>=0 && -j*offset>=-numCols*direction;i--,j+=offset) {
if (b[i][j]==charAtPosition) {
counter[direction]++;
// etc.
The math can get ugly sometimes, or you can do it in a separate line. Look at my other post on this question for an elegant way to do the math in this particular problem using ? : syntax.

Categories