File indexing completed on 2024-04-28 04:04:44
0001 /**************************************************************************** 0002 * Copyright 2015 Ian Wadham <iandw.au@gmail.com> * 0003 * * 0004 * This program is free software; you can redistribute it and/or * 0005 * modify it under the terms of the GNU General Public License as * 0006 * published by the Free Software Foundation; either version 2 of * 0007 * the License, or (at your option) any later version. * 0008 * * 0009 * This program is distributed in the hope that it will be useful, * 0010 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 0011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 0012 * GNU General Public License for more details. * 0013 * * 0014 * You should have received a copy of the GNU General Public License * 0015 * along with this program. If not, see <http://www.gnu.org/licenses/>. * 0016 ****************************************************************************/ 0017 0018 #include "dlxsolver.h" 0019 #include "ksudoku_logging.h" 0020 0021 0022 // #define DLX_LOG 0023 0024 DLXSolver::DLXSolver (QObject * parent) 0025 : 0026 QObject (parent), 0027 mBoardValues (0), 0028 mSolutionMoves(nullptr), 0029 mGraph (nullptr) 0030 { 0031 #ifdef DLX_LOG 0032 qCDebug(KSudokuLog) << "DLXSolver constructor entered"; 0033 #endif 0034 mCorner = new DLXNode; 0035 clear(); 0036 } 0037 0038 DLXSolver::~DLXSolver() 0039 { 0040 #ifdef DLX_LOG 0041 qCDebug(KSudokuLog) << "DLXSolver destructor entered"; 0042 #endif 0043 deleteAll(); 0044 delete mCorner; 0045 } 0046 0047 void DLXSolver::printDLX (bool forced) 0048 { 0049 #ifdef DLX_LOG 0050 bool verbose = (forced || (mGraph->order() <= 5)); 0051 0052 if ((mEndNodeNum < 0) || (mEndColNum < 0)) { 0053 0054 qCDebug(KSudokuLog, "DLXSolver::printDLX(): EMPTY, mEndNodeNum %d, " 0055 "mEndRowNum %d, mEndColNum %d", 0056 mEndNodeNum, mEndRowNum, mEndColNum); 0057 return; 0058 } 0059 // fprintf (stderr, "\nDLX Matrix has %d cols, %d rows and %d ones\n\n", 0060 // mEndColNum + 1, mEndRowNum + 1, mEndNodeNum + 1); 0061 DLXNode * colDLX = mCorner->right; 0062 if (colDLX == mCorner) { 0063 fprintf (stderr, "DLXSolver::printDLX(): ALL COLUMNS ARE HIDDEN\n"); 0064 return; 0065 } 0066 int totGap = 0; 0067 int nRows = 0; 0068 int nNodes = 0; 0069 int lastCol = -1; 0070 QList<DLXNode *> rowsRemaining; 0071 rowsRemaining.fill (0, mRows.count()); 0072 if (verbose) fprintf (stderr, "\n"); 0073 while (colDLX != mCorner) { 0074 int col = mColumns.indexOf(colDLX); 0075 if (verbose) fprintf (stderr, "Col %02d, %02d rows ", 0076 col, mColumns.at(col)->value); 0077 DLXNode * node = mColumns.at(col)->below; 0078 while (node != colDLX) { 0079 int rowNum = node->value; 0080 if (verbose) fprintf (stderr, "%02d ", rowNum); 0081 if (rowsRemaining.at (rowNum) == 0) { 0082 nRows++; 0083 } 0084 rowsRemaining[rowNum] = mRows.at (rowNum); 0085 nNodes++; 0086 node = node->below; 0087 } 0088 int gap = col - (lastCol + 1); 0089 if (gap > 0) { 0090 if (verbose) fprintf (stderr, "covered %02d", gap); 0091 totGap = totGap + gap; 0092 } 0093 if (verbose) fprintf (stderr, "\n"); 0094 colDLX = colDLX->right; 0095 lastCol = col; 0096 } 0097 if (verbose) fprintf (stderr, "\n"); 0098 fprintf (stderr, "Matrix NOW has %d rows, %d columns and %d ones\n", 0099 nRows, lastCol + 1 - totGap, nNodes); 0100 #else 0101 Q_UNUSED (forced); 0102 #endif 0103 } 0104 0105 void DLXSolver::recordSolution (const int solutionNum, QList<DLXNode *> & solution) 0106 { 0107 // Extract a puzzle solution from the DLX solver into mBoardValues. There 0108 // may be many solutions, found at various times as the solver proceeds. 0109 0110 // TODO - DLXSolver's solutions are not needed for anything in KSudoku: we 0111 // just need to know if there is more than 1 solution. In the future, 0112 // maybe each solution could be returned via a signal-slot mechanism. 0113 0114 int order = mGraph->order(); 0115 int nCages = mGraph->cageCount(); 0116 SudokuType t = mGraph->specificType(); 0117 if (mSolutionMoves) { 0118 mSolutionMoves->clear(); 0119 } 0120 #ifdef DLX_LOG 0121 qCDebug(KSudokuLog) << "NUMBER OF ROWS IN SOLUTION" << solution.size(); 0122 #endif 0123 if ((t == Mathdoku) || (t == KillerSudoku)) { 0124 for (int n = 0; n < solution.size(); n++) { 0125 int rowNumDLX = solution.at (n)->value; 0126 int searchRow = 0; 0127 #ifdef DLX_LOG 0128 qCDebug(KSudokuLog) << " Node" << n << "row number" << rowNumDLX; 0129 #endif 0130 for (int nCage = 0; nCage < nCages; nCage++) { 0131 int cageSize = mGraph->cage (nCage).size(); 0132 int nCombos = (mPossibilitiesIndex->at (nCage + 1) - 0133 mPossibilitiesIndex->at (nCage)) / cageSize; 0134 if ((searchRow + nCombos) <= rowNumDLX) { 0135 searchRow += nCombos; 0136 continue; 0137 } 0138 int comboNum = rowNumDLX - searchRow; 0139 int comboValues = mPossibilitiesIndex->at (nCage) 0140 + (comboNum * cageSize); 0141 #ifdef DLX_LOG 0142 qCDebug(KSudokuLog) << "Solution node" << n << "cage" << nCage 0143 << mGraph->cage (nCage) << "combos" << nCombos; 0144 qCDebug(KSudokuLog) << "Search row" << searchRow << "DLX row" << rowNumDLX 0145 << "cageSize" << cageSize << "combo" << comboNum 0146 << "values at" << comboValues; 0147 #endif 0148 const QList<int> cage = mGraph->cage (nCage); 0149 for (const int cell : cage) { 0150 #ifdef DLX_LOG 0151 fprintf (stderr, "%d:%d ", cell, 0152 mPossibilities->at (comboValues)); 0153 #endif 0154 // Record the sequence of cell-numbers, for use in hints. 0155 if (mSolutionMoves) { 0156 mSolutionMoves->append (cell); 0157 } 0158 mBoardValues [cell] = mPossibilities->at (comboValues); 0159 comboValues++; 0160 } 0161 #ifdef DLX_LOG 0162 fprintf (stderr, "\n\n"); 0163 #endif 0164 break; 0165 } 0166 } 0167 } 0168 else { // Sudoku or Roxdoku variant. 0169 for (DLXNode * node : std::as_const(solution)) { 0170 int rowNumDLX = node->value; 0171 mBoardValues [rowNumDLX/order] = (rowNumDLX % order) + 1; 0172 } 0173 } 0174 0175 #ifdef DLX_LOG 0176 fprintf (stderr, "\nSOLUTION %d\n\n", solutionNum); 0177 printSudoku(); 0178 #else 0179 Q_UNUSED (solutionNum); 0180 #endif 0181 } 0182 0183 void DLXSolver::retrieveSolution (BoardContents & solution) 0184 { 0185 solution = mBoardValues; 0186 } 0187 0188 void DLXSolver::printSudoku() 0189 { 0190 // TODO - The code at SudokuBoard::print() is VERY similar... 0191 #ifdef DLX_LOG 0192 // Used for test and debug, but the format is also parsable and loadable. 0193 0194 char nLabels[] = "123456789"; 0195 char aLabels[] = "abcdefghijklmnopqrstuvwxy"; 0196 int index, value; 0197 int order = mGraph->order(); 0198 int blockSize = mGraph->base(); 0199 int sizeX = mGraph->sizeX(); 0200 int sizeY = mGraph->sizeY(); 0201 int sizeZ = mGraph->sizeZ(); // If 2-D, depth == 1, else depth > 1. 0202 0203 for (int k = 0; k < sizeZ; k++) { 0204 int z = (sizeZ > 1) ? (sizeZ - k - 1) : k; 0205 for (int j = 0; j < sizeY; j++) { 0206 if ((j != 0) && (j % blockSize == 0)) { 0207 fprintf (stderr, "\n"); // Gap between square blocks. 0208 } 0209 int y = (sizeZ > 1) ? (sizeY - j - 1) : j; 0210 for (int x = 0; x < sizeX; x++) { 0211 index = mGraph->cellIndex (x, y, z); 0212 value = mBoardValues.at (index); 0213 if (x % blockSize == 0) { 0214 fprintf (stderr, " "); // Gap between square blocks. 0215 } 0216 if (value == UNUSABLE) { 0217 fprintf (stderr, " '"); // Unused cell (e.g. in Samurai). 0218 } 0219 else if (value == VACANT) { 0220 fprintf (stderr, " -"); // Empty cell (to be solved). 0221 } 0222 else { 0223 value--; 0224 char label = (order > 9) ? aLabels[value] : nLabels[value]; 0225 fprintf (stderr, " %c", label); // Given cell (or clue). 0226 } 0227 } 0228 fprintf (stderr, "\n"); // End of row. 0229 } 0230 fprintf (stderr, "\n"); // Next Z or end of 2D puzzle/solution. 0231 } 0232 #endif 0233 } 0234 0235 int DLXSolver::solveSudoku (SKGraph * graph, const BoardContents & boardValues, 0236 int solutionLimit) 0237 { 0238 // NOTE: This procedure is not actually used in KSudoku, but was used to 0239 // develop and test solveDLX(), using Sudoku and Roxdoku puzzles. It 0240 // turned out that solveSudoku(), using DLX, was not significantly 0241 // faster than the methods in the SudokuBoard class and had the 0242 // disadvantage that no method to assess puzzle difficulty could 0243 // be found for solveDLX(). 0244 0245 mBoardValues = boardValues; // Used later for filling in a solution. 0246 mGraph = graph; 0247 0248 int nSolutions = 0; 0249 int order = graph->order(); 0250 int boardArea = graph->size(); 0251 int nGroups = graph->cliqueCount(); 0252 int vacant = VACANT; 0253 int unusable = UNUSABLE; 0254 0255 #ifdef DLX_LOG 0256 qCDebug(KSudokuLog) << "TEST for DLXSolver"; 0257 printSudoku(); 0258 0259 qCDebug(KSudokuLog) << "DLXSolver::solve: Order" << order << "boardArea" << boardArea 0260 << "nGroups" << nGroups; 0261 #endif 0262 0263 // Generate a DLX matrix for an empty Sudoku grid of the required type. 0264 // It has (boardArea*order) rows and (boardArea + nGroups*order) columns. 0265 clear(); // Empty the DLX matrix. 0266 mColumns.clear(); 0267 mRows.clear(); 0268 for (int n = 0; n < (boardArea + nGroups*order); n++) { 0269 mColumns.append (mCorner); 0270 } 0271 for (int n = 0; n < (boardArea*order); n++) { 0272 mRows.append (mCorner); 0273 } 0274 0275 // Exclude constraints for unusable cells and already-filled cells (clues). 0276 for (int index = 0; index < boardArea; index++) { 0277 if (boardValues.at(index) != vacant) { 0278 #ifdef DLX_LOG 0279 qCDebug(KSudokuLog) << "EXCLUDE CONSTRAINT for cell" << index 0280 << "value" << boardValues.at(index); 0281 #endif 0282 mColumns[index] = nullptr; 0283 for (int n = 0; n < order; n++) { 0284 mRows[index*order + n] = nullptr; // Drop row. 0285 } 0286 if (boardValues.at(index) == unusable) { 0287 continue; 0288 } 0289 // Get a list of groups (row, column, etc.) that contain this cell. 0290 const QList<int> groups = graph->cliqueList (index); 0291 #ifdef DLX_LOG 0292 int row = graph->cellPosY (index); 0293 int col = graph->cellPosX (index); 0294 qCDebug(KSudokuLog) << "CLUE AT INDEX" << index 0295 << "value" << boardValues.at(index) 0296 << "row" << row << "col" << col << "groups" << groups; 0297 #endif 0298 int val = boardValues.at(index) - 1; 0299 for (const int group : groups) { 0300 #ifdef DLX_LOG 0301 qCDebug(KSudokuLog) << "EXCLUDE CONSTRAINT" << (boardArea+group*order+val); 0302 #endif 0303 mColumns[boardArea + group*order + val] = nullptr; 0304 const QList<int> clique = graph->clique (group); 0305 for (const int cell : clique) { 0306 mRows[cell*order + val] = nullptr; // Drop row. 0307 } 0308 } 0309 } 0310 } 0311 0312 // Create the initial set of columns. 0313 for (DLXNode * colDLX : std::as_const(mColumns)) { 0314 mEndColNum++; 0315 // If the constraint is not excluded, put an empty column in the matrix. 0316 if (colDLX != nullptr) { 0317 DLXNode * node = allocNode(); 0318 mColumns[mEndColNum] = node; 0319 initNode (node); 0320 addAtRight (node, mCorner); 0321 } 0322 } 0323 0324 // Generate the initial DLX matrix. 0325 int rowNumDLX = 0; 0326 for (int index = 0; index < boardArea; index++) { 0327 // Get a list of groups (row, column, etc.) that contain this cell. 0328 const QList<int> groups = graph->cliqueList (index); 0329 #ifdef DLX_LOG 0330 int row = graph->cellPosY (index); 0331 int col = graph->cellPosX (index); 0332 qCDebug(KSudokuLog) << " Index" << index << "row" << row << "col" << col 0333 << "groups" << groups; 0334 #endif 0335 0336 // Generate a row for each possible value of this cell in the Sudoku 0337 // grid, representing part of a possible solution. Each row must have 0338 // 1's in columns that correspond to a constraint on the cell and on the 0339 // value (in each group to which the cell belongs --- row, column, etc). 0340 0341 for (int possValue = 0; possValue < order; possValue++) { 0342 #ifdef DLX_LOG 0343 QString s = (mRows.at (rowNumDLX) == 0) ? "DROPPED" : "OK"; 0344 qCDebug(KSudokuLog) << "Row" << rowNumDLX << s; 0345 #endif 0346 if (mRows.at (rowNumDLX) != nullptr) { // Skip already-excluded rows. 0347 mRows[rowNumDLX] = nullptr; // Re-initialise a "live" row. 0348 addNode (rowNumDLX, index); // Mark cell fill-in constraint. 0349 for (const int group : groups) { 0350 // Mark possibly-satisfied constraints for row, column, etc. 0351 addNode (rowNumDLX, boardArea + group*order + possValue); 0352 } 0353 } 0354 rowNumDLX++; 0355 } 0356 } 0357 #ifdef DLX_LOG 0358 printDLX(true); 0359 qCDebug(KSudokuLog) << "Matrix MAX had " << mRows.count() << " rows, " << mColumns.count() 0360 << " columns and " << ((boardArea + nGroups*order)*order) << " ones"; 0361 qCDebug(KSudokuLog) << "CALL solveDLX(), solution limit" << solutionLimit; 0362 #endif 0363 // Solve the DLX-matrix equivalent of the Sudoku-style puzzle. 0364 nSolutions = solveDLX (solutionLimit); 0365 #ifdef DLX_LOG 0366 qCDebug(KSudokuLog) << "FOUND" << nSolutions << "solutions, limit" << solutionLimit; 0367 #endif 0368 return nSolutions; 0369 } 0370 0371 int DLXSolver::solveMathdoku (SKGraph * graph, QList<int> * solutionMoves, 0372 const QList<int> * possibilities, 0373 const QList<int> * possibilitiesIndex, 0374 int solutionLimit) 0375 { 0376 mSolutionMoves = solutionMoves; 0377 #ifdef DLX_LOG 0378 qCDebug(KSudokuLog) << "DLXSolver::solveMathdoku ENTERED" << possibilities->size() 0379 << "possibilities" << possibilitiesIndex->size() << "index size"; 0380 #endif 0381 int nSolutions = 0; 0382 int order = graph->order(); 0383 int nCages = graph->cageCount(); 0384 int nGroups = graph->cliqueCount(); 0385 0386 // Save these pointers for use later, in recordSolution(). 0387 mGraph = graph; 0388 mPossibilities = possibilities; 0389 mPossibilitiesIndex = possibilitiesIndex; 0390 mBoardValues.fill (0, order * order); 0391 0392 // Create an empty DLX matrix. 0393 clear(); 0394 mColumns.clear(); 0395 mRows.clear(); 0396 0397 // Create the initial set of columns. 0398 for (int n = 0; n < (nCages + nGroups * order); n++) { 0399 mEndColNum++; 0400 // Put an empty column in the matrix. 0401 DLXNode * node = allocNode(); 0402 mColumns.append (node); 0403 initNode (node); 0404 addAtRight (node, mCorner); 0405 } 0406 0407 int rowNumDLX = 0; 0408 int counter = 0; 0409 for (int n = 0; n < nCages; n++) { 0410 int size = graph->cage (n).size(); 0411 int nVals = possibilitiesIndex->at (n + 1) - possibilitiesIndex->at (n); 0412 int nCombos = nVals / size; 0413 int index = possibilitiesIndex->at (n); 0414 #ifdef DLX_LOG 0415 qCDebug(KSudokuLog) << "CAGE" << n << "of" << nCages << "size" << size 0416 << "nCombos" << nCombos << "nVals" << nVals 0417 << "index" << index << "of" << possibilities->size(); 0418 #endif 0419 for (int nCombo = 0; nCombo < nCombos; nCombo++) { 0420 mRows.append (nullptr); // Start a row for each combo. 0421 addNode (rowNumDLX, n); // Mark the cage's fill-in constraint. 0422 counter++; 0423 #ifdef DLX_LOG 0424 qCDebug(KSudokuLog) << "Add cage-node: row" << rowNumDLX << "cage" << n 0425 << graph->cage (n); 0426 #endif 0427 const QList<int> cage = graph->cage (n); 0428 for (const int cell : cage ) { 0429 int possVal = possibilities->at (index); 0430 // qCDebug(KSudokuLog) << " Cell" << cell << "possVal" << possVal; 0431 const QList<int> cliqueList = graph->cliqueList (cell); 0432 for (const int group : cliqueList) { 0433 // Poss values go from 0 to (order - 1) in DLX (so -1 here). 0434 addNode (rowNumDLX, nCages + group * order + possVal - 1); 0435 counter++; 0436 } 0437 index++; 0438 } 0439 rowNumDLX++; 0440 } 0441 } 0442 qCDebug(KSudokuLog) << "DLX MATRIX HAS" << mColumns.size() << "cols" << mRows.size() << "rows" << counter << "nodes"; 0443 nSolutions = solveDLX (solutionLimit); 0444 return nSolutions; 0445 } 0446 0447 /* TODO - Delete this eventually. 0448 void DLXSolver::testDLX () 0449 { 0450 const int test [6][7] = { 0451 {1,0,0,1,0,0,1}, 0452 {1,0,0,1,0,0,0}, 0453 {0,0,0,1,1,0,1}, 0454 {0,0,1,0,1,1,0}, 0455 {0,1,1,0,0,1,1}, 0456 {0,1,0,0,0,0,1} 0457 }; 0458 const int w = 7; 0459 const int h = 6; 0460 fprintf (stderr, "\nTEST MATRIX\n"); 0461 for (int row = 0; row < h; row++) { 0462 for (int col = 0; col < w; col++) { 0463 fprintf (stderr, " %d", test[row][col]); 0464 } 0465 fprintf (stderr, "\n"); 0466 } 0467 fprintf (stderr, "\n"); 0468 for (int row = 0; row < h; row++) { 0469 for (int col = 0; col < w; col++) { 0470 if (test[row][col]) addNode (row, col); 0471 } 0472 } 0473 printDLX(); 0474 solveDLX (0); 0475 } 0476 */ 0477 0478 /* HOW THE DANCING LINKS ALGORITHM WORKS IN METHOD solveDLX(). 0479 0480 The solution algorithm must satisfy every column's constraint if it is to 0481 succeed. So it proceeds by taking one column at a time and "covering" it. 0482 In this context, "covering" can mean logically hiding the column and so 0483 reducing the size of the matrix to be solved, as happens in the method 0484 coverColumn() below. But it also means that the constraint represented 0485 by that column is "covered" or satisfied, in the sense that a payment 0486 of money can be "covered" (i.e. provided for). 0487 0488 Whichever column is covered first, one of its non-zero values must be in 0489 a row that is part of the solution, always supposing that there is a 0490 solution. Knuth recommends to select first the columns that have the 0491 smallest number of 1's. The algorithm then tries each column in turn and 0492 each non-zero item within that column, backtracking if there are no items 0493 left in a column. When all columns have been covered, a solution has been 0494 found, but the algorithm continues to search for other solutions until 0495 the caller's solution limit is reached. The solutions are delivered via 0496 the Qt library's signal-slot mechanism. 0497 0498 The algorithm terminates when the first column in the next solution is to 0499 be chosen, but one of the columns has no 1's in it, meaning that there can 0500 be no further solution. In principle, this can happen right at the start, 0501 because the corresponding problem is insoluble, but more likely will be 0502 after an extensive search where the solution limit parameter is zero (no 0503 limit) or the number of solutions found is less than the required limit or 0504 there is no solution, even after an extensive search. The algorithm then 0505 returns the integer number of solutions found (possibly 0). 0506 0507 The "Dancing Links" aspect of the algorithm refers to lists of nodes that 0508 are linked in four directions (left, right, above and below) to represent 0509 columns, rows and column headers. Each node represents a 1 in the matrix. 0510 Covering a column involves unlinking it from the columns on each side of 0511 it and unlinking each row that has a 1 in that column from the rows above 0512 and below. One of the nodes in the column is included (tentatively) in 0513 the current partial solution and so the other nodes and their rows cannot 0514 be. At the same time, the matrix reduces to a sub-matrix and sub-problem. 0515 0516 The thing is that the removed columns and rows "remember" their previous 0517 state and can easily be re-linked if backtracking becomes necessary and 0518 they need to be "uncovered". Thus the nodes, links, columns and rows can 0519 "dance" in and out of the matrix as the solution proceeds. Furthermore, 0520 the algorithm can be written without using recursion. It just needs to 0521 keep a LIFO list (i.e. a stack) of nodes tentatively included in the 0522 current solution. Using iteration should make the algorithm go fast. 0523 */ 0524 0525 int DLXSolver::solveDLX (int solutionLimit) 0526 { 0527 int solutionCount = 0; 0528 int level = 0; 0529 DLXNode * currNode = nullptr; 0530 DLXNode * bestCol = nullptr; 0531 QList<DLXNode *> solution; 0532 bool searching = true; 0533 bool descending = true; 0534 0535 if (mCorner->right == mCorner) { 0536 // Empty matrix, nothing to solve. 0537 qCDebug(KSudokuLog) << "solveDLX(): EMPTY MATRIX, NOTHING TO SOLVE."; 0538 return solutionCount; 0539 } 0540 0541 while (searching) { 0542 // Find the column with the least number of rows yet to be explored. 0543 int min = mCorner->right->value; 0544 bestCol = mCorner->right; 0545 for (DLXNode * p = mCorner->right; p != mCorner; p = p->right) { 0546 if (p->value < min) { 0547 bestCol = p; 0548 min = p->value; 0549 } 0550 } 0551 #ifdef DLX_LOG 0552 qCDebug(KSudokuLog) << "solveDLX: BEST COLUMN " << mColumns.indexOf(bestCol) 0553 << " level " << level << " rows " << bestCol->value; 0554 #endif 0555 0556 coverColumn (bestCol); 0557 currNode = bestCol->below; 0558 solution.append (currNode); 0559 #ifdef DLX_LOG 0560 fprintf (stderr, "CURRENT SOLUTION: %d rows:", solution.size()); 0561 for (DLXNode * q : std::as_const(solution)) { 0562 fprintf (stderr, " %d", q->value); 0563 } 0564 fprintf (stderr, "\n"); 0565 #endif 0566 while (descending) { 0567 if (currNode != bestCol) { 0568 // Found a row: cover all other cols of currNode's row (L to R). 0569 // Those constraints are satisfied (for now) by this row. 0570 DLXNode * p = currNode->right; 0571 while (p != currNode) { 0572 coverColumn (p->columnHeader); 0573 p = p->right; 0574 } 0575 // printDLX(); 0576 0577 if (mCorner->right != mCorner) { 0578 break; // Start searching a new sub-matrix. 0579 } 0580 // All columns covered: a solution has been found. 0581 solutionCount++; 0582 recordSolution (solutionCount, solution); 0583 if (solutionCount == solutionLimit) { 0584 return solutionCount; 0585 } 0586 } 0587 else { 0588 // No more rows to try in this column. 0589 uncoverColumn (bestCol); 0590 if (level > 0) { 0591 // Backtrack by one level. 0592 solution.removeLast(); 0593 level--; 0594 currNode = solution.at (level); 0595 bestCol = currNode->columnHeader; 0596 #ifdef DLX_LOG 0597 qCDebug(KSudokuLog) << "BACKTRACKED TO LEVEL" << level; 0598 #endif 0599 } 0600 else { 0601 // The search is complete. 0602 return solutionCount; 0603 } 0604 } 0605 0606 // Uncover all other columns of currNode's row (R to L). 0607 // Restores those constraints to unsatisfied state in reverse order. 0608 #ifdef DLX_LOG 0609 qCDebug(KSudokuLog) << "RESTORE !!!"; 0610 #endif 0611 DLXNode * p = currNode->left; 0612 while (p != currNode) { 0613 uncoverColumn (p->columnHeader); 0614 p = p->left; 0615 } 0616 // printDLX(); 0617 0618 // Select next row down and continue searching for a solution. 0619 currNode = currNode->below; 0620 solution [level] = currNode; 0621 #ifdef DLX_LOG 0622 qCDebug(KSudokuLog) << "SELECT ROW" << currNode->value 0623 << "FROM COL" << mColumns.indexOf (currNode->columnHeader); 0624 #endif 0625 } // End while (descending) 0626 0627 level++; 0628 0629 } // End while (searching) 0630 0631 return solutionCount; // Should never reach this point. 0632 } 0633 0634 void DLXSolver::coverColumn (DLXNode * colDLX) 0635 { 0636 #ifdef DLX_LOG 0637 fprintf (stderr, "coverColumn: %d rows %d\n", 0638 mColumns.indexOf(colDLX), colDLX->value); 0639 #endif 0640 colDLX->left->right = colDLX->right; 0641 colDLX->right->left = colDLX->left; 0642 0643 DLXNode * colNode = colDLX->below; 0644 while (colNode != colDLX) { 0645 DLXNode * rowNode = colNode->right; 0646 #ifdef DLX_LOG 0647 qCDebug(KSudokuLog) << "DLXSolver::coverColumn: remove DLX row" << rowNode->value; 0648 #endif 0649 while (rowNode != colNode) { 0650 rowNode->below->above = rowNode->above; 0651 rowNode->above->below = rowNode->below; 0652 rowNode->columnHeader->value--; 0653 rowNode = rowNode->right; 0654 } 0655 colNode = colNode->below; 0656 } 0657 } 0658 0659 void DLXSolver::uncoverColumn (DLXNode * colDLX) 0660 { 0661 DLXNode * colNode = colDLX->below; 0662 while (colNode != colDLX) { 0663 DLXNode * rowNode = colNode->right; 0664 #ifdef DLX_LOG 0665 qCDebug(KSudokuLog) << "DLXSolver::uncoverColumn: return DLX row" 0666 << rowNode->value; 0667 #endif 0668 while (rowNode != colNode) { 0669 rowNode->below->above = rowNode; 0670 rowNode->above->below = rowNode; 0671 rowNode->columnHeader->value++; 0672 rowNode = rowNode->right; 0673 } 0674 colNode = colNode->below; 0675 } 0676 0677 #ifdef DLX_LOG 0678 fprintf (stderr, "uncoverColumn: %d rows %d\n", 0679 mColumns.indexOf(colDLX), colDLX->value); 0680 #endif 0681 colDLX->left->right = colDLX; 0682 colDLX->right->left = colDLX; 0683 } 0684 0685 void DLXSolver::clear() 0686 { 0687 #ifdef DLX_LOG 0688 qCDebug(KSudokuLog) << "============================================================="; 0689 qCDebug(KSudokuLog) << "DLXSolver::clear"; 0690 #endif 0691 // Logically clear the DLX matrix, but leave all previous nodes allocated. 0692 // This is to support faster DLX solving on second and subsequent puzzles. 0693 mEndNodeNum = -1; 0694 mEndRowNum = -1; 0695 mEndColNum = -1; 0696 initNode (mCorner); 0697 } 0698 0699 void DLXSolver::addNode (int rowNum, int colNum) 0700 { 0701 DLXNode * header = mColumns.at (colNum); 0702 if (header == nullptr) { 0703 return; // This constraint is excluded (clue or unused). 0704 } 0705 0706 // Get a node from the pool --- or create one. 0707 DLXNode * node = allocNode(); 0708 0709 // Circularly link the node onto the end of the row. 0710 if (mRows.at (rowNum) == nullptr) { 0711 mRows[rowNum] = node; // First in row. 0712 initNode (node); // Linked to itself at left and right. 0713 } 0714 else { 0715 addAtRight (node, mRows.at (rowNum)); 0716 } 0717 0718 // Circularly link the node onto the end of the column. 0719 addBelow (node, header); 0720 0721 // Set the node's data-values. 0722 node->columnHeader = header; 0723 node->value = rowNum; 0724 0725 // Increment the count of nodes in the column. 0726 header->value++; 0727 } 0728 0729 DLXNode * DLXSolver::allocNode() 0730 { 0731 mEndNodeNum++; 0732 if (mEndNodeNum >= mNodes.count()) { 0733 // Allocate a node only when needed, otherwise re-use one. 0734 mNodes.append (new DLXNode); 0735 } 0736 0737 return mNodes.at (mEndNodeNum); 0738 } 0739 0740 void DLXSolver::initNode (DLXNode * node) 0741 { 0742 node->left = node->right = node; 0743 node->above = node->below = node; 0744 node->columnHeader = node; 0745 node->value = 0; 0746 } 0747 0748 void DLXSolver::addAtRight (DLXNode * node, DLXNode * start) 0749 { 0750 node->right = start; 0751 node->left = start->left; 0752 start->left = node; 0753 node->left->right = node; 0754 } 0755 0756 void DLXSolver::addBelow (DLXNode * node, DLXNode * start) 0757 { 0758 node->below = start; 0759 node->above = start->above; 0760 start->above = node; 0761 node->above->below = node; 0762 } 0763 0764 void DLXSolver::deleteAll() 0765 { 0766 #ifdef DLX_LOG 0767 qCDebug(KSudokuLog) << "DLXSolver::deleteAll() CALLED"; 0768 #endif 0769 qDeleteAll (mNodes); // Deallocate the nodes pointed to. 0770 mNodes.clear(); 0771 mColumns.clear(); // Secondary pointers: no nodes to deallocate. 0772 mRows.clear(); 0773 } 0774 0775 #include "moc_dlxsolver.cpp"