Reputation:
Note: this problem has been solved, the actual problem is NOT in this method but the other, so if you're searching for something about Sudoku and finally get into this page, you can absolutely use my method below, it works.
Ok, forget about all the complex algorithms used to solve Sudoku. I'm writing a simple solver on Java to solve simple Sudoku games. The idea of this method is very common, so I think everyone knows it already. I'm also surprised that I can't get it done.
The method is to go over every cell on the board and fill in all the cells that have only 1 possibility. Repeat until every cell is filled. Very simple, and here is my code, return int number of fillings can be made:
public int solveGame() {
/*
variable possible contains 10 elements, the first element is true if there
is one or more possible value to fill in, false otherwise. The remaining
elements (1-9) are whether true or false depending on their indexes
e.g. possible[3] is true if 3 is a possibility.
*/
boolean[] possible;
int[] save;
int count;
int numresolve = 0;
while (!isFinished()) {
for (int i = 0; i < GAMESIZE; i++) {
for (int j = 0; j < GAMESIZE; j++) {
possible = new boolean[10];
possible = getPossible(i,j);
if (possible[0]) {
count = 0;
save = new int[9];
for (int k = 1; k < 10; k++) {
if (possible[k]) {
count++;
save[count] = k;
}
}
if (count == 1) {
setCell(i,j,save[count]);
numresolve++;
}
}
}
}
}
return numresolve;
}
The problem of my code is that it can never finish the loop because after filling all the cells that have 1 possibility, the remaining cells will have more than 1 possibility, which is impossible for the loop to be finished.
I know I'm missing something that I can't think of.
Upvotes: 3
Views: 2276
Reputation: 7452
I don't see anything wrong with this code except for the inability to detect that you can't solve the puzzle. The difficulty of the sudokus you are going to be able to solve is obviously dependent on your implementation of getPossible, which isn't posted.
Keep in mind that even "very easy" sudokus are likely to include portions where you have to analyze multiple cells simultaneously, if you can't do this in getPossible you won't be able to solve much of anything:
consider cell 1 == {a, b}, cell 2 = {a, b}, cell 3 = {a, b, c}
cells 3 is solvable and this scenario is likely to occur in the easiest sudokus you are going to find in a book, etc.
what you might want to do is to look at the board after your algorithm is no longer able to solve more cells and then figure out what the missing logic is that will enable your algorithm to solve more cells.
Upvotes: 3
Reputation: 2728
int numresolve = 0;
// this variable will be used to track # of changed cells in each loop
// init to -1 to run loop at least once
// loop can be more elegant if you put the condition at the end
int changed = -1;
// stop loop if no cell changed
while (!isFinished() && changed != 0) {
// initialize # of changed cells in this loop
changed = 0;
for (int i = 0; i < GAMESIZE; i++) {
for (int j = 0; j < GAMESIZE; j++) {
boolean[] possible = getPossible(i,j);
if (possible[0]) {
int count = 0;
int[] save = new int[9];
for (int k = 1; k < 10; k++) {
if (possible[k]) {
count++;
save[count] = k;
}
}
if (count == 1) {
setCell(i,j,save[count]);
numresolve++;
changed++;
}
}
}
}
}
Upvotes: 1
Reputation: 13096
You should use a recursive function, that will finish only when all the cells are filled.
It will happen that there is no cell that have only one possibility, so your code should fork by calling the function itself again tring each of the two (or more) possibilities, until the grid is filled completely.
Upvotes: 2
Reputation: 206689
To detect that you can't solve anything more with this approach, do something like this:
while (!isFinished()) {
int prevResolved = numresolve;
.... // your loop
if (numresolve == prevResolved) {
// did not find anything - out of luck, can't solve this board.
return ...; // numresolve or something to indicate that it failed
}
}
If your algo didn't find anything at all during one loop, then it didn't change the board - so it won't find anything else the next time around.
Alternatively, just set a boolean to false
at the top of the loop, and set it to true
when you make a change to the board. Use that to detect whether your algo found something or not (and bail out if it didn't).
Upvotes: 3
Reputation: 39197
If you fill in a cell (by calling setCell
) you reduce the number of possibilities for all other cells in the same row/column/block. Check that your routine getPossibile
takes into account these changes.
Note also that some puzzles are not solvable using your simple strategy. There might be situations where each open cell allows more than a single value but alltogether there is a unique solution.
Upvotes: 2