Skip to content

tsathis/a-sudoku-solver.cpp

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

4 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

A Sudoku Solver using C++ [experimental]

Algorithm

The Sudoku puzzle can be represented as a 9x9 or 16x16 matrix. In addition to the puzzle matrix, another matrix allowed-values is maintained which holds the possible valid values for each of the empty cells. Once an empty cell named cell is filled with a value new-value, the allowed-values matrix is also updated according to the basic rules of Sudoku; (i)The new-value is disallowed for each other cells in the same row, column, and block, (ii) Allowed values set of the cell is emptied. After the puzzle matrix and allowed-values matrices are initialized based on the original input, then each empty cell is filled gradually by a recursive function ([F1]).

Solve-Puzzle (puzzle, allowed-values, cell, new-value)                              [F1]
    if: Solved ( puzzle )
        return: TRUE
    puzzle [ cell ] ⟵ new-value
    Update-Allowed ( puzzle, &allowed-values, cell ) 
    cell ⟵ Get-Next-Empty-Cell ( puzzle, allowed-values )                           [F2]
    foreach: new-value ∈ Get-Next-Possible-Values ( puzzle, allowed-values, cell )  [F3]
        if: new-value ∈ allowed-values [ cell ]
            return: Solve-Puzzle ( puzzle, allowed-values, cell, new-value )
    return: FALSE

In a single call of this function, a single empty cell is updated. This function takes a cell and a new value to the cell as well as the current state ( puzzle ) and current constraints ( allowed-values ). After the new value is set to the cell, then the allowed-values matrix is updated to be ready for processing the next empty cell. A new-value is chosen for the next cell and if that value is valid (available in allowed-values), the function is called again for that cell and value and continues recursively. If the successive recursive calls together fail to fill the whole puzzle, then continues with the next possible new-value value. It is very important to reduce the total number of recursive calls of the above function. The strategy used here to reduce recursive calls is limiting the search space by selecting the next empty cell to fill and the next new-value to try, as stable as possible. Therefore, the need to back-track and update a filled value again will be reduced.

Get-Next-Empty-Cell ( puzzle, allowed-values )                                      [F2]
    foreach: cell ∈ Empty-Cells ( puzzle )
        variance-scores [ cell ] ⟵ [ 
                        Count ( allowed-values [ cell ] ),
                        Count ( Σ allowed-values [ row |column | block of cell ] ), 
                    ]
    return: cell of Min ( variance-scores )

The empty cell with a minimum estimated variability is chosen as the next cell. The variability is calculated based on the counts of the total allowed value (i) for the given cell, and (ii) for the give cell’s neighbours (cells within the same row, column or block) (see function [F2]). The assumption here is that if the variability is lesser, then a change to that cell will be more stable.

Get-Next-Possible-Values ( puzzle, allowed-values, cell )                           [F3]
    possible-values ⟵ allowed-values [ cell ]
    foreach: value ∈ possible-values
        variance-scores [ value ] ⟵ Count ( puzzle [ value ] ),
    return: values of Sorted ( variance-scores )

The order of the new values to be tried is also decided by estimating the variability of values. Here, a simple assumption is used based on the fact that each value must have the same count in the solved puzzle. It is assumed that if a value is lesser appeared in the current state of puzzle, then it is more stable to be used to fill the next cell. Therefore, the values are prioritised (sorted) on their counts and use as the array of possible values to be tried.

Results

On average, the algorithm able to solve a puzzle of any number of empty cells with a total number of recursive calls less than twice of the empty cells count. For 16x16 puzzles, the algorithm performs better when the number of empty cells is below 160; and also, the time cost is very low for most of the inputs; and, for 16x16 inputs with <180 number of empty cells, the total time consumption is very lower.

graph

Sample run

tharindu@tharindu-pc:~/tmp/a-sudoku-solver.cpp$ ./test.sh
$ [START] /home/tharindu/tmp/a-sudoku-solver.cpp/sample_inputs/input1.txt

