Detect Infinite Loop? - java

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.

Related

How to find a >3 line of consecutive elements in a 2d array

I'm a game where you have to make a line in a row/column of 3 or more (up to 7) consecutive elements in a 2d array. Every time there is one of those lines you add the score and delete those consecutive elements from the row/column (Similar as to candycrash disappearing candies.
If you have something like this ['a' 'b' 'b' 'b' 'a'] the result should be ['a' '' '' '' 'a']
The problem comes to more complex cases like ['b' 'b' ' ' 'b' 'b'], that ends up like this
['' '' '' '' ''] because its also detected as a >=3 elem. consecutive line.
I know its due to the counter that keeps adding to the value it already has, but I couldnt come to any other solution till now
The code I have up to now is this:
**
public int[] checkRows() {
int[] results = new int[BOARD_SIZE];
for (int i = 0; i < BOARD_SIZE; i++) {
int counter = 1;
int counterHead = 1;
int j = 0;
while (j < BOARD_SIZE) {
if (j+1 < BOARD_SIZE) {
if (getBoard()[i][j].getType() == getBoard()[i][j+1].getType() && getBoard()[i][j].getType() != ' ') {
counter++;
}
}
if (counter >= 3)
deleteRows(i, j);
j++;
}
results[i] = counter;
}
return results;
}
**
So we want to see if there are 3 consecutive elements with the same value, but what it looks like to me is we are simply testing if there are three values in a row of the board that are equal. This works if we find a section of consecutive equivalent elements, but as soon as we find a space or non-equal element the logic fails.
Things we need to consider:
If the counter reaches 3 we can break out of your conditional and delete. This case is covered.
If your counter is updated from its original value (counter > 1) and never reaches 3 we know we must have encountered either a space or a non-equivalent value. In this case we should reset the counter and continue our test for the rest of the row.
Your problem is that you are not counting consecutive values, but rather pairs of consecutive values. For 'b', 'b', 'b', there are three b characters, but only 2 pairs of values, 1) the first and second b, and 2) the second and third b. Your counter should start at 1 rather than 0 because every value is by itself a run of 1 "consecutive" values. This, along with resetting the counter when you see a non-matching letter should give you the result you desire.
I haven't tried this as I don't have your data or the structures that this code uses, but try this:
public int[] checkRows() {
int[] results = new int[BOARD_SIZE];
for (int i = 0; i < BOARD_SIZE; i++) {
int counter = 1;
int counterHead = 1;
int j = 1;
while (j < BOARD_SIZE) {
if (j+1 < BOARD_SIZE) {
if (getBoard()[i][j].getType() == getBoard()[i][j+1].getType() && getBoard()[i][j].getType() != ' ') {
counter++;
}
else {
counter = 1;
}
}
if (counter >= 3)
deleteRows(i, j);
j++;
}
results[i] = counter;
}
return results;
}
First of all, I would suggest that for such complex problems, always try to break your problems and then merge those pieces together.
Below is the algorithm for your problem, just for simplicity and ease of explanation I used an Integer array which you can easily replace with a string or character array and change the condition.
A basic function for performing candyCrush Algorithm.
public void candyCrush(){
int[][] result = new int[][]{{1,2,2,2,2},
{1,2,2,2,1},
{1,2,1,1,1},
{2,1,2,1,1}
};
int count = 0;
for (int i = 0; i < result.length; i++) {
for (int j = 0; j < result[i].length; j++) {
if(result[i][j]==-1){
continue;
}
boolean hasRowElements = checkRowForCurrentIndex(result, i, j);
boolean hasColumnElements = checkColumnForCurrentIndex(result, i, j);
if(hasRowElements || hasColumnElements){
count++;
}
}
}
System.out.println(count);
}
private boolean checkRowForCurrentIndex(int[][] result, int row, int col) {
int forTop = row, forBottom = row;
int topStartingLimit = 0, bottomEndingLimit = 0;
while(forTop>= 0){
if(result[row][col] == result[forTop][col] && result[forTop][col]!=-1){
topStartingLimit = forTop;
}else{
break;
}
forTop--;
}
while(forBottom< result.length){
if(result[row][col] == result[forBottom][col] && result[forBottom][col]!=-1){
bottomEndingLimit = forBottom;
}else{
break;
}
forBottom++;
}
if(topStartingLimit==bottomEndingLimit){
return false;
}
if(bottomEndingLimit-topStartingLimit>=2 && bottomEndingLimit-topStartingLimit<= 6) {
deleteRows(result, topStartingLimit, bottomEndingLimit, row, col);
return true;
}
return false;
}
private void deleteRows(int[][] result, int topStartingLimit, int bottomEndingLimit, int row, int col) {
while(topStartingLimit<= bottomEndingLimit){
result[topStartingLimit][col] = -1;
topStartingLimit++;
}
return;
}
private boolean checkColumnForCurrentIndex(int[][] result, int row, int col) {
int forLeft = col, forRight = col;
int leftStartingLimit = 0, rightEndingLimit = 0;
while(forLeft>= 0){
if(result[row][col] == result[row][forLeft] && result[row][forLeft]!=-1){
leftStartingLimit = forLeft;
}else{
break;
}
forLeft--;
}
while(forRight< result[row].length){
if(result[row][col] == result[row][forRight] && result[row][forRight]!=-1){
rightEndingLimit = forRight;
}else{
break;
}
forRight++;
}
if(leftStartingLimit==rightEndingLimit){
return false;
}
if(rightEndingLimit-leftStartingLimit>=2 && rightEndingLimit-leftStartingLimit<= 6) {
deleteCols(result, leftStartingLimit, rightEndingLimit, row, col);
return true;
}
return false;
}
private void deleteCols(int[][] result, int leftStartingLimit, int rightEndingLimit, int row, int col) {
while(leftStartingLimit<= rightEndingLimit){
result[row][leftStartingLimit] = -1;
leftStartingLimit++;
}
return;
}
Definitely, you can optimize this code better by using the same function again for Rows and Cols, but for sake of simplicity. I tried to break everything so that the solution becomes more clear.
Hope this algorithm would work.

