/// <summary>Reduces naked triples.</summary> private ReduceResult ReduceNakedTriples(ReduceResult result, SudokuState state) { if (SkipMethod(SudokuSolverMethods.NakedTriples, result)) { return result; } foreach (var singleValue in Puzzle.SingleValues) { foreach (var region in Puzzle.Regions) { var index0 = -1; var index1 = -1; var index2 = -1; var match = singleValue; foreach (var index in region) { var value = state[index]; if (!state.IsKnown(index) && (value & match) != SudokuPuzzle.Invalid) { match |= value; /**/ if (index0 == -1) { index0 = index; } else if (index1 == -1) { index1 = index; } else if (index2 == -1) { index2 = index; } else { index2 = -1; break; } } } // We found 3 cells. if (index2 != -1 && SudokuCell.Count(match) == 3) { foreach (var index in region) { if (index != index0 && index != index1 && index != index2) { result |= state.AndMask(index, ~match); } } } } } return result; }
/// <summary>Reduces hidden singles.</summary> /// <remarks> /// Very frequently, there is only one candidate for a given row, column or /// sub square, but it is hidden among other candidates. /// </remarks> private ReduceResult ReduceHiddenSingles(ReduceResult result, SudokuState state) { if (SkipMethod(SudokuSolverMethods.HiddenSingles, result)) { return result; } foreach (var region in Puzzle.Regions) { foreach (var singleValue in Puzzle.SingleValues) { var cnt = 0; var found = -1; foreach (var index in region) { var val = state[index]; if ((val & singleValue) != SudokuPuzzle.Invalid) { unchecked { cnt++; } if (state.IsKnown(index)) { found = -1; break; } else if (cnt == 1) { found = index; } } } if (cnt == 1 && found != -1) { result |= state.AndMask(found, singleValue); } else if (cnt == 0) { return ReduceResult.Inconsistend; } } } return result; }
/// <summary>Reduces options that should be in the intersection.</summary> private ReduceResult ReduceLockedCandidates(ReduceResult result, SudokuState state) { if (SkipMethod(SudokuSolverMethods.LockedCandidates, result)) { return result; } foreach (var region in Puzzle.Regions) { foreach (var other in region.Intersected) { ulong combined = 0; foreach (var index in region) { if (!other.Contains(index)) { combined |= state[index]; } } // There are options that should be in the intersection. if (combined != Puzzle.Unknown) { foreach (var index in other) { if (!region.Contains(index)) { var val = state[index]; var nw = val & combined; result |= state.AndMask(index, nw); } } } } } return result; }