Input:
  0  2  0  0  0  7  5  0  8
  0  0  7  0  0  0  3  0  0
  1  0  0  0  0  2  0  6  0
  0  0  5  0  0  0  4  0  0
  0  3  0  8  1  6  0  0  0
  0  0  0  4  0  0  0  8  0
  5  0  0  0  6  1  8  0  0
  0  0  3  0  4  0  6  0  0
  9  0  0  5  7  0  0  4  0

Output:
  3  2  4  6  9  7  5  1  8
  6  5  7  1  8  4  3  2  9
  1  9  8  3  5  2  7  6  4
  8  6  5  7  2  9  4  3  1
  4  3  9  8  1  6  2  5  7
  2  7  1  4  3  5  9  8  6
  5  4  2  9  6  1  8  7  3
  7  1  3  2  4  8  6  9  5
  9  8  6  5  7  3  1  4  2


$ Total Zeros in input : 53
$ Total Recursive calls: 55
$ Calculation Time     : 0.000128 s
$ Total Program Time   : 0.000334 s
$ [DONE]
$ [START] /home/tharindu/tmp/a-sudoku-solver.cpp/sample_inputs/input2.txt

Input:
  0  1  0  0  0  0  8  7  0
  0  0  0  0  0  0  4  0  1
  0  7  6  0  0  0  0  0  0
  9  0  0  0  0  0  0  0  5
  1  0  0  8  0  4  7  0  6
  0  6  0  0  0  0  0  0  0
  0  0  0  0  7  5  0  0  4
  0  0  0  1  4  0  0  9  0
  0  5  0  2  0  9  1  3  0

Output:
  5  1  3  4  6  2  8  7  9
  8  2  9  7  5  3  4  6  1
  4  7  6  9  1  8  2  5  3
  9  4  8  6  2  7  3  1  5
  1  3  5  8  9  4  7  2  6
  7  6  2  5  3  1  9  4  8
  2  9  1  3  7  5  6  8  4
  3  8  7  1  4  6  5  9  2
  6  5  4  2  8  9  1  3  7


$ Total Zeros in input : 55
$ Total Recursive calls: 72
$ Calculation Time     : 0.00016 s
$ Total Program Time   : 0.000352 s
$ [DONE]
$ [START] /home/tharindu/tmp/a-sudoku-solver.cpp/sample_inputs/input3.txt

Input:
  0  9  0  0  0  0  6  0  0
  2  0  0  0  0  8  0  0  7
  0  0  7  0  0  0  0  9  0
  0  0  8  0  9  0  0  1  0
  0  5  0  0  0  2  0  0  0
  6  0  0  3  0  0  0  0  4
  0  0  1  0  5  0  0  8  0
  9  0  0  4  0  0  0  0  3
  0  6  0  0  0  7  1  0  0

Output:
  8  9  5  7  2  3  6  4  1
  2  4  6  9  1  8  5  3  7
  1  3  7  5  4  6  8  9  2
  7  2  8  6  9  4  3  1  5
  4  5  3  1  7  2  9  6  8
  6  1  9  3  8  5  2  7  4
  3  7  1  2  5  9  4  8  6
  9  8  2  4  6  1  7  5  3
  5  6  4  8  3  7  1  2  9


$ Total Zeros in input : 57
$ Total Recursive calls: 1616
$ Calculation Time     : 0.00244 s
$ Total Program Time   : 0.00266 s
$ [DONE]
$ [START] /home/tharindu/tmp/a-sudoku-solver.cpp/sample_inputs/input_hex1.txt

Input:
 12  0  8  9  0  6 15  0  4  0  0 11 14  0 13  1
  0  0  5  0  0  8  0  0  0 13  0 16 11  0  0  3
 11  0  0  0  0  0  0  0  0  0  0  5  4  8  0  0
  0  0  6  0  0  0 10 16  0  0  0  0  0  0  0  9
  0  5  0  0 12  9  0  0  0 15  0  8 10  4  0  0
  0  0 15  4  8 13  0  0  0  0 16 14 12  0  0  5
 10 16  0  8  0  0  6 14  0  4  0  0  0  0  9  0
  6  0  0 14  0 16  4  0  3  5 11  9 13  0  1  0
  0  9  0  0  0  0  0  0 12  0  0  0  0  1 14  6
  0  0 14  0  0  0  0  0  0  9  0  0 16  0 15  0
  0  0 11  0 10  0 16  0  0  7  8  0  0  0 12 13
  0  0  0 13  0 11 12  0  0  0  0 15  8  3  5  0
  8 11  0 10  0 12  2  0  0  0  6  0  0  7  4  0
 14  0 13 15 16  0  8  0 11  0  0  0  0  9  0  0
  0  0  0  0 15  0 11  0  0 14  0  0  6  0  0  0
  0  7  4  6  1 10 13  0  0 12  0  0 15  0  0  0

