the reason why I am creating this new thread instead of just reading the answers to this particular question that have been given before is that I feel I just don't fully understand the whole idea behind it. I can't seem to get my head around the whole backtracking concept. So I need to fully understand backtracking and then solve the particular sudoku problem.
What I understand so far is that backtracking is a technique to go back, in (e.g.) a recursive flow if one discovers that decisions made prior to the current state led to a dead end. So you go back try something else and continue again.
So in my sudoku example I pick the first empty cell and try to fill in a natural number out of {1...9} that doesn't conflict with the well know sudoku rules. Now I do the same thing with the next empty cell until I get to the point where no valid number may be inserted without conflicts. As of my understanding this should be the point where backtracking comes into play. But how? If I use recursion to go back to the last written cell the algorithm will fill in the number again, continue and end up stuck in an endless loop.
So I searched the Internet for hints and found this to be a quite well documented and frequently solved problem. Yet many solutions claim to use backtracking I don't see how or where they do it even if I have the source code right in front of me.
Examples are: Sudoku solver in Java, using backtracking and recursion or http://www.heimetli.ch/ffh/simplifiedsudoku.html
Here is my (not working) source code:
private boolean isSolvable( Sudoku sudoku, int row, int col ){
//if the method is called for a row > 8 the sudoku is solved
if(row > 8)
return true;
//calculate the next cell, jump one row if at last column
int[] nextCell = (col < 8) ? new int[]{row,col+1} : new int[]{row+1,0};
//check if the current cell isWritable() that is if it is not a given cell by the puzzle
//continue recursively with the next cell if not writable
if(!sudoku.isWritable(row, col))
isSolvable(sudoku, nextCell[0], nextCell[1]);
else{
//set the current cell to the lowest possible not conflicting number
for(int i=1; i< 10; i++){
if(!conflictAt(sudoku, row, col, i)){
sudoku.setValue(row, col, i);
//continue recursively with the next cell
isSolvable(sudoku, nextCell[0], nextCell[1]);
}
}
}
return false;
}
Now I don't know how to continue. How to implement the backtracking or did I already? This seems like a stupid question but I really don't see more backtracking going on in source codes mentioned in the links above.
EDIT: Final (working) version:
private boolean isSolvable( Sudoku sudoku, int row, int col ){
//if the method is called for a row > 8 the Sudoku is solved
if(row > 8)
return true;
//if the cell is not writable, get the next writable cell recursively
if(!sudoku.isWritable(row,col))
return isSolvable(sudoku, (col<8) ? row : row + 1, (col<8) ? col + 1 : 0);
//brute forcing for solution
for(int i=1; i<=9; i++){
if(!conflictAt(sudoku, row, col, i)){
sudoku.setValue(row, col, i);
if(isSolvable(sudoku, (col<8) ? row : row + 1, (col<8) ? col + 1 : 0)) return true;
}
}
sudoku.setValue(row, col, 0);
return false;
}
I am just going to give an explanation of what backtracking means.
Recursion means to call the function from within that same function. Now what happens is that when the function encounters a call to itself.. imagine that a new page opens up and control is transferred from the old page onto this new page to the start of the function, when the function encounters the call again in this new page, another page opens up beside it and in this way new pages keep popping up beside the old page.
The only way to go back is using return
statement. When the function encounters it the control goes from the new page back to the old page on the same line from where it was called and starts executing whatever is below that line. This is where backtracking starts. In order to avoid issues like feeding data again when its filled up you need to put a return statement after every call to the function.
For e.g in your code
if(row > 8)
return true;
This is the base case. When its true, the function starts backtracking i.e control goes back from the new page to the old page BUT it goes back to from wherever it was called. If for e.g it was called from this statement.
for(int i=1; i< 10; i++){
if(!conflictAt(sudoku, row, col, i)){
sudoku.setValue(row, col, i);
//continue recursively with the next cell
isSolvable(sudoku, nextCell[0], nextCell[1]); <------ here
}
it will go back to this line and start doing whatever it should. This statement is inside the for loop and if i < 10
the loop will run and it will try to set values again. That's not what you want, you want it to keep backtracking till it exits the function because sudoku is filled up right? In order to do that you need to put a return
statement after this call i.e return true;
I haven't read your code so there might be many more mistakes like that.