NAME
Games::Sudoku::PatternSolver - Solve, generate and play Sudoku 9x9 grids.
DESCRIPTION
A Sudoku solver and generator. It works by application of the pattern overlay method (POM) in a backtracking process.
Lists of generated puzzles may get exported to html and can be played in a browser.
Note: For this module the term 'pattern' refers to a 9x9 matrix, holding the final 9 positions of any single symbol.
SYNOPSIS
use Games::Sudoku::PatternSolver qw( solve );
$result = solve( '.2.4.6.8....2......9......1..4......51.....9.....4.5.335..6....9...823.5..1.....8' );
print_grid( $result->{solutions}[0] );
use Games::Sudoku::PatternSolver::Generator qw(get_grid_builder get_sudoku_builder);
$grid_builder = get_grid_builder();
$solution = &$grid_builder( $do_shuffle );
$generator = get_sudoku_builder( $solution );
$sudokuHash = &$generator();
use Games::Sudoku::PatternSolver::PlayerIF qw( sudoku_html_page );
@list = ( [$sudokuHash->{strPuzzle}, "<descriptive text with properties, rating, source, etc.>"], ... )
$htmlpage = sudoku_html_page( \@list )
MODULES AND UTILITIES
PatternSolver
Games::Sudoku::PatternSolver can solve any standard 9x9 puzzle.
It is unique in that it tries to find a combination of 9 out of 46656 unique patterns in which a number may be placed on the grid. And if a faulty puzzle has very many solutions the solver will find them all, given sufficient time and computer memory and $MAX_SOLUTIONS is false.
solve( <puzzle> )
The input can be an 81-character string with zeroes or non-digits for empty cells, it can be 81 individual values, an arrayref with these or a 9x9 AoA.
The return value is an unblessed hash reference, populated with properties of the puzzle and the results of the solving process.
strPuzzle, givensCount, uniqueGivens
Describing the puzzle.
seconds
Time needed for the entire solving process.
solutionCount
Normally == '1'. Is subject to $MAX_SOLUTIONS and the nature of the puzzle.
solutions
An arrayref with string representation of the one or more solutions.
logicSolved
Boolean, telling whether the limited power from PatternSolver::CPLogic sufficed for completion.
logicFilled
Number of cells filled by naked/hidden singles.
candidatesDropped
Number of individual candidates dropped from any cells without a value yet.
Especially the last couple of attributes can be taken for a rough estimation towards the puzzle's difficulty.
If logicSolved is false, it takes more than finding all naked or hidden pairs, triples or quads and all occasions for pointing and claiming. Hence we may put it at 'Master' level. (Maybe, a single xy-wing has forced our resorting to backtracking, but thats highly unlikely.) The majority of all chance created puzzles falls into this category. And many of these are insanely hard.
Otherwise, if candidatesDropped == 0, it means that the puzzle was solved with all values forced as naked or hidden singles. These can be called 'Easy' puzzles, more or less. But sometimes even singles are a bit difficult to spot.
And I personally prefer to play the grade in-between, and therefore call it the 'Advanced' level, not the 'Still relatively easy' level. Knowing for sure that nothing but spotting locked sets and applying locked candidates is required for victory, I find highly motivating.
Exports
PatternSolver optionally exports the symbols solve(), print_solution(), print_grid(), $VERBOSE, $MAX_SOLUTIONS, $LOOSE_MODE, $USE_LOGIC and provides the import tag ':all'.
- print_solution(), print_grid()
-
The two helper functions give formatted output of selected attributes to STDOUT.
- $VERBOSE (default false)
-
Give informative output.
- $MAX_SOLUTIONS (default 2)
-
On (invalid) multi-solution puzzles, stop and return after this number of solutions is reached. Without a value (false) an exhaustive search is carried out.
- $LOOSE_MODE (default true)
-
If true, puzzles with less than 8 different clues may get solved and can be generated by Games::Sudoku::PatternSolver::Generator. Does refuse to solve puzzles with less than 8 different clues if false. Knowledge of the different interpretations of Sudoku solution uniqueness is helpful for comprehension.
- $USE_LOGIC (default true)
-
Load and apply the constraint logic from PatternSolver::CPLogic.
PatternSolver::CPLogic
$USE_LOGIC = 1 (default)
Trying to fill in more values before the brute force gets unleashed comes with two advantages. It may significantly speed up the subsequent process of backtracking or even eleminate the need for it, because much less combinations have to be tried (or even none at all if the sudoku was solved), and it is also giving a few hints towards the puzzle's difficulty.
This helper module implements just the first and basic most strategies known to every occasional player. The 'hidden singles' and 'naked singles' directly force a value into a specific cell. And the just slightly more sophisticated 'locked sets' and 'locked candidates' rule out certain values in some cells. Because of the vast gain in speed (on average) switching off the logic is only reasonable for bechmarking the unamended pattern matching algorithm.
PatternSolver::Generator
Games::Sudoku::PatternSolver::Generator creates Sudoku puzzles with random properties. Apart from using the Games::Sudoku::PatternSolver there is nothing making this special.
As almost always when creating Sudokus programmatically, it follows the procedure
1. start with any valid solution (a rule-compliant 9x9 grid with all 81 numbers)
2. remove values in a random order (or copy them to a new blank grid) until a grid with a unique solution is found that cannot further be reduced
Puzzles returned are minimal and with respect to $LOOSE_MODE, have a unique solution (see below). The results are totally random, the majority being too hard for the average player and it is up to you, to filter them as you please. One would usually just call the sub reference returned from get_sudoku_builder()
inside a loop to inspect and keep or skip the puzzles based upon their properties.
A solution (complete grid) can be fed to get_sudoku_builder(<strPuzzle>)
as a common starting point. It is amazing to see how many very different puzzles can be produced from a single solution. (But of course they will all share this single solution.)
Absolutely random solution grids may be produced from a sub returned by get_grid_builder()
. A boolean parameter <shuffle> passed to this sub, determines if the first row in the grids produced will always be 1 .. 9. (But is not minlexed!)
PatternSolver::PlayerIF
sudoku_html_page( arrayref ) returns a scalar html page, playable in a browser
Its parameter is an array of arrays, each entry consisting of 2 items: a 81 character puzzle string and any descriptive text for the list entry. You may put as many puzzles as you like into the array, they can all be played from the one, javascript-driven static page. Can also be used to play lists with numerous 9x9 Sudoku from other sources.
PatternSolver::Patterns
Internal module to access the serialized patterns. The method init_patterns()
could be used to re-create the file with the 46656 binary symbol distribution patterns.
Scripts
-
Basic use of PatternSolver::solve().
-
Use of PatternSolver::Generator::get_sudoku_builder() to create Sudoku lists and how to export them to playable html pages.
Solution uniqueness
Quite a number of online discussions broach the issue of solution uniqueness; whether any valid puzzle really must have only one solution and whether a solving strategy is allowed to draw from the knowledge that only one solution can exist. On the other hand, no one seems to care or even be aware that the conventional nonchalant definition of the playing rules poses a slight deviance from the mathematical model of the problem at hand.
It is commonly felt that a new puzzle cannot be created from another one just by swapping numbers. But interestingly this insight never seems to get applied to the puzzle solutions.
Sudoku rules for novice players mandate that numbers 1 to 9 are to be put into the free cells and that one never should have to guess which number that might be. Consequently any puzzle with less than 8 unique givens is regarded as 'invalid', as it cannot doubtlessly be solved. Most Sudoku programs (solvers and generators alike) are implemented in accordance with this point of view.
Yet, if Sudoku is seen and explored as a general mathematical problem, the choice of symbols becomes irrelevant. The sole task is to determine the 9 sets of 9 cells that form the specific pattern or 'path' which complies with the constraints. The way these patterns get noted or marked forms no intrinsic part of the problem; nor has there to be a predefined, fix set of numbers, letters, colors or icons.
This viewpoint is allowing puzzles with less than 8 different givens and still only one solution to be regarded as valid. Some puzzles with only 5 different givens have indeed been found, but a mathematical proof for that being the minimum does not yet exist.
A readily solvable example: (After putting in the given symbols, the remaining 18 fields can be filled with absent numbers 6 and 9 or any other two symbols in just one possible way.)
-------------------------
| . . . | . 7 . | 4 . 5 |
| 2 . 8 | . . . | . . 3 |
| . . 3 | . 2 . | 8 . . |
-------------------------
| . . 2 | . . 1 | . . . |
| . 8 . | . . . | . 1 . |
| . . 5 | . . 2 | . 8 . |
-------------------------
| . . . | . . . | 7 . . |
| . . . | 8 5 . | 3 4 2 |
| . . . | 7 . 4 | . . . |
-------------------------
With the default setting $LOOSE_MODE=1 PatternSolver and Generator can solve and generate such puzzles. (Though generating puzzles with less than 7 different givens will take quite some time and even more luck.)
DEPENDENCIES
COPYRIGHT AND LICENSE
The following copyright notice applies to all the files provided in this distribution, including binary files, unless explicitly noted otherwise.
This software is copyright (c) 2024 by Steffen Heinrich
This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself.
SEE ALSO
https://www.sudokuwiki.org/Pattern_Overlay, https://sites.math.washington.edu/~morrow/mcm/team2280.pdf