private static void Solve(PuzzleSetup puzzleSetup) { IncorrectGuesses = new Dictionary <int, Candidates>(); for (var i = 0; i < 81; i++) { IncorrectGuesses[i] = Candidates.None; } var puzzle = new PuzzleGrid(puzzleSetup); foreach (var cell in puzzle.Cells) { cell.Initialize(); } puzzle.Print(); bool solved; var result = Solve(puzzle, out solved); Console.WriteLine(solved ? "Solved!" : "Failed"); result.Print(); }
private static PuzzleGrid Solve(PuzzleGrid puzzle, out bool solved) { var anyChanges = false; do { anyChanges = false; var unsolvedCells = puzzle.Cells .Where(c => !c.Solution.HasValue) .ToArray(); if (!unsolvedCells.Any()) { solved = true; return(puzzle); } if (anyChanges |= unsolvedCells.TrySingleCandidateSolve()) { Console.WriteLine("Single candidate."); continue; } if (anyChanges |= unsolvedCells.TryUniqueCandidateSolve()) { Console.WriteLine("Unique candidate."); continue; } if (anyChanges |= puzzle.Boxes.TryCandidateLineElimination()) { Console.WriteLine("Candidate line."); continue; } if (anyChanges |= puzzle.AllUnits.TryNakedPairElimination()) { Console.WriteLine("Naked pair."); continue; } if (anyChanges |= puzzle.AllUnits.TryNakedTripleElimination()) { Console.WriteLine("Naked triple."); continue; } if (anyChanges |= puzzle.AllUnits.TryNakedQuadElimination()) { Console.WriteLine("Naked quadruple."); continue; } if (anyChanges |= puzzle.AllUnits.TryNakedQuintElimination()) { Console.WriteLine("Naked quintuplet."); continue; } if (anyChanges |= puzzle.TryDoublePairElimination()) { Console.WriteLine("Double pair."); continue; } if (anyChanges |= puzzle.TryClosedLoopCandidateElimination(loopScale: 2)) { Console.WriteLine("X-Wing."); continue; } if (anyChanges |= puzzle.TryClosedLoopCandidateElimination(loopScale: 3)) { Console.WriteLine("Swordfish."); continue; } if (anyChanges |= puzzle.TryClosedLoopCandidateElimination(loopScale: 4)) { Console.WriteLine("Closed loop, scale 4."); continue; } if (anyChanges |= puzzle.TryClosedLoopCandidateElimination(loopScale: 5)) { Console.WriteLine("Closed loop, scale 5."); continue; } //var mostSolvedCellIdx = unsolvedCells // .OrderBy(c => c.Candidates.CountExcluding(IncorrectGuesses[c.Idx])) // .First() // .Idx; //var clone = puzzle.DeepClone(); //var cell = clone.Cells[mostSolvedCellIdx]; //var nextGuess = cell.Candidates.FirstOrDefaultExcluding(IncorrectGuesses[mostSolvedCellIdx]); //if(nextGuess == Candidates.None) //{ // throw new InvalidOperationException($"No remaining guesses for cell {mostSolvedCellIdx}"); //} //Console.WriteLine($"Guessing {nextGuess} on cell {cell.Idx}"); //cell.Solve(nextGuess); //try //{ // Solve(clone, out solved); // if (solved) // { // return clone; // } // anyChanges = true; //} //catch (InvalidSolutionException) //{ // Console.WriteLine("Incorrect guess."); // IncorrectGuesses[mostSolvedCellIdx] |= nextGuess; // solved = false; // return clone; //} }while (anyChanges); solved = false; return(puzzle); }
public static bool ClosedLoop( this PuzzleGrid puzzle, byte loopScale, Func <PuzzleGrid, Cell[][]> getUnits, // row or cols Func <PuzzleGrid, Cell[][]> getOtherUnits, // cols or rows Func <Cell, byte> getIdxInOtherUnit) // RowIdx or ColIdx { var anyChanges = false; foreach (var candidate in CandidatesUtil.ALL) { var indiciesOfCandidateWithinUnits = new Dictionary <int, Index>(); for (var i = 0; i < 9; i++) { Index indicies; if (GetIndiciesOfCandidateIfOccuringTwice(getUnits(puzzle)[i], candidate, out indicies)) { indiciesOfCandidateWithinUnits.Add(i, indicies); } } if (indiciesOfCandidateWithinUnits.Count < loopScale) { continue; } var unitCount = indiciesOfCandidateWithinUnits.Count; var unitIdxGroups = indiciesOfCandidateWithinUnits.Select(i => i.Key).ToList().UniqueCombinations(loopScale); foreach (var unitIdxGroup in unitIdxGroups) { var units = indiciesOfCandidateWithinUnits .Where(i => unitIdxGroup.Contains(i.Key)) .ToArray(); var indicies = Index.None; foreach (var index in units.Select(u => u.Value)) { indicies |= index; } if (!indicies.HasNumberOfIndicies(loopScale)) { continue; } foreach (var unitIndexAndCellIndiciesPair in indiciesOfCandidateWithinUnits) { var unitIdx = unitIndexAndCellIndiciesPair.Key; var indexesInUnit = unitIndexAndCellIndiciesPair.Value.GetValues() .Select(idx => IndexUtil.INDEX_BYTE_MAP[idx]) .ToArray(); var cell1 = getUnits(puzzle)[unitIdx][indexesInUnit[0]]; var cell2 = getUnits(puzzle)[unitIdx][indexesInUnit[1]]; foreach (var cell in getOtherUnits(puzzle)[getIdxInOtherUnit(cell1)]) { if (cell == cell1 || cell == cell2) { continue; } anyChanges |= cell.RemoveCandidates(candidate); } } } } return(anyChanges); }