=encoding UTF-8

=head1 NAME

Games::Sudoku::PatternSolver - Solve, generate and play Sudoku 9x9 grids.

=head1 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.

B<Note:> I<For this module the term 'pattern' refers to a 9x9 matrix, holding the final 9 positions of any single symbol.>

=head1 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 )

=head1 MODULES AND UTILITIES

=head2 PatternSolver

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

=over 3

=item * strPuzzle, givensCount, uniqueGivens

Describing the puzzle.

=item * seconds

Time needed for the entire solving process.

=item * solutionCount

Normally == '1'. Is subject to $MAX_SOLUTIONS and the nature of the puzzle.

=item * solutions

An arrayref with string representation of the one or more solutions.

=item * logicSolved

Boolean, telling whether the limited power from L<PatternSolver::CPLogic|/"PatternSolver::CPLogic"> sufficed for completion.

=item * logicFilled

Number of cells filled by naked/hidden singles.

=item * candidatesDropped

Number of individual candidates dropped from any cells without a value yet.

=back

Especially the last couple of attributes can be taken for a rough estimation towards the puzzleE<apos>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.

=head2 Exports

PatternSolver optionally exports the symbols solve(), print_solution(), print_grid(), $VERBOSE, $MAX_SOLUTIONS, $LOOSE_MODE, $USE_LOGIC and provides the import tag ':all'.

=over 3 

=item print_solution(), print_grid()

The two helper functions give formatted output of selected attributes to STDOUT.

=item $VERBOSE (default false)

Give informative output. 

=item $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. 

=item $LOOSE_MODE (default true)

If true, puzzles with less than 8 different clues may get solved and can be generated by L<Games::Sudoku::PatternSolver::Generator>.
Does refuse to solve puzzles with less than 8 different clues if false.
Knowledge of the different interpretations of L<Sudoku solution uniqueness|/"Solution uniqueness"> is helpful for comprehension.

=item $USE_LOGIC (default true)

Load and apply the constraint logic from L<PatternSolver::CPLogic|/PatternSolver::CPLogic>.

=back

=head2 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 puzzleE<apos>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.


=head2 PatternSolver::Generator

L<Games::Sudoku::PatternSolver::Generator> creates Sudoku puzzles with random properties.
Apart from using the L<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 L<below|/"Solution uniqueness">).
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 C<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 C<get_sudoku_builder(E<lt>strPuzzleE<gt>)> 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 C<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!)

=head2 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.

=head2 PatternSolver::Patterns

Internal module to access the serialized patterns. 
The method C<init_patterns()> could be used to re-create the file with the 46656 binary symbol distribution patterns.

=head2 Scripts

=over 3

=item * L<examples/solve.pl>

Basic use of L<PatternSolver::solve()|/"solve()">.

=item * L<examples/play.pl>

Use of L<PatternSolver::Generator::get_sudoku_builder()|Games::Sudoku::PatternSolver::Generator/"get_sudoku_builder()"> to create Sudoku lists and how to export them to playable html pages.

=back

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

=head1 DEPENDENCIES

=over 5

=item * L<Bit::Vector>

=item * L<List::Util>

=item * L<Algorithm::Combinatorics>

=item * L<Time::HiRes>

=item * L<HTML::Template>

=back

=head1 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.

=head1 SEE ALSO

L<https://www.sudokuwiki.org/Pattern_Overlay>, L<https://sites.math.washington.edu/~morrow/mcm/team2280.pdf>

=cut

