private void ReduceRegion(uint pair, SudokuRegion region, SudokuState state, ICollection <IEvent> events) { HiddenPairs.Clear(); foreach (var index in region) { var and = state[index] & pair; // at least on of the two is pressent. if (and != 0) { // If not both are present or we already had 2, return. if (and != pair || HiddenPairs.Count > 1) { return; } HiddenPairs.Add(index); } } if (HiddenPairs.Count == 2) { Fetch(pair, HiddenPairs, state, events); } }
private void Fetch(uint quad, SimpleList <int> buffer, SudokuRegion region, SudokuState state, ICollection <IEvent> events) { var reduced = false; var mask = ~quad; foreach (var index in region) { if (buffer.Contains(index)) { continue; } var result = state.And <ReduceNakedTriples>(index, mask); if (result is ValueFound) { events.Add(result); } else if (result is ReducedOption) { reduced = true; } } if (reduced) { events.Add(ReducedOptions.Ctor <ReduceNakedTriples>()); } }
private void ReduceRegion(int skip, SudokuRegion region, SudokuState state, ICollection <IEvent> events) { var quad = 0u; buffer.Clear(); foreach (var index in region.Skip(skip)) { var value = state[index]; if (SudokuCell.Count(value) < 4) { quad |= value; // Joined the represent more then 3 values. if (SudokuCell.Count(quad) > 4 || buffer.Count > 3) { return; } buffer.Add(index); } } if (buffer.Count == 4) { Fetch(quad, buffer, region, state, events); } }
private void Fetch(uint nakedPair, SudokuRegion region, SudokuState state, ICollection <IEvent> events) { IEvent result = NoReduction.Instance; var mask = ~nakedPair; foreach (var index in region) { var value = state[index]; if (value != nakedPair) { var test = state.And <ReduceNakedPairs>(index, mask); if (test is ValueFound) { events.Add(test); } else if (test is ReducedOption) { result = test; } } } if (result is ReducedOption) { events.Add(ReducedOptions.Ctor <ReduceNakedPairs>()); } }
/// <inheritdoc /> public void Solve(SudokuPuzzle puzzle, SudokuState state, ICollection <IEvent> events) { foreach (var region in puzzle.Regions) { foreach (var intersected in region.Intersected) { intersection.Clear(); intersection.AddRange(region.Intersect(intersected)); // We found candidate intersections if (intersection.Count > 1) { foreach (var value in puzzle.SingleValues) { var pre = events.Count; Solve(state, region, intersected, value, events); if (pre != events.Count) { return; } } } } } }
private void ReduceRegion(SudokuRegion region, SudokuState state, ICollection <IEvent> events) { var nakedPair = 0u; var count = 0; foreach (var index in region) { var value = state[index]; // nothing found yet. if (nakedPair == default) { if (SudokuCell.Count(value) == 2) { nakedPair = value; count++; } } // Equal to the first (potential) naked pair. else if (value == nakedPair && count++ > 2) { throw new InvalidPuzzleException(); } } if (count > 1) { Fetch(nakedPair, region, state, events); } }
private void CheckCells(SudokuState state, SudokuRegion region, uint singleValue, ICollection <IEvent> events) { var hidden = NoIndex; foreach (var index in region) { var value = state[index]; // the cell has the value. if ((singleValue & value) != 0) { // Already value, try next. if (singleValue == value) { return; } // not the first if (hidden != NoIndex) { return; } hidden = index; } } if (hidden == NoIndex) { return; } events.Add(state.And <ReduceHiddenSingles>(hidden, singleValue)); }
public void Solve(SudokuPuzzle puzzle, SudokuState state, ICollection <IEvent> events) { var count = -1; while (count != events.Count) { count = events.Count; for (var i = 0; i < solvers.Length; i++) { var solver = solvers[i]; solver.Solve(puzzle, state, events); if (events.Count != count) { if (state.IsSolved) { events.Add(SolvedPuzzle.Instance); return; } i = solvers.Length; } } } }
/// <inheritdoc /> public void Solve(SudokuPuzzle puzzle, SudokuState state, ICollection <IEvent> events) { foreach (var region in puzzle.Regions) { var pre = events.Count; ReduceRegion(region, state, events); if (pre != events.Count) { return; } } }
/// <summary>Solves a Sudoku puzzle given the Sudoku state.</summary> public SudokuState Solve(SudokuState sudokuState) { // As states are mutable, create a copy. var state = sudokuState.Copy(); var events = new List <IEvent>(128); Solver.Solve(Puzzle, state, events); foreach (var @event in events) { Console.WriteLine(@event); } return(state); }
/// <inheritdoc /> public void Solve(SudokuPuzzle puzzle, SudokuState state, ICollection <IEvent> events) { // check all groups. foreach (var region in puzzle.Regions) { foreach (var singleValue in puzzle.SingleValues) { var pre = events.Count; CheckCells(state, region, singleValue, events); if (pre != events.Count) { return; } } } }
private void Fetch(uint pair, SimpleList <int> hiddenPairs, SudokuState state, ICollection <IEvent> events) { IEvent result = NoReduction.Instance; foreach (var index in hiddenPairs) { var test = state.And <ReduceHiddenPairs>(index, pair); if (test is ReducedOption) { result = test; } } if (result is ReducedOption) { events.Add(ReducedOptions.Ctor <ReduceHiddenPairs>()); } }
/// <inheritdoc /> public void Solve(SudokuPuzzle puzzle, SudokuState state, ICollection <IEvent> events) { foreach (var region in puzzle.Regions) { foreach (var pair in Pairs) { var pre = events.Count; ReduceRegion(pair, region, state, events); // We found some, let simpler strategies try again. if (pre != events.Count) { return; } } } }
/// <inheritdoc /> public void Solve(SudokuPuzzle puzzle, SudokuState state, ICollection <IEvent> events) { var reduced = false; for (var index = 0; index <= puzzle.MaximumIndex; index++) { // For known cells only. if (state.IsKnown(index)) { var mask = ~state[index]; // for all groups the cell belongs to. foreach (var group in puzzle.Lookup[index]) { foreach (var target in group) { if (target == index) { continue; } var result = state.And <ReduceNakedSingles>(target, mask); if (result is ReducedOption) { reduced = true; } else if (result is ValueFound) { events.Add(result); } } } } } if (reduced) { events.Add(ReducedOptions.Ctor <ReduceNakedSingles>()); } }
private void Solve(SudokuPuzzle puzzle, SudokuState state, ICollection <IEvent> events, SudokuRegionType type, SudokuRegionType otherType) { var pre = events.Count; foreach (var first in puzzle.Regions.Where(r => r.RegionType == type)) { foreach (var second in puzzle.Regions.Where(r => r.RegionType == otherType)) { if (first != second) { foreach (var value in SudokuCell.Singles) { Solve(value, first, second, otherType, state, events); if (events.Count != pre) { return; } } } } } }
private void Solve(SudokuState state, SudokuRegion region, SudokuRegion intersected, uint value, ICollection <IEvent> events) { var count = 0; foreach (var index in region) { if ((state[index] & value) != 0) { if (intersection.Contains(index)) { count++; } else { return; } } } if (count > 1) { Fetch(value, intersection, intersected, state, events); } }
private bool Fetch(uint value, SudokuRegion region, SudokuState state, ICollection <IEvent> events) { var reducded = false; var mask = ~value; foreach (var index in region) { if (buffer.Contains(index)) { continue; } var result = state.And <ReduceXWing>(index, mask); if (result is ValueFound) { events.Add(result); } else if (result is ReducedOption) { reducded = true; } } return(reducded); }
private void Fetch(uint value, SimpleList <int> intersection, SudokuRegion intersected, SudokuState state, ICollection <IEvent> events) { IEvent result = NoReduction.Instance; var mask = ~value; foreach (var index in intersected) { // items in the shared section should be skipped. if (intersection.Contains(index)) { continue; } var test = state.And <ReducePointingPairs>(index, mask); if (test is ValueFound) { events.Add(test); } else if (test is ReducedOption) { result = test; } } if (result is ReducedOption) { events.Add(ReducedOptions.Ctor <ReduceNakedPairs>()); } }
public void Solve(SudokuPuzzle puzzle, SudokuState state, ICollection <IEvent> events) { Solve(puzzle, state, events, SudokuRegionType.Row, SudokuRegionType.Column); Solve(puzzle, state, events, SudokuRegionType.Column, SudokuRegionType.Row); }
public void Solve(uint value, SudokuRegion first, SudokuRegion second, SudokuRegionType otherType, SudokuState state, ICollection <IEvent> events) { buffer.Clear(); for (var index = 0; index < 9; index++) { var indexFirst = first[index]; var indexSecond = second[index]; var joinFirst = state[indexFirst] & value; var joinSecond = state[indexSecond] & value; if (joinFirst == 0) { if (joinSecond != 0) { return; } } else { if (joinSecond == 0 || buffer.Count > 3) { return; } buffer.Add(indexFirst); buffer.Add(indexSecond); } } if (buffer.Count == 4) { var reducded = Fetch( value, first.Intersected.FirstOrDefault(r => r.RegionType == otherType), state, events); reducded |= Fetch( value, second.Intersected.FirstOrDefault(r => r.RegionType == otherType), state, events); if (reducded) { events.Add(ReducedOptions.Ctor <ReduceXWing>()); } } }