I am trying to write a sudoku solver with backtracking right now and I solved some problems already but I don't know what to do now.
This is the Problem:
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 9
at ISudoku.NumberOnBoard(ISudoku.java:19)
at ISudokuSolver.containedinRoC(ISudokuSolver.java:23)
at BacktrackingISudokuSolver.backtracking(BacktrackingISudokuSolver.java:10)
at BacktrackingISudokuSolver.backtracking(BacktrackingISudokuSolver.java:19)
at BacktrackingISudokuSolver.backtracking(BacktrackingISudokuSolver.java:19)
at BacktrackingISudokuSolver.backtracking(BacktrackingISudokuSolver.java:19)
at BacktrackingISudokuSolver.backtracking(BacktrackingISudokuSolver.java:19)
at BacktrackingISudokuSolver.backtracking(BacktrackingISudokuSolver.java:19)
at BacktrackingISudokuSolver.backtracking(BacktrackingISudokuSolver.java:19)
at BacktrackingISudokuSolver.backtracking(BacktrackingISudokuSolver.java:19)
at BacktrackingISudokuSolver.backtracking(BacktrackingISudokuSolver.java:19)
at BacktrackingISudokuSolver.backtracking(BacktrackingISudokuSolver.java:19)
at BacktrackingISudokuSolver.solveSudoku(BacktrackingISudokuSolver.java:4)
at Examples.main(Examples.java:17)
When I run the code
I don't expect to get the right code handed to me, i just appreciate every help.
public class ISudoku {
private boolean[][] sudokuboolean;
private int[][] sudokuboard;
private int size;
public ISudoku(int size){
this.size = size;
sudokuboard = new int[size][size];
sudokuboolean = new boolean[size][size];
}
public void setNumber(int i, int j, int number, boolean given){
sudokuboard[i][j] = number;
sudokuboolean[i][j] = given;
}
public int NumberOnBoard(int i, int j){
return sudokuboard[i][j];
}
public int getSize(){
return size;
}
public String toString(){
String string = "";
for(int i = 0; i < size; i++){
for(int j = 0; j < size; j++){
if(sudokuboolean[i][j]){
string += "<" + sudokuboard[i][j] + "> ";
}
else{
string += sudokuboard[i][j] + " ";
}
if(j == 2 || j == 5){
string += " ";
}
}
string += "\n";
if(i == 2 || i == 5){
string += "\n";
}
}
return string;
}
}
public abstract class ISudokuSolver {
public abstract boolean solveSudoku(ISudoku sudoku);
public boolean containedin3x3(ISudoku sudoku,int row, int col, int value){
int firstRow = row / 3 * 3;
int firstCol = col / 3 * 3;
for(int i = firstRow; i < firstRow+3; i++){
for(int j = firstCol; j < firstCol+3; j++){
if(!(i == row && j == col)){
if(sudoku.NumberOnBoard(i,j) == value){
return true;
}
}
}
}
return false;
}
public boolean containedinRoC(ISudoku sudoku,int row, int col, int value){
for(int i = 0; i < 9;i++){
if(i != col){
if(sudoku.NumberOnBoard(row,i) == value){
return true;
}
}
if(i != row){
if(sudoku.NumberOnBoard(i,col) == value){
return true;
}
}
}
return false;
}
}
public class BacktrackingISudokuSolver extends ISudokuSolver{
public boolean solveSudoku(ISudoku sudoku){
backtracking(0,1,sudoku);
return true;
}
private boolean backtracking(int row,int number, ISudoku sudoku){
for(int i = 0; i < sudoku.getSize();i++){
if(!containedinRoC(sudoku,row,i,number) && !containedin3x3(sudoku,row,i,number)){
sudoku.setNumber(row,i,number,false);
if(row == sudoku.getSize()-1 && i == sudoku.getSize()-1 && number != 9){
number += 1;
}
if(row == sudoku.getSize()-1 && i == sudoku.getSize()-1 && number == 9){
return true;
}
else{
if(backtracking(row+1,number,sudoku)){
return true;
}
else{
sudoku.setNumber(row,i,0,false);
}
}
}
}
return false;
}
}
public class Examples extends BacktrackingISudokuSolver {
public static void main(String[] args) {
ISudokuSolver solver = new BacktrackingISudokuSolver();
ISudoku sudoku = new ISudoku(9);
System.out.println(sudoku);
System.out.println("Beispiel 1: ");
System.out.println("Lösbar? (Erwartet): Ja");
System.out.println("Benötigte Zeit? (Erwartet): 15 ms (Intel i5 3,8 Ghz)");
long start = System.currentTimeMillis();
boolean solvable = solver.solveSudoku(sudoku);
long end = System.currentTimeMillis();
System.out.println("Lösbar?: " + solvable);
System.out.println("Benötigte Zeit: " + (end - start) + " ms");
System.out.println(sudoku);
}
}
Without a line number in the exception, I'm going to blame the i in the second loop conditional in containedin3x3. The body never changes i, so j gets incremented until it goes out of bounds.
for(int i = firstRow; i < firstRow+3; i++){
for(int j = firstCol; i < firstCol+3; j++){
The stack trace in the image you linked appears to implicate this line:
return sudokuboard[i][j];
The error message indicates that the value of the out-of-bounds index is 9.
Supposing that you are solving a 9x9 sudoku, variable sudokuboard will have dimensions 9, 9. In Java, array indices start at 0, so the valid range for both indexes of that array is 0 to 8.
It would take rather more analysis on my part to work out why that method is called with incorrect arguments, as it is; that job would better be handled via a debugger.
Update:
seems to be the problem but i dont know how to change it
Generally speaking, "knowing how to change it" depends on determining just where and how things go pear-shaped. That is one of the things a debugger is useful for, as I already suggested. You really should learn how to use one.
The rest of the stack trace can be useful for that purpose as well. In this case, it implicates this method invocation on line 10 of BacktrackingISudokuSolver.backtracking():
containedinRoC(sudoku,row,i,number)
It doesn't take much study of the code to conclude that the only argument that could be out of bounds is row, whose value was itself an argument to a recursive call to backtracking() at line 19 (referring again to the stack trace). Consider, then, that line and the ones around it:
09 for(int i = 0; i < sudoku.getSize();i++){
10 if(!containedinRoC(sudoku,row,i,number) && !containedin3x3(sudoku,row,i,number)){
11 sudoku.setNumber(row,i,number,false);
12 if(row == sudoku.getSize()-1 && i == sudoku.getSize()-1 && number != 9){
13 number += 1;
14 }
15 if(row == sudoku.getSize()-1 && i == sudoku.getSize()-1 && number == 9){
16 return true;
17 }
18 else{
19 if(backtracking(row+1,number,sudoku)){
20 return true;
21 }
22 else{
23 sudoku.setNumber(row,i,0,false);
24 }
25 }
26 }
27 }
Looking at that code, and at line 19 in particular, do you see any way that this method could have been called with valid arguments, yet perform a recursive call with invalid arguments? That's what you need to fix.
Related
I have been going through some codingbat exercises and I came across this problem.
"Given a string, return the length of the largest "block" in the string. A block is a run of adjacent chars that are the same."
Required Output:
maxBlock("hoopla") → 2
maxBlock("abbCCCddBBBxx") → 3
maxBlock("") → 0
My code seems to pass all the test except for the last one "other test". Can someone please review my code and tell me where exactly I could have gone wrong.
Submitted Code:
public int maxBlock(String str) {
int charBlock = 0;
int holder = 1;
if(str.length() == 0){ //If string is empty return 0
charBlock = 0;
} else if(str.length() == 1){ //If string contains only a single char return 1
charBlock = 1;
} else {
for(int i=0; i < str.length()-1; i++){ //loop through each char value
if((str.length() == 2) && (str.charAt(i) != str.charAt(i+1))){
charBlock =1; //return 1 if the length of the string is 2 and non of the two chars match
}
else if((str.length() == 3) && (str.charAt(i) != str.charAt(i+1))){
charBlock = 1; //return 1 if the length of the string is 3 and non of the three chars match
}
else if (str.charAt(i) == str.charAt(i+1)){
holder = holder + 1;
if(holder > charBlock){
charBlock = holder; //update the value of charBlock if a holder is larger current value
}
} else holder = 1;
}
}
return charBlock;
}
Expected Run
maxBlock("hoopla") → 2 2 OK
maxBlock("abbCCCddBBBxx") → 3 3 OK
maxBlock("") → 0 0 OK
maxBlock("xyz") → 1 1 OK
maxBlock("xxyz") → 2 2 OK
maxBlock("xyzz") → 2 2 OK
maxBlock("abbbcbbbxbbbx") → 3 3 OK
maxBlock("XXBBBbbxx") → 3 3 OK
maxBlock("XXBBBBbbxx") → 4 4 OK
maxBlock("XXBBBbbxxXXXX") → 4 4 OK
maxBlock("XX2222BBBbbXX2222") → 4 4 OK
other tests X
This can be more efficient especially with a helper method! Don't overthink the problem, I know its hard. My strategy is get the block for this char and move on to the next one.
public int maxBlock(String str) {
if (str.length() == 0) {
return 0;
}
int biggest = Integer.MIN_VALUE;
for (int a = 0; a < str.length(); a++) {
biggest = Math.max(biggest, (countBlock(str, str.substring(a, a + 1), a));
}
return biggest; //by now we have the biggest
}
public int countBlock(String s, String any, int startIndex) {
int cnt = 1;
for (int a = startIndex + 1; a < s.length(); a++) { //start right after index
if (s.substring(a, a + 1).contains(any)){ //keep going
cnt++;
}
else if (!s.substring(a, a + 1).equals(any)) { //stop here
break;
}
}
return cnt;
}
Your code is good but you are unnecessarily checking the length of the input string.
Here is your code with some improvements.
public int maxBlock(String str) {
int holder = 1;
int charBlock = 0;
for(int i=0; i < str.length()-1; i++){ //loop through each char value
if (str.charAt(i) == str.charAt(i+1)){
holder++;
}else{
holder = 1;
}
if(holder > charBlock){
charBlock = holder; //update the value of charBlock if a holder is larger current value
}
}
return charBlock;
}
public class SomeQueens {
static Stack<Integer> s= new Stack<Integer>();
static int Solved = 0;
static int current = 0;
public static int solve(int n) { // n is 8
while(current < n) { // should I use current < n instead
for (int i = current; i < n; i++) {
if(validPosition(i)) {
s.push(i);
current = 0;
}
}
if(!validPosition(current)) {
if(s.empty()) {
break;
}
if(!s.empty()) {
s.pop();
current++;
}
}
if(s.size() == n) {
s.pop();
current++;
printSolution(s);// this is a method, but it shouldn't matter for this
Solved++;
}
}
return Solved;
}
public static boolean validPosition(int column) {
for( int row = 0; row < s.size(); row++)
if(s.get(row) == column || ((column - s.get(row)) == (s.size() - row)) ||
((s.get(row) - column) == (s.size() - row)) )
return false; // there's a conflict
return true; // no conflict;
}
//it's called by int num = solve(n);
//sop("There're" + num + "sols to the" + n "queens prob");
This is a subsection of my program for NQueens, but I seem to always get: There are 0 solutions to the 8-queens problem. I tried debugging with system.out.prints in the main method, which led me to guess that there would be something wrong in my boolean method, but I don't think it's doing anything wrong.
I'm unsure if my while statement is incorrect or if the break inside the while loop is initialized before anything is even done. Thanks for the help and guidance and I'm sorry if my program and explanation makes no sense
Here is why you instantly get a zero:
s.push(0);
while(s.size() > n) // n is 8
{
//...
}
return Solved;
When the program arrives at the while-condition s has a size of one and n is 8. This will instantly fail and cause the method to return a zero.
But that's not the only problem with the algorithm. You should seriously rethink it.
I have a java method like
void getSumAtPrime(int[] n, int n_limit){
System.out.println("limit:"+n_limit);
for(int j=0; j<n_limit; j++){
if(getPrime(j)){
System.out.println(n[j]);
}
}
Which will print prime indexed array elements using getPrime()
and my getPrime() method is like
boolean getPrime(int numi){
boolean flag=false;
for(int i=2;i<numi;i++){
if(numi%i==0) {
flag = true;
break;
}
}
return flag;
}
but now it is only printing numbers from 5 for example if i enter 1,2,3,4,5,6,7,8,9 it will print 5,7,8. I couldn't find the problem, someone please help me to fix this
boolean getPrime(int p){
if(p < 2) return false;
if(p == 2 || p == 3) return true;
if(p % 2 == 0) return false;
for(int i = 3; i <= Math.ceil(Math.sqrt(p)); i += 2){
if(p % i == 0) {
return false;
}
}
return true;
}
try this :
void getSumAtPrime(int[] n, int n_limit) {
System.out.println("limit:"+n_limit);
for(int j=0; j < n_limit; j++) {
if(getPrime(j))
System.out.println(j + " : " + n[j]);
}
}
boolean getPrime(int numi) {
if ( n < 2) return false;
for(int i=2; i < numi; i++)
if(numi%i==0) return false;
return true;
}
Your question was why you are getting 5 as the first output.
Well because in your getPrime method, you are checking if(numi%i==0) . Which will be true for 2,4,6 and 8.
Now, in your for loop you have for(int i=2;i<numi;i++){ so "2" is not satisfying the i<num1 check.
So we get 4,6,8 indices for which the method returns true.
Now, you are printing n[j], so you get
n[4] = 5 n[6] = 7 n[8] = 9
What is the concern now?
P.s I just answered the doubt. Whether whatever you are doing is
correct or not, is out of scope here.
void getSumAtPrime(int[] n, int n_limit){
System.out.println("limit:"+n_limit);
for(int j=0; j<n_limit; j++){
if(getPrime(j)){
System.out.println(n[j]);
}
}
//method to get prime or not
public boolean getPrime(int numi){
int i, res;
boolean flag=true;
for(i=2;i<=numi/2;i++)
{
res=numi%i;
if(res==0)
{
flag=false;
break;
}
}
return flag;
}
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;
}
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