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