11

I'm having issues with my logic solving algorithm. It solves puzzles with a large number of hints very well, it just has issues with puzzles that have less than 45 clues.

This is the algorithm for solving. Immutable is a boolean that determines whether or not that value can be changed. cell[row][col].possibleValues is a LinkedList within a class called SudokuCell that stores the values that are possible for that grid element. grid.sGrid is the main int[][] array of the puzzle. removeFromCells() is a method that removes values from the row, column, and quadrant of the grid. That code is provided further down.

The second for loop is just for checking for a single solution. I decided to avoid recursion because I really can't get my head around it. This method seems to be working well enough for now.

public boolean solve(){

    for(int i = 0; i < 81; i++){
        for(int row = 0; row < 9; row++){
            for(int col = 0; col < 9; col++){
                if(!immutable[row][col]){
                    if(cell[row][col].getSize() == 1){
                        int value = cell[row][col].possibleValues.get(0);
                        grid.sGrid[row][col] = value;
                        immutable[row][col] = true;
                        removeFromCells(row, col, value);
                    }
                }
            }
        }
    }


    int i = 0;
    for(int row = 0; row < 9; row++){
        for(int col = 0; col < 9; col++){
            if(grid.sGrid[row][col] == 0){
                i++;
            }
        }
    }

    if(i != 0){
        return false;
    } else{
        return true;
    }
}

This is the code for removeFromCells()

I think most of the code is pretty self-explanatory. The first for loop removes the value from the row and column of (x, y), and the second loop removes the value from the quadrant.

public void removeFromCells(int x, int y, int value){

    /*
     * First thing to do, find the quadrant where cell[x][y] belong.
     */

    int topLeftCornerRow = 3 * (x / 3) ;
    int topLeftCornerCol = 3 * (y / 3) ;

    /*
     * Remove the values from each row and column including the one
     * where the original value to be removed is.
     */
    for(int i = 0; i < 9; i++){
        cell[i][y].removeValue(value);
        cell[x][i].removeValue(value);
    }


    for(int row = 0; row < 3; row++){
        for(int col = 0; col < 3; col++){
            cell[topLeftCornerRow + row][topLeftCornerCol + col].removeValue(value);
        }
    }
}

Another problem spot could be where the possible values are constructed. This is the method I have for that:

The first for loop creates new SudokuCells to avoid the dreaded null pointer exception.

Any null values in sGrid are represented as 0, so the for loop skips those.

The constructor for SudokuBoard calls this method so I know it's being called.

public void constructBoard(){

    for(int row = 0; row < 9; row++){
        for(int col = 0; col < 9; col++){
            cell[row][col] = new SudokuCell();
        }
    }

    immutable = new boolean[9][9];

    for(int row = 0; row < 9; row++){
        for(int col = 0; col < 9; col++){
            immutable[row][col] = false;
            if(grid.sGrid[row][col] != 0){
                removeFromCells(row, col, grid.sGrid[row][col]);
                immutable[row][col] = true;
            }
        }
    }
}

I would post the entire file, but there are a lot of unnecessary methods in there. I posted what I think is causing my problems.

SkylineAddict
  • 189
  • 1
  • 2
  • 13

2 Answers2

6

You seem to have built only a simple constraint based solved for now. You need a full backtracking one in order to solve puzzles with less hints. There are some cases that you can't really solve without backtracking.

Alternatively you should try to implement Knuth's algorithm (Dancing Links) for solving this type of problems. It's more complicated to understand and implement than a backtracking algorithm but it's running way better :). See here: http://en.wikipedia.org/wiki/Dancing_Links

It's also an algorithm for a more general problem and it was applied to solving sudoku quite successfully.

On wikipedia there is a link to an article detailing what type of instances are possible to solve using constraints programming: http://4c.ucc.ie/~hsimonis/sudoku.pdf (found from here: http://en.wikipedia.org/wiki/Sudoku_algorithms). The Table 4 is really interesting :).

Mihai Toader
  • 12,041
  • 1
  • 29
  • 33
  • I have a brute force algorithm written which solves anything thrown at it. The reason I'm writing this is because I want an algorithm that can test for a single solution. Correct me if I'm mistaken, but isn't this method that I'm using widely used in logic solvers? – SkylineAddict Mar 08 '11 at 19:03
  • 2
    I've found backtracking with forward checking to be fast enough and considerably easier to implement that dancing links. – Fred Foo Mar 08 '11 at 19:04
  • @skyline Some instances of Sudoku can't really be solved without backtracking from what i know. If you want to be able to home in directly on a solution for every instance i'm not sure a logic solver will work. – Mihai Toader Mar 08 '11 at 19:05
  • @larsmans I agree that the Dancing Links algo is not really easy to implement. If backtracking with forward checking worked for you than the op should try it too. – Mihai Toader Mar 08 '11 at 19:07
  • @SkylineAddict: This method works well for most puzzles that you'll find out there, because most human beings aren't willing to do puzzles that require them to guess and backtrack. But it should be possible to create a Sudoku puzzle where you won't discover that your guess was wrong until it leads you to an impossible conclusion. – StriplingWarrior Mar 08 '11 at 19:11
  • Is there a better method to checking what values are possible at a certain square? I realized that, as Toader and Stripling said, my method is correct in determining the possible values for a square, it just won't solve more difficult puzzles. – SkylineAddict Mar 08 '11 at 19:34
  • @skyline check the pdf i linked to inside the post. It seemed to me to be extremely comprehensive and it should point you to all better known algorithms used to solve sudoku by logic – Mihai Toader Mar 09 '11 at 09:31
  • I'd like to add that the Dancing Links is technically a backtracking algorithm. The clever data structure is the only advantage. Otherwise it's just a bruteforce on steroids. – st0le Mar 09 '11 at 11:00
  • For logic reasons, it must be possible to solve a sudoku without backtracking, I guess. They are determined from the beginning, you just need to create bigger and bigger constraints, which can cause headaches. I didn't made it. :) For performance reasons, backtracking or an optimized brute-forcing work well enough, but it should be possible, to create a more sophisticated program. – user unknown Mar 18 '11 at 09:50
  • As far as I understand sudoku, one of the requirements is that solving it does not require backtracking. In each step, there is always a rule that allows you to make a move. So backtracking should not be necessary, but perhaps it's easier than some more sophisticated rules ("butterfly"). – Kris Mar 18 '11 at 12:01
2

I used many such rules to develop my sudoku solver. Yet I always ended up forced to use backtracking for very hard sudokus. According to wikipedia, some sudokus are effectively impossible to solve by using only rules.

I implemented a total of 6 rules.

  1. No other value is allowed..
  2. A certain value is allowed in no other square in the same section.
  3. A certain value is allowed in no other square in the same row or column.
  4. A certain value is allowed only on one column or row inside a section, thus we can eliminate this value from that row or column in the other sections.
  5. Naked pairs
  6. Lines

I described the whole algorithm and gave the code in these two blog posts (the initial version only used the first 4 rules).

http://www.byteauthor.com/2010/08/sudoku-solver/

http://www.byteauthor.com/2010/08/sudoku-solver-update/

PS. My algorithm was geered towards performance so it automatically balances backtracking with these rules even though it could sometimes do without any guessing.

Kevin Coulombe
  • 1,517
  • 1
  • 17
  • 35