3

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.

  • 7
    Not all Sudoku puzzles can be solved by simply filling squares with 1 possibility. – ShreevatsaR May 21 '11 at 09:23
  • of course, but i've tried quite a few simple games already :) –  May 21 '11 at 09:24
  • Note that once a cell allows all nine numbers your value `count` will be `9` and thus you are accessing array element `save[9]` which does not exist (save was initialized as `int[9]`). – Howard May 21 '11 at 09:34
  • Ok I can int[] save = int[10], but that's not related to my question anyway :) –  May 21 '11 at 09:41
  • @Tris Le: a regular backtracking algo is very short and not that hard at all to write and it's going to be a very interesting experiment. – SyntaxT3rr0r May 21 '11 at 10:23
  • 1
    Hi everyone, I've solved the algo, the problem isn't in this method but because I forgot to filter possibility by 3x3 square. Really appreciate your help, so I will up vote for everyone who attempted to help me :) –  May 23 '11 at 03:43

5 Answers5

3

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).

Mat
  • 202,337
  • 40
  • 393
  • 406
  • Your solution is used to detect whether (complex) games can be solved. My method aims at solving very easy games that are tested to be claimed very easy :) There for I assume that the games can be solved after the loop. However, they didn't –  May 21 '11 at 09:30
  • 1
    I don't understand: are you saying that you input a game board that you _know for sure_ is solvable, and your solver isn't returning? If that is the case, how did you make sure that the algorithm is indeed capable of solving them? Unless the puzzles are really trivial, that's not easy to do. – Mat May 21 '11 at 09:43
3

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.

Yaur
  • 7,333
  • 1
  • 25
  • 36
2

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.

Howard
  • 38,639
  • 9
  • 64
  • 83
  • I've checked already, getPossible() still returns the right answer for the possibilities. –  May 21 '11 at 09:27
  • @Tris Le This is want I meant. Either your `getPossible` is not taking into account reduced possibilities or there is no solution to the puzzle with your algorithm. Use a debugger or print out the state of all cells (i..e the return array of `getPossible`) and check by hand which of the two cases applies. – Howard May 21 '11 at 09:32
  • Actually I have 1 method to print the current state of the game, I used it to test the method above so I know it's not a problem with getPossible. –  May 21 '11 at 09:34
  • 1
    @Tris Le And thus your puzzle is not solvable (and the loop cannot terminate). – Howard May 21 '11 at 09:36
  • No it's solvable :) There are hundred available solvers online for me to check whether it's solvable or not :) I think the problem is in my method above. –  May 21 '11 at 09:42
  • 2
    @Tris Le With "not solvable" I meant that your simple scheme does not allow to solve this puzzle (as also others mentioned there are puzzles with unique solutions where your algorithm fails). If there is no cell with a unique number (which you confirmed just before) but not all cells are filled then this is the case. – Howard May 21 '11 at 09:45
  • 2
    @Howard: I get the feeling that the original poster is not getting it and refuses to accept your logical thoughts. – Hovercraft Full Of Eels May 21 '11 at 10:09
  • @Hovercraft Full Of Eels: Everyone needs time to think and I have my own logical thoughts too, I know exactly what he was trying to explain to me, but the problem is not in this range of logic, so your comment is not very logical as it doesn't cover every aspect of the situation. @Howard: many thanks for your reply, I've solved this problem anyway, it was my mistake not the problem with the algo :) See my comment on why post though, upvoted. –  May 23 '11 at 03:48
  • @BeingSimpler You're welcome. I'm happy if I could help you finding the issue although somehow indirectly ;-) – Howard May 23 '11 at 05:07
2

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.

BFil
  • 12,966
  • 3
  • 44
  • 48
  • I know what you mean by recursion but in this case, I don't think it's different to the method I'm using now. Can you be more specific with your answer? –  May 21 '11 at 09:36
  • With a recursive function it would be easier to fork the code to handle the times when all the remaining cells have 2 or more possibilities. Your code doesn't handle this cases, and even if you'd be able to modify it accordingly, your code would likely become messy.. Simple is better =D – BFil May 21 '11 at 10:11
1
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++;
                }
            }
        }
    }
}
ymajoros
  • 2,454
  • 3
  • 34
  • 60