private void NarrowDownIndependantCellGrouping(List<SudokuCell> cells, CellGroupingType type) { bool overallFoundOne; bool innerfoundOne; do { overallFoundOne = false; do { innerfoundOne = false; CheckForSolitarySolutionInGroup(cells, ref innerfoundOne); overallFoundOne |= innerfoundOne; if (!CheckValid()) break; } while (innerfoundOne); if (!CheckValid()) break; do { innerfoundOne = false; CheckForMultiplesInGroup(cells, type, ref innerfoundOne); if (!CheckValid()) break; overallFoundOne |= innerfoundOne; } while (innerfoundOne); if (!CheckValid()) break; do { innerfoundOne = false; CheckForLockingSituations(cells, type, ref innerfoundOne); if (!CheckValid()) break; overallFoundOne |= innerfoundOne; } while (innerfoundOne); if (!CheckValid()) break; } while (overallFoundOne); }
private List<SudokuCell> GetCellGroupingFor(SudokuCell cell, CellGroupingType type) { int col = cell.Col; int row = cell.Row; List<SudokuCell> cells = new List<SudokuCell>(); switch (type) { case CellGroupingType.Horizontal: for (int i = 0; i < 9; i++) { cells.Add(solvedData[i, row]); } break; case CellGroupingType.Vertical: for (int i = 0; i < 9; i++) { cells.Add(solvedData[col, i]); } break; case CellGroupingType.Square: int gridCol = col / 3; int gridRow = row / 3; int gridX = 3 * gridCol; int gridY = 3 * gridRow; for (int x = gridX; x - gridX < 3; x++) { for (int y = gridY; y - gridY < 3; y++) { cells.Add(solvedData[x, y]); } } break; } return cells; }
private void CheckForMultiplesInGroup(List<SudokuCell> cells, CellGroupingType type, ref bool foundSome) { WeedOutExistingFoundNumbers(cells); int numCellsUnsolved = 0; foreach (SudokuCell cell in cells) { numCellsUnsolved += (cell.Number == 0) ? 1 : 0; } if (numCellsUnsolved == 0) return; // check to see if there's a multiple of cells each with the same set of numbers // then that set of numbers should be removed from all the other cells // in this cell group, which aren't one of the multiples of cells. // such as a two cells have 4/6 left each. All the other cells in that line cannot have 4/6 then. for (int numMultiples = 2; numMultiples < numCellsUnsolved; numMultiples++) { List<SudokuCell> multiplesCells = new List<SudokuCell>(); foreach (SudokuCell cell in cells) { if (cell.Possibilities.StartsWith(numMultiples.ToString())) { multiplesCells.Add(cell); } } foreach (SudokuCell checkCell in multiplesCells) // multuplesCells is like 4/6, 1/3, 4/6, and 7/8 { List<SudokuCell> matchingCells = new List<SudokuCell>(); matchingCells.Add(checkCell); string theseUsed = checkCell.Possibilities; foreach (SudokuCell possibleMatchingCell in multiplesCells) { if (checkCell == possibleMatchingCell) continue; if (theseUsed == possibleMatchingCell.Possibilities) { matchingCells.Add(possibleMatchingCell); } } if (numMultiples == matchingCells.Count) { // this set of 4/6 foundSome |= CleanOtherCells(cells, theseUsed); // loop thru each individual number and see if they match up in a row/col/square lock based upon the type they're not. for (int i = 1; i < 10; i++) { if (theseUsed.Substring(i, 1) != "-") { ClearOutLockingSituations(matchingCells, i, type, ref foundSome); } } } } } }
private void ClearOutLockingSituations(List<SudokuCell> matches, int checkNum, CellGroupingType type, ref bool foundOne) { if (matches.Count > 0) { switch (type) { case CellGroupingType.Horizontal: case CellGroupingType.Vertical: // if type is a col/row, then see if the poss falls in same square int sqRow = matches[0].Row / 3; int sqCol = matches[0].Col / 3; bool sameSquare = true; foreach (SudokuCell match in matches) { if (sqRow != (match.Row / 3) || sqCol != (match.Col / 3)) sameSquare = false; } if (sameSquare) { List<SudokuCell> cellsInSquare = GetCellGroupingFor(matches[0], CellGroupingType.Square); foreach (SudokuCell cell in cellsInSquare) { if (matches.Contains(cell)) continue; // don't update one of the matches by accident foundOne |= SetCellPossibilityToFalse(cell, checkNum); } } break; case CellGroupingType.Square: // if type is group, then see if they are all possible in same row int rowMatch = matches[0].Row; bool sameRow = true; foreach (SudokuCell match in matches) { if (rowMatch != match.Row) sameRow = false; } if (sameRow) { for (int col = 0; col < 9; col++) { SudokuCell updateThisCell = solvedData[col, rowMatch]; if (matches.Contains(updateThisCell)) continue; // don't update one of the matches by accident foundOne |= SetCellPossibilityToFalse(updateThisCell, checkNum); } } // if type is group, then see if they are all possible in same column int colMatch = matches[0].Col; bool sameCol = true; foreach (SudokuCell matchedCell in matches) { if (colMatch != matchedCell.Col) sameCol = false; } if (sameCol) { for (int row = 0; row < 9; row++) { SudokuCell updateThisCell = solvedData[colMatch, row]; if (matches.Contains(updateThisCell)) continue; // don't update one of the matches by accident foundOne |= SetCellPossibilityToFalse(updateThisCell, checkNum); } } break; } } }
private void CheckForLockingSituations(List<SudokuCell> cells, CellGroupingType type, ref bool foundOne) { for (int checkNum = 1; checkNum < 10; checkNum++) { List<SudokuCell> matches = new List<SudokuCell>(); foreach (SudokuCell cell in cells) { if (cell.Number == 0) { if (cell.PossibleNumbers[checkNum]) matches.Add(cell); } } ClearOutLockingSituations(matches, checkNum, type, ref foundOne); } }