Output:
 12 10  8  9  2  6 15  5  4  3  7 11 14 16 13  1
  1 15  5  2  4  8 14  7  9 13 10 16 11 12  6  3
 11 14 16  7 13  3  9 12  1  6  2  5  4  8 10 15
  4 13  6  3 11  1 10 16 14  8 15 12  2  5  7  9
 13  5  7 11 12  9  3  2  6 15  1  8 10  4 16 14
  9  3 15  4  8 13  1 11  7 10 16 14 12  6  2  5
 10 16  1  8  5 15  6 14 13  4 12  2  3 11  9  7
  6  2 12 14  7 16  4 10  3  5 11  9 13 15  1  8
 15  9 10 16  3  2  5  8 12 11 13  4  7  1 14  6
  5  8 14 12  6  4  7 13  2  9  3  1 16 10 15 11
  3  4 11  1 10 14 16 15  5  7  8  6  9  2 12 13
  7  6  2 13  9 11 12  1 10 16 14 15  8  3  5  4
  8 11  9 10 14 12  2  3 15  1  6 13  5  7  4 16
 14 12 13 15 16  5  8  6 11  2  4  7  1  9  3 10
  2  1  3  5 15  7 11  4 16 14  9 10  6 13  8 12
 16  7  4  6  1 10 13  9  8 12  5  3 15 14 11  2


$ Total Zeros in input : 150
$ Total Recursive calls: 152
$ Calculation Time     : 0.000684 s
$ Total Program Time   : 0.000967 s
$ [DONE]
$ [START] /home/tharindu/tmp/a-sudoku-solver.cpp/sample_inputs/input_hex2.txt

Input:
 14  0  7  2  0  0 10  0  0  3  0  0  6  0  0  1
 13  0  0  0  0  2  0  0  0  0  0  0  0  0 16  0
 12  0  0  0  0  1  0  3 14  0  0  0  4  5  0  9
  9 10 15  0  0  0  0  0  5  0  1  0  0 13 11  0
  0 16  0  1  0  0  0 14  2  6  0  9  3 12 10  4
  0  7 10  0  8  0  1 12  4 11  0  0  0  0  9  0
  0  3  0 14  2  0  0 15  0  0  0 12  0  0 13  6
 11  0  0  0 13  0  3  0 15  1  5  0 16  0  0  0
  0  0  0 16  0 12  2  9  3  0  0  0  0  0  0  0
  0  5  0  6 11  0  0  8  0 13 14  1  9  0  0 16
  0  0  9  0  0  0  0 13  0  0  8  0  0  0  5  3
 10  0  0 15  3  6  0  0  0 16  4  0  0  8 14  0
  0 14  3  4  0  0  0  0  0  0 15 11  1  0  0  0
  5  9 11  0  0  0 15  0  0  0  6 16 12  0  4  7
  0 15  6  8 12  0 16  0  0  0  0  0  0  0  0  0
  0  0  0  0  0  0  0  0  0  0  0  0  8  0  3  0

