Warning, file /games/ksudoku/src/logic/skgraph.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
0001 /*************************************************************************** 0002 * Copyright 2005-2007 Francesco Rossi <redsh@email.it> * 0003 * Copyright 2006-2007 Mick Kappenburg <ksudoku@kappendburg.net> * 0004 * Copyright 2006-2008 Johannes Bergmeier <johannes.bergmeier@gmx.net> * 0005 * Copyright 2012 Ian Wadham <iandw.au@gmail.com> * 0006 * Copyright 2015 Ian Wadham <iandw.au@gmail.com> * 0007 * * 0008 * This program is free software; you can redistribute it and/or modify * 0009 * it under the terms of the GNU General Public License as published by * 0010 * the Free Software Foundation; either version 2 of the License, or * 0011 * (at your option) any later version. * 0012 * * 0013 * This program is distributed in the hope that it will be useful, * 0014 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 0015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 0016 * GNU General Public License for more details. * 0017 * * 0018 * You should have received a copy of the GNU General Public License * 0019 * along with this program; if not, write to the * 0020 * Free Software Foundation, Inc., * 0021 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * 0022 ***************************************************************************/ 0023 0024 #include "skgraph.h" 0025 0026 #include <QMultiMap> 0027 0028 SKGraph::SKGraph(int order, ksudoku::GameType type) 0029 { 0030 m_order = order; 0031 m_base = 3; 0032 for (int n = 2; n <= 5; n++) { 0033 if (m_order == n * n) { 0034 m_base = n; 0035 } 0036 } 0037 m_type = type; 0038 } 0039 0040 SKGraph::~SKGraph() 0041 { 0042 clearCages(); 0043 } 0044 0045 void SKGraph::initSudoku() 0046 { 0047 m_name = QStringLiteral("PlainSudoku"); 0048 m_specificType = Plain; 0049 0050 m_sizeX = m_order; 0051 m_sizeY = m_order; 0052 m_sizeZ = 1; 0053 m_emptyBoard.fill (UNUSABLE, size()); 0054 initSudokuGroups(0, true); 0055 indexCellsToCliques(); 0056 } 0057 0058 void SKGraph::initSudokuGroups(int pos, bool withBlocks) 0059 { 0060 // initSudokuGroups() sets up rows and columns in a Sudoku grid of size 0061 // (m_order*m_order) cells. Its first parameter (usually 0) shows where 0062 // on the whole board the grid goes. This is relevant in Samurai and 0063 // related layouts. Its second attribute is true if square-block groups 0064 // are required or false if not (e.g. as in a Jigsaw or Mathdoku type). 0065 0066 m_structures << SudokuGroups << pos << (withBlocks ? 1 : 0); 0067 0068 QList<int> rowc, colc, blockc; 0069 for(int i = 0; i < m_order; ++i) { 0070 rowc.clear(); 0071 colc.clear(); 0072 blockc.clear(); 0073 0074 for(int j = 0; j < m_order; ++j) 0075 { 0076 rowc << pos + j*m_sizeY + i; 0077 colc << pos + i*m_sizeY + j; 0078 blockc << pos + ((i/m_base)*m_base + j%m_base) * m_sizeY + (i%m_base)*m_base + j/m_base; 0079 } 0080 addClique(rowc); 0081 addClique(colc); 0082 if (withBlocks) { 0083 addClique(blockc); 0084 } 0085 } 0086 } 0087 0088 void SKGraph::initRoxdoku() 0089 { 0090 m_name = QStringLiteral("Roxdoku"); 0091 m_specificType = Roxdoku; 0092 0093 m_sizeX = m_base; 0094 m_sizeY = m_base; 0095 m_sizeZ = m_base; 0096 m_emptyBoard.fill (UNUSABLE, size()); 0097 initRoxdokuGroups(0); 0098 indexCellsToCliques(); 0099 } 0100 0101 void SKGraph::initRoxdokuGroups(int pos) 0102 { 0103 // initRoxdokuGroups() sets up the intersecting planes in a 0104 // 3-D Roxdoku grid. Its only parameter shows where in the entire 0105 // three-dimensional layout the grid goes. 0106 0107 m_structures << RoxdokuGroups << pos << 1; 0108 0109 QList<int> xFace, yFace, zFace; 0110 int x = cellPosX(pos); 0111 int y = cellPosY(pos); 0112 int z = cellPosZ(pos); 0113 0114 for (int i = 0; i < m_base; i++) { 0115 xFace.clear(); 0116 yFace.clear(); 0117 zFace.clear(); 0118 for (int j = 0; j < m_base; j++) { 0119 for (int k = 0; k < m_base; k++) { 0120 // Intersecting faces at relative (0,0,0), (1,1,1), etc. 0121 xFace << cellIndex (x + i, y + j, z + k); 0122 yFace << cellIndex (x + k, y + i, z + j); 0123 zFace << cellIndex (x + j, y + k, z + i); 0124 } 0125 } 0126 addClique(xFace); 0127 addClique(yFace); 0128 addClique(zFace); 0129 } 0130 } 0131 0132 void SKGraph::addCliqueStructure(const QList<int> &data) { 0133 0134 m_structures << Clique << m_cliques.count() << 0; 0135 0136 addClique(data); 0137 } 0138 0139 void SKGraph::addClique(const QList<int> &data) { 0140 // Add to the cliques (groups) list. 0141 m_cliques << data; 0142 for (int n = 0; n < data.size(); n++) { 0143 // Set cells in groups VACANT: cells not in groups are UNUSABLE. 0144 m_emptyBoard [data.at(n)] = VACANT; 0145 } 0146 } 0147 0148 void SKGraph::addCage(const QList<int> &cage, CageOperator cageOperator, 0149 int cageValue) 0150 { 0151 // Add to the cages list. 0152 m_cages.append (new Cage); 0153 Cage * newCage = m_cages.last(); 0154 newCage->cage = cage; 0155 newCage->cageOperator = cageOperator; 0156 newCage->cageValue = cageValue; 0157 0158 // Calculate cageTopLeft cell (used for displaying operator and value). 0159 int topY = m_order; 0160 int leftX = m_order; 0161 newCage->cageTopLeft = 0; 0162 for (const int cell : cage) { 0163 if (cellPosY(cell) > topY) { 0164 continue; // Below the best so far. 0165 } 0166 else if ((cellPosY(cell) == topY) && (cellPosX(cell) > leftX)) { 0167 continue; // Same height as best but to the right. 0168 } 0169 newCage->cageTopLeft = cell; 0170 topY = cellPosY(cell); 0171 leftX = cellPosX(cell); 0172 } 0173 } 0174 0175 void SKGraph::dropCage(int cageNum) 0176 { 0177 if (cageNum >= m_cages.count()) { 0178 return; 0179 } 0180 delete m_cages.at (cageNum); 0181 m_cages.remove (cageNum); 0182 } 0183 0184 void SKGraph::clearCages() { 0185 // Clear previous cages (if any). 0186 if (! m_cages.isEmpty()) { 0187 qDeleteAll (m_cages); 0188 m_cages.clear(); 0189 } 0190 } 0191 0192 void SKGraph::initCustom(const QString & name, SudokuType specificType, 0193 int order, int sizeX, int sizeY, int sizeZ) { 0194 // The Serializer's deserializer methods will add groups (or cliques). 0195 m_name = name; 0196 m_specificType = specificType; 0197 0198 m_order = order; 0199 m_sizeX = sizeX; 0200 m_sizeY = sizeY; 0201 m_sizeZ = sizeZ; 0202 m_emptyBoard.fill (UNUSABLE, size()); 0203 } 0204 0205 void SKGraph::endCustom() 0206 { 0207 indexCellsToCliques(); 0208 } 0209 0210 void SKGraph::indexCellsToCliques() 0211 { 0212 QMultiMap<int, int> cellsToCliques; 0213 int nCliques = cliqueCount(); 0214 int nCells = size(); 0215 for (int g = 0; g < nCliques; g++) { 0216 QList<int> cellList = clique(g); 0217 for (int n = 0; n < m_order; n++) { 0218 cellsToCliques.insert (cellList.at (n), g); 0219 } 0220 } 0221 0222 m_cellIndex.fill (0, nCells + 1); 0223 m_cellCliques.fill (0, nCliques * m_order); 0224 int index = 0; 0225 for (int cell = 0; cell < nCells; cell++) { 0226 m_cellIndex [cell] = index; 0227 const QList<int> cliqueList = cellsToCliques.values (cell); 0228 for (int g : cliqueList) { 0229 m_cellCliques [index] = g; 0230 index++; 0231 } 0232 } 0233 m_cellIndex [nCells] = index; 0234 } 0235 0236 const QList<int> SKGraph::cliqueList(int cell) const 0237 { 0238 // NOTE: We could have used QMultiMap<int, int>::values(int cell) to 0239 // access this index, but the index's main usage is on an inner loop 0240 // of the generator/solver and execution time is a concern there. 0241 0242 QList<int> cells; 0243 int start = m_cellIndex.at(cell); 0244 int end = m_cellIndex.at(cell + 1); 0245 for (int n = start; n < end; n++) { 0246 cells << m_cellCliques.at(n); 0247 } 0248 return cells; 0249 }