Finite Coins - using recursion

Given 1 coin from multiple denominations (E.G. a 1 coin, 5 coin, 16 coin), and a sum, return true or false determining if the sum can be made.
boolean go(int[] coins, int goal)
{
//Will set each time, but shouldn't matter as toggle is at bottom
boolean ans = false;
//loop running in recursion till founds ans
//Really bad time complexity lol
for (int i = 0; i < coins.length && (!ans); i++) {
if ((goal - coins[i] == 0) || goal == 0) {
return true;
}
if (goal > coins[i]) {
int[] red = new int[coins.length - 1];
//it necessary because making list with one less
int it = 0;
//Setting new list to avoid runtime
for(int x = 0; x < coins.length; x++){
if(!(i == x)){
red[it] = coins[i];
it += 1;
}
}
//Run with new list
ans = go(red, goal - coins[i]);
}
}
return ans;
}
This is my code so far. I have made it recursive, yet one of the test cases returns true when it should not. The test case in particular is [111, 1, 2, 3, 9, 11, 20, 30], with the goal doing 8; This should return false (as it cannot add up to 8), but in this case, returns true.
Other test cases work fine, so I believe my code has some sort of an exception.
I have tried to move the base case upward, and make a reverse variation...
boolean go(int[] coins, int goal)
{
boolean ans = false;
if(goal == 0){
return true;
}else if(goal < 0){
return false;
}
for (int i = 0; i < coins.length && (!ans); i++) {
if (goal >= coins[i]) {
int[] red = new int[coins.length - 1];
int it = 0;
for(int x = 0; x < coins.length; x++){
if(!(i == x)){
red[it] = coins[i];
it += 1;
}
}
ans = go(red, goal - coins[i]);
}
}
return ans;
}
is what I've tried, but the base case doesn't seem to affect anything
The bug is in your copying of the coins array: red[it] = coins[i] should really be red[it] = coins[x]...
For time complexity, you don't really have to do a loop inside the method. Each denomination is either part of the sum or not, so you can always remove the first denomination and test with and without it:
boolean go(int[] coins, int goal) {
if(goal == 0)
return true;
else if(coins.length == 0 || goal < 0)
return false;
else {
int[] tailOfCoins = Arrays.copyOfRange(coins, 1, coins.length);
return go(tailOfCoins, goal) || go(tailOfCoins, goal - coins[0]);
}
}

Java Maze Problem - Stack Overflow Error & Maze Matrix Not Updating

I'm attempting to solve a maze problem in Java.
We have a string array. Each character in each string can be empty ("."), have an obstacle ("X"), or have a person. If it has a person, it has you ("A") or it has a stranger. A stranger can be facing east, west, up and down and their entry in the string is represented by arrows with directions. If there's a stranger in a square facing up, the corresponding character will be "^". Similarly, down is "v", left is "<" and right is ">". We want to cross through the maze without running over obstacles or being in the line of vision of a stranger (depending if they're facing up, down, left or right).
Here's what I have right now:
import java.util.*;
class Solution {
public boolean solution(String[] B) {
//make a 2d string array
int numCol = B[0].length();
int[][] Bcopy = new int[B.length][numCol];
int rowA = -1;
int colA = -1;
for(int i = 0; i < B.length; i++) {
for(int j = 0; j<numCol; j++) {
if(B[i].charAt(j) == 'A') {
rowA = i;
colA = j;
}
else if(B[i].charAt(j) == '>') {
for(int upd = j; upd<numCol; upd++){
Bcopy[i][upd] = -1;
}
}
else if(B[i].charAt(j) == '<') {
for(int upd = 0; upd<j+1; upd++){
Bcopy[i][upd] = -1;
}
}
else if(B[i].charAt(j) == 'v') {
for(int upd = i; upd<B.length; upd++){
Bcopy[upd][j] = -1;
}
}
else if(B[i].charAt(j) == '^') {
for(int upd = 0; upd<i+1; upd++){
Bcopy[upd][j] = -1;
}
}
else if(B[i].charAt(j) == 'X') {
Bcopy[i][j] = -1;
}
else if(Bcopy[i][j]==0){
Bcopy[i][j] = 1;
}
}
System.out.println(Arrays.deepToString(Bcopy).replace("],", "],\n"));
}
return helper(Bcopy, rowA, colA);
}
public boolean helper(int[][] copy, int i, int j) {
if(i==copy.length-1 && j==copy[0].length) {
return true;
}
if(copy[i][j]==-1) {
return false;
}
if(i>=copy.length | j>=copy[0].length) {
return false;
}
return (helper(copy, i++, j)) | helper(copy, i, j++) | helper(copy, i--, j) | helper(copy, i, j--);
}
}
My approach is to create an int[][] array, with -1's representing where you can't go and 1 where you can go. Then it goes through all the possible paths and if it runs into something it returns but it does not update BCopy correctly - it only updates the arrows or the X's, but not the lines of sight of people where you can't cross.
My other issue is that I'm getting a stack overflow error.
I figured out why the matrix Bcopy wasn't changing - it didn't account for if that value had already been filled. Fixed the code for that, still stuck on the overflow error.

Explanation of 8-Queen solution Java code.

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!

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;
}

Categories