Output:
 14  8  7  2  4  9 10  5 16  3 11 13  6 15 12  1
 13  1  4  5 14  2 11  7  6  9 12 15 10  3 16  8
 12  6 16 11 15  1 13  3 14  2 10  8  4  5  7  9
  9 10 15  3  6  8 12 16  5  4  1  7 14 13 11  2
 15 16  8  1  5 11  7 14  2  6 13  9  3 12 10  4
  6  7 10 13  8 16  1 12  4 11  3 14 15  2  9  5
  4  3  5 14  2 10  9 15  8  7 16 12 11  1 13  6
 11  2 12  9 13  4  3  6 15  1  5 10 16  7  8 14
  8  4 14 16 10 12  2  9  3 15  7  5 13  6  1 11
  3  5  2  6 11  7  4  8 12 13 14  1  9 10 15 16
  1 12  9  7 16 15 14 13 11 10  8  6  2  4  5  3
 10 11 13 15  3  6  5  1  9 16  4  2  7  8 14 12
  2 14  3  4  9  5  8 10  7 12 15 11  1 16  6 13
  5  9 11 10  1  3 15  2 13  8  6 16 12 14  4  7
  7 15  6  8 12 13 16  4  1 14  9  3  5 11  2 10
 16 13  1 12  7 14  6 11 10  5  2  4  8  9  3 15


$ Total Zeros in input : 151
$ Total Recursive calls: 153
$ Calculation Time     : 0.000665 s
$ Total Program Time   : 0.000981 s
$ [DONE]
$ [START] /home/tharindu/tmp/a-sudoku-solver.cpp/sample_inputs/input_hex3.txt

Input:
  0 15  1  0  4 16 12  0  0  5  0  9  7  0  0  8
  0  0  0  0 11  0 15  3  0  0 13  0  0  0 16  0
  0  0  7  3  0  0 10  6 11  0 14  0  0  0  0  9
  0  0 14  0  0  0  7  0 16  4  0  0  0  0  0 13
  0  0 16  0  8  0 13  0  1  0  6  0  0 15  5 11
 14 11 12  8  0  0  0 15  2 13  4  0 16  0  0  7
 15 13  4  0 14  0  5  0  0  0  0  0  0  0  0  3
  0  9  0  0  0  0 11  0  0  0  0 14  0  0  6 12
  0  0  0  0  2  6  0  5 10 16 12  8  9  0  0 15
  0  0  0  0 15  0  0  0  0 14  0  3  0  0  0  0
  8  0 11  0  0  0 16  0 13 15  0  0  0  0  0 10
  0  0  0  7  0 13  0 10  9  0  0  0  0 16 12  0
 16  7  0 13  6 12  0  0  0 10  0  0  0  0  9  0
 12  0  5 15  0  0 14 16  8  0 11  0  0  0  0  0
  0  2  3  0  0  9  0  0 12  0  0  1  0  0 10  0
  0  0  0 10  0  0  0 11  4  0  0  6  0 13  8  0

Output:
 13 15  1 11  4 16 12  2  3  5 10  9  7  6 14  8
  9  8  2 12 11 14 15  3  6  1 13  7  5 10 16  4
  4 16  7  3 13  5 10  6 11  8 14  2  1 12 15  9
  6 10 14  5  9  8  7  1 16  4 15 12  2  3 11 13
  7  3 16  2  8  4 13  9  1 12  6 10 14 15  5 11
 14 11 12  8 10  3  6 15  2 13  4  5 16  9  1  7
 15 13  4  6 14  1  5 12  7 11  9 16 10  8  2  3
  5  9 10  1 16  2 11  7 15  3  8 14 13  4  6 12
  3  4 13 14  2  6  1  5 10 16 12  8  9 11  7 15
 10 12  6 16 15 11  9  8  5 14  7  3  4  2 13  1
  8  1 11  9 12  7 16 14 13 15  2  4  6  5  3 10
  2  5 15  7  3 13  4 10  9  6  1 11  8 16 12 14
 16  7  8 13  6 12  2  4 14 10  3 15 11  1  9  5
 12  6  5 15  1 10 14 16  8  9 11 13  3  7  4  2
 11  2  3  4  5  9  8 13 12  7 16  1 15 14 10  6
  1 14  9 10  7 15  3 11  4  2  5  6 12 13  8 16


$ Total Zeros in input : 151
$ Total Recursive calls: 153
$ Calculation Time     : 0.000726 s
$ Total Program Time   : 0.00116 s
$ [DONE]

About

Yet another sudoku solver using c++

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published