File indexing completed on 2024-04-28 04:04:44

0001 /****************************************************************************
0002  *    Copyright 2011  Ian Wadham <iandw.au@gmail.com>                       *
0003  *    Copyright 2006  David Bau <david bau @ gmail com> Original algorithms *
0004  *    Copyright 2015  Ian Wadham <iandw.au@gmail.com>                       *
0005  *                                                                          *
0006  *    This program is free software; you can redistribute it and/or         *
0007  *    modify it under the terms of the GNU General Public License as        *
0008  *    published by the Free Software Foundation; either version 2 of        *
0009  *    the License, or (at your option) any later version.                   *
0010  *                                                                          *
0011  *    This program is distributed in the hope that it will be useful,       *
0012  *    but WITHOUT ANY WARRANTY; without even the implied warranty of        *
0013  *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
0014  *    GNU General Public License for more details.                          *
0015  *                                                                          *
0016  *    You should have received a copy of the GNU General Public License     *
0017  *    along with this program.  If not, see <http://www.gnu.org/licenses/>. *
0018  ****************************************************************************/
0019 
0020 #ifndef SUDOKUBOARD_H
0021 #define SUDOKUBOARD_H
0022 
0023 #include "globals.h"
0024 #include "skgraph.h"
0025 
0026 #include <QList>
0027 #include <QObject>
0028 #include <QStack>
0029 
0030 using Pair = qint32;        // Two small integers packed into one.
0031 
0032 using Move = Pair;
0033 using MoveList = QList<Move>;
0034 
0035 using Guess = Move;
0036 using GuessesList = MoveList;
0037 
0038 enum                 GuessingMode {Random, NotRandom};
0039 
0040 class SKGraph;
0041 class State;
0042 
0043 // TODO - SudokuBoard, MathdokuGenerator, CageGenerator and DLXSolver could be
0044 //        factored better. At the moment, MathdokuGenerator needs SudokuBoard's
0045 //        fillBoard() method to create a square that satisfies Sudoku rules for
0046 //        Killer Sudoku or Mathdoku puzzles. But fillBoard() depends on large
0047 //        parts of SudokuBoard's solver logic... so we have two solver objects
0048 //        co-existing for now, but this happens only for a second or so.
0049 
0050 /**
0051  * @class SudokuBoard  sudokuboard.h
0052  * @short Generalized data-structures and methods for handling Sudoku puzzles.
0053  *
0054  * SudokuBoard is an abstract class for handling several types of Sudoku puzzle,
0055  * including the classic 9x9 Sudoku, other sizes of the classic Sudoku, the
0056  * XSudoku and Jigsaw variants, Samurai Sudoku (with five overlapping grids)
0057  * and the three-dimensional Roxdoku.
0058  *
0059  * The class is an adaptation of algorithms in a Python program, Copyright (c)
0060  * David Bau 2006, which appears at http://davidbau.com/downloads/sudoku.py and
0061  * is discussed at http://davidbau.com/archives/2006/09/04/sudoku_generator.html
0062  * 
0063  * A puzzle, its solution and the intermediate steps in solution are represented
0064  * as vectors of integer cells (type BoardContents), in which a cell can contain
0065  * zero if it is yet to be solved, -1 if it is not used (e.g. the gaps between
0066  * the five overlapping grids of a Samurai Sudoku) or an integer greater than
0067  * zero if it is a given (or clue) or has been (tentatively) solved.
0068  *
0069  * The central method of the class is the solver (solve()). It is used when
0070  * solving an existing puzzle, generating a new puzzle, checking the validity of
0071  * a puzzle keyed in or loaded from a file, verifying that a puzzle is solvable,
0072  * checking that it has only one solution and collecting statistics related to
0073  * the difficulty of solving the puzzle.
0074  *
0075  * Puzzle generation begins by using the solver to fill a mainly empty board and
0076  * thus create the solution.  The next step is to insert values from the
0077  * solution into another empty board until there are enough to solve the puzzle
0078  * without any guessing (i.e. by logic alone).  If the difficulty of the puzzle
0079  * is now as required, puzzle generation finishes.  It it is too hard, a few
0080  * more values are inserted and then puzzle generation finishes.
0081  *
0082  * If the puzzle is not yet hard enough, some of the values are removed at
0083  * random until the puzzle becomes insoluble if any more cells are removed or
0084  * the puzzle has more than one solution or the required level of difficulty
0085  * is reached.  If the puzzle is still not hard enough after all random removals
0086  * have been tried, the whole puzzle-generation process is repeated until the
0087  * required difficulty is reached or a limit is exceeded.
0088  *
0089  * The principal methods used in puzzle-generation are generatePuzzle(),
0090  * insertValues(), removeValues() and checkPuzzle().  The checkPuzzle() method
0091  * is also used to check the validity of a puzzle entered manually or loaded
0092  * from a file.  The virtual methods clear() and fillBoard() clear a board or
0093  * fill it with randomly chosen values (the solution).
0094  *
0095  * The main input to the puzzle generator/solver is a pointer to an object of
0096  * type SKGraph.  That object contains the shape, dimensions and rules for
0097  * grouping the cells of the particular type of Sudoku being played, including
0098  * Classic Sudoku in several sizes and variants, Samurai Sudoku with five
0099  * overlapping grids and the three-dimensional Roxdoku in several sizes.
0100  *
0101  * Each group (row, column, block or plane) contains N cells in which the
0102  * numbers 1 to N must appear exactly once.  N can be 4, 9, 16 or 25, but not
0103  * all types of puzzle support all four sizes.
0104  *
0105  * As examples, a classic Sudoku puzzle has 27 groups: 9 rows, 9 columns and
0106  * 9 blocks of 3x3 cells.  Each group must contain the numbers 1 to 9 once and
0107  * only once.  An XSudoku puzzle has two extra groups of 9 cells each on the
0108  * board's diagonals.  A Samurai puzzle has five overlapping 9x9 grids, with 45
0109  * columns, 45 rows and 41 blocks of 3x3 cells, making 131 groups in all.  A
0110  * classic Sudoku puzzle of size 16 has 16 rows, 16 columns and 16 blocks of
0111  * 4x4 cells, making 48 groups, where each group must contain the values 1 to
0112  * 16 once and only once.  A 3x3x3 Roxdoku puzzle is a cube with 9 groups of
0113  * 3x3 cells.  These form 3 planes perpendicular to each of the X, Y and Z axes.
0114  *
0115  * All these configurations are represented by a table of groups (or cliques) in
0116  * the SKGraph object, which maps cell numbers into groups.  The SudokuBoard
0117  * class itself is unaware of the type of puzzle it is generating or solving.
0118  */
0119 class SudokuBoard : public QObject
0120 {
0121     Q_OBJECT
0122 public:
0123     /**
0124      * Construct a new SudokuBoard object with a required type and size.
0125      *
0126      * @param graph         The layout, type and size of the board, including
0127      *                      the grouping of cells into rows, columns and blocks,
0128      *                      as required by the type of puzzle being played.
0129      */
0130     explicit SudokuBoard (SKGraph * graph);
0131 
0132     /**
0133      * Generate a puzzle and its solution (see details in the class-header doc).
0134      *
0135      * @param puzzle        The generated puzzle.
0136      * @param solution      The generated solution.
0137      * @param difficulty    The required level of difficulty (as defined in file
0138      *                      globals.h).
0139      * @param symmetry      The required symmetry of layout of the clues.
0140      *
0141      * @return              Normally true, but false if the user wishes to go
0142      *                      back to the Welcome screen (e.g. to change reqs.)
0143      *                      after too many attempts to generate a puzzle.
0144      */
0145     bool                    generatePuzzle (BoardContents & puzzle,
0146                                             BoardContents & solution,
0147                                             Difficulty      difficulty,
0148                                             Symmetry        symmetry);
0149 
0150     /**
0151      * Check that a puzzle is soluble, has the desired solution and has only one
0152      * solution.  This method can be used to check puzzles loaded from a file or
0153      * entered manually, in which case the solution parameter can be omitted.
0154      *
0155      * @param puzzle        The board-contents of the puzzle to be checked.
0156      * @param solution      The board-contents of the desired solution if known.
0157      *
0158      * @return              The result of the check, with values as follows:
0159      * @retval >= 0         The difficulty of the puzzle, approximately, after
0160      *                      one solver run.  If there are guesses, the
0161      *                      difficulty can vary from one run to another,
0162      *                      depending on which guesses are randomly chosen.
0163      * @retval -1           No solution.
0164      * @retval -2           Wrong solution.
0165      * @retval -3           More than one solution.
0166      */
0167     int                     checkPuzzle (const BoardContents & puzzle,
0168                                          const BoardContents & solution =
0169                                                BoardContents());
0170 
0171     /**
0172      * Provide a list of solution moves for use as KSudoku hints.
0173      *
0174      * @param moveList     A list of KSudoku indices of solution moves (output).
0175      */
0176     void getMoveList (QList<int> & moveList);
0177 
0178     /**
0179      * Calculate the difficulty of a puzzle, based on the number of guesses
0180      * required to solve it, the number of iterations of the solver's deduction
0181      * method over the whole board and the fraction of clues or givens in the
0182      * starting position.  Easier levels of difficulty involve logical deduction
0183      * only and would usually not require guesses: harder levels might.
0184      *
0185      * When guesses are involved (i.e. branches or forks in the solution
0186      * process), the calculated difficulty can vary from one run to another of
0187      * the solver, depending on which guesses are randomly chosen, so it is
0188      * necessary to do several runs (e.g. 5) and calculate average values.
0189      *
0190      * @param puzzle        The board-contents of the puzzle to be assessed.
0191      * @param nSamples      The number of solver runs over which to take an
0192      *                      average.
0193      *
0194      * @return              The estimated difficulty of the puzzle (as defined
0195      *                      in file globals.h).
0196      */
0197     Difficulty              calculateRating (const BoardContents & puzzle,
0198                                              int nSamples = 5);
0199 
0200     /**
0201      * Solve a puzzle and return the solution.
0202      *
0203      * @param boardValues   The board-contents of the puzzle to be solved.
0204      *
0205      * @return              The board-contents of the solution.
0206      */
0207     BoardContents &         solveBoard (const BoardContents & boardValues,
0208                                               GuessingMode gMode = Random);
0209 
0210     /**
0211      * Fill the board with randomly chosen valid values, thus generating a
0212      * solution from which a puzzle can be created (virtual).  It is made
0213      * public so that it can be used to fill a Mathdoku or Killer Sudoku
0214      * board with numbers that satisfy Sudoku constraints.
0215      *
0216      * @return              The filled board-vector.
0217      */
0218     virtual BoardContents & fillBoard();
0219 
0220     /**
0221      * Initialize or re-initialize the random number generator.
0222      */
0223     void                    setSeed();
0224 
0225 protected:
0226     BoardContents           m_currentValues;    ///< The current state of the
0227                         ///< cell values during solve().
0228 
0229     SudokuType              m_type;     ///< The type of Sudoku puzzle
0230                         ///< (see file globals.h).
0231     int                     m_order;        ///< The number of cells per
0232                         ///< row, column or block (4,
0233                         ///< 9, 16 or 25).
0234     int                     m_blockSize;    ///< The number of cells on one
0235                         ///< side of a square block (2,
0236                         ///< 3, 4 or 5).
0237     int                     m_boardSize;    ///< The number of cells on one
0238                         ///< side of the whole board.
0239                         ///< In Samurai with 9x9 grids,
0240                         ///< this is 21.
0241     int                     m_boardArea;    ///< The number of cells in the
0242                         ///< whole board.  In Samurai
0243                         ///< with 9x9 grids this is 441.
0244     int                     m_overlap;      ///< The degree of overlap in a
0245                         ///< Samurai board (=m_blockSize
0246                         ///< or 1 for a TinySamurai).
0247     int                     m_nGroups;      ///< The total number of rows,
0248                         ///< columns, blocks, diagonals,
0249                         ///< etc. in the puzzle.
0250     int                     m_groupSize;    ///< The number of cells in each
0251                         ///< group (= m_order).
0252     QList<int>              m_cellIndex;    ///< A first-level index from a
0253                         ///< cell to the list of groups
0254                         ///< to which it belongs.
0255     QList<int>              m_cellGroups;   ///< A second-level index from
0256                         ///< cells to individual groups
0257                         ///< to which they belong.
0258 
0259     /**
0260      * Clear a board-vector of the required type and size (virtual).
0261      *
0262      * @param boardValues   The board-contents to be cleared.
0263      */
0264     virtual void            clear (BoardContents & boardValues);
0265 
0266     /*
0267      * Fill a vector of integers with values from 1 up to the size of the
0268      * vector, then shuffle the integers into a random order.
0269      *
0270      * @param sequence      The vector to be filled.
0271      */
0272     void                    randomSequence (QList<int> & sequence);
0273 
0274 private:
0275     bool                    generateSudokuRoxdokuTypes (BoardContents & puzzle,
0276                                                        BoardContents & solution,
0277                                                        Difficulty    difficulty,
0278                                                        Symmetry      symmetry);
0279 
0280     SKGraph *               m_graph;
0281     int                     m_vacant;
0282     int                     m_unusable;
0283     enum                    MoveType {Single, Spot, Guess, Wrong,
0284                                       Deduce, Result};
0285     Statistics              m_stats;
0286     Statistics              m_accum;
0287     MoveList                m_moves;
0288     MoveList                m_moveTypes;
0289     QList<int>              m_KSudokuMoves; // Move-list for KSudoku hints.
0290 
0291     QStack<State *>         m_states;
0292 
0293     QList<qint32>           m_validCellValues;
0294     QList<qint32>           m_requiredGroupValues;
0295 
0296     // These are the principal methods of the solver.  The key method is
0297     // deduceValues().  It finds and fills cells that have only one possible
0298     // value left.  If no more cells can be deduced, it returns a randomised
0299     // list of guesses.  Very easy to Medium puzzles are usually entirely
0300     // deducible, so solve() begins by trying that path.  If unsuccessful, it
0301     // uses tryGuesses() to explore possibilities and backtrack when required.
0302 
0303     BoardContents &         solve          (GuessingMode gMode);
0304     BoardContents &         tryGuesses     (GuessingMode gMode);
0305     GuessesList             deduceValues   (BoardContents & cellValues,
0306                                             GuessingMode gMode);
0307     GuessesList             solutionFailed (GuessesList & guesses);
0308 
0309     // These methods set up and maintain bit maps that indicate which values are
0310     // (still) allowed in each cell and which values are (still) required in
0311     // each group (row, column or block).
0312 
0313     void                    setUpValueRequirements
0314                                       (BoardContents & boardValues);
0315     void                    updateValueRequirements
0316                                       (BoardContents & boardValues, int cell);
0317 
0318     /**
0319      * Clear a board-vector and insert values into it from a solved board.  As
0320      * each value is inserted, it is copied into a parallel board along with
0321      * cells that can now be deduced logically.  The positions of values to be
0322      * inserted are chosen at random.  The process finishes when the parallel
0323      * board is filled, leaving a puzzle board that is only partly filled but
0324      * for which the solution can be entirely deduced without any need to guess
0325      * or backtrack.  However this could still be a difficult puzzle for a human
0326      * solver.  If the difficulty is greater than required, further values are
0327      * inserted until the puzzle reaches the required difficulty.
0328      *
0329      * @param solution      The solved board from which values are selected for
0330      *                      insertion into the puzzle board.
0331      * @param difficulty    The required level of difficulty (as defined in file
0332      *                      globals.h).
0333      * @param symmetry      The required symmetry of layout of the clues.
0334      *
0335      * @return              The puzzle board arrived at so far.
0336      */
0337     BoardContents           insertValues (const BoardContents & solution,
0338                                           const Difficulty      difficulty,
0339                                           const Symmetry        symmetry);
0340 
0341     /**
0342      * Remove values from a partially generated puzzle, to make it more
0343      * difficult.  As each value is removed, there is a check that the puzzle
0344      * is soluble, has the desired solution and has only one solution.  If it
0345      * fails this check, the value is replaced and another value is tried.  The
0346      * resulting puzzle could require one or more guesses, perhaps with some
0347      * backtracking.  The positions of values to be removed are chosen in a
0348      * random order.  If the required difficulty is "Unlimited", this algorithm
0349      * can generate "inhuman" puzzles that are extremely difficult and tedious
0350      * for a person to solve and can also be rather boring.
0351      *
0352      * This tendency is controlled in two ways.  Firstly, there is a minimum
0353      * percentage of the board that must be filled with clues and deducible
0354      * moves before a puzzle with guesses (i.e. branches or forks) is allowed.
0355      * Secondly, when the required difficulty is reached, removed values are
0356      * saved in a list until the required difficulty is exceeded.  Then half
0357      * the saved values are put back.  This "middle road" is chosen because, at
0358      * the transition points, the difficulty can vary between runs of the solver
0359      * if (random) guessing is required.
0360      *
0361      * @param solution      The board-contents of the desired solution.
0362      * @param puzzle        The board-contents of the partly generated puzzle.
0363      * @param difficulty    The required level of difficulty (as defined in file
0364      *                      globals.h).
0365      * @param symmetry      The required symmetry of layout of the clues.
0366      *
0367      * @return              The pruned puzzle board.
0368      */ 
0369     BoardContents           removeValues (const BoardContents & solution,
0370                                                 BoardContents & puzzle,
0371                                           const Difficulty      difficulty,
0372                                           const Symmetry        symmetry);
0373 
0374     /**
0375      * Compile statistics re solution moves and calculate a difficulty rating
0376      * for the puzzle, based on the number of guesses required, the number of
0377      * iterations of the deducer over the whole board and the fraction of clues
0378      * provided in the starting position.
0379      *
0380      * @param s             A structure containing puzzle and solution stats.
0381      */
0382     void                    analyseMoves (Statistics & s);
0383 
0384     /**
0385      * Convert the difficulty rating of a puzzle into a difficulty level.
0386      *
0387      * @param rating        The difficulty rating.
0388      *
0389      * @return              The difficulty level, from VeryEasy to Unlimited, as
0390      *                      defined in file globals.h).
0391      */
0392     Difficulty              calculateDifficulty (float rating);
0393 
0394     /**
0395      * Add or clear one clue or more in a puzzle, depending on the symmetry.
0396      *
0397      * @param to            The puzzle grid to be changed.
0398      * @param cell          The first cell to be changed.
0399      * @param type          The type of symmetry.
0400      * @param from          The grid from which the changes are taken.
0401      */
0402     void                    changeClues (BoardContents & to,
0403                                          int cell, Symmetry type,
0404                                          const BoardContents & from);
0405     /**
0406      * For a given cell, calculate the positions of cells that satisfy the
0407      * current symmetry requirement.
0408      *
0409      * @param size          The size of one side of the board.
0410      * @param type          The required type of symmetry (if any).
0411      * @param cell          The position of a selected cell.
0412      * @param out[4]        A set of up to four symmetrically placed cells.
0413      *
0414      * @return              The number of symmetrically placed cells.
0415      */
0416     int                     getSymmetricIndices (int size, Symmetry type,
0417                                                  int cell, int * out);
0418 
0419     /**
0420      * Format some board-contents into text for printing, debugging output or
0421      * saving to a file that can be loaded.
0422      *
0423      * @param boardValues   The contents of the board to be formatted.
0424      */
0425     void                    print (const BoardContents & boardValues);
0426 
0427     // Methods for packing two small integers into one and unpacking them.  Used
0428     // for speed and efficiency in the solver and other places.
0429     inline Pair             setPair (int p, int v ) { return (p << 8) + v; }
0430     inline int              pairPos (const Pair x)  { return (x >> 8);     }
0431     inline int              pairVal (const Pair x)  { return (x & 255);    }
0432 };
0433 
0434 #endif // SUDOKUBOARD_H