public void Apply(MutablePuzzle puzzle, RegionQueue changedRegions) { while (changedRegions.TryDequeueOfType(RegionType.Box, out int boxIndex)) { var box = puzzle.Puzzle.Boxes[boxIndex]; var placedDigits = box.GetPlacedDigits(); for (int digit = 1; digit <= Puzzle.LineLength; digit++) { var value = SudokuValues.FromHumanValue(digit); if (placedDigits.HasAnyOptions(value)) { continue; } var rows = SudokuValues.None; var cols = SudokuValues.None; for (var i = 0; i < Puzzle.LineLength; i++) { var cellValue = box[i]; var cellCoord = box.GetCoordinate(i); if (!cellValue.IsSingle && cellValue.HasAnyOptions(value)) { rows = rows.AddOptions(SudokuValues.FromIndex(cellCoord.Row)); cols = cols.AddOptions(SudokuValues.FromIndex(cellCoord.Column)); } } if (rows.IsSingle) { var region = puzzle.Puzzle.Rows[rows.ToIndex()]; var anyChanged = RemoveFromOtherBoxesInRegion(puzzle, region, value, boxIndex); if (anyChanged) { #if DEBUG Program.Debugger.AddAction($"{digit}s in {box} remove others in {region}."); #endif return; } } if (cols.IsSingle) { var region = puzzle.Puzzle.Columns[cols.ToIndex()]; var anyChanged = RemoveFromOtherBoxesInRegion(puzzle, region, value, boxIndex); if (anyChanged) { #if DEBUG Program.Debugger.AddAction($"{digit}s in {box} remove others in {region}."); #endif return; } } } } }
public void Apply(MutablePuzzle puzzle, RegionQueue changedRegions) { while (changedRegions.TryDequeue(puzzle, out var region)) { var placedDigits = region.GetPlacedDigits(); FindTuple(puzzle, changedRegions, region, placedDigits); } }
private void FindTuple(MutablePuzzle puzzle, RegionQueue regions, Region region, SudokuValues placedDigits) { var combinations = Helpers.GetCombinationIndices(Puzzle.LineLength, _size); for (int i = 0; i < combinations.Length; i++) { var comb = combinations[i]; if (placedDigits.HasAnyOptions(comb)) { // skip any tuples that include placed digits continue; } var positions = region.GetPositions(comb); if (positions.GetOptionCount() != _size) { // these digits are placeable in more than tupleSize spots, so not hidden tuple continue; } // we found a hidden tuple! var options = ArrayPool <int> .Shared.Rent(Puzzle.LineLength); var count = positions.CopyIndices(options); var opposite = comb.Invert(); var anyChanged = false; for (var index = 0; index < count; index++) { var cell = region[options[index]]; if (!cell.IsSingle && cell.HasAnyOptions(opposite)) { var update = region.RemoveOptions(options[index], opposite); puzzle.RemoveOptions(update); anyChanged = true; regions.Enqueue(RegionType.Row, update.Coordinate.Row); regions.Enqueue(RegionType.Column, update.Coordinate.Column); regions.Enqueue(RegionType.Box, update.Coordinate.Box); } } ArrayPool <int> .Shared.Return(options); if (anyChanged) { #if DEBUG Program.Debugger.AddAction($"Hidden {comb} tuple in {region}"); #endif return; } } }
public void EnqueueAll(RegionQueue other) { _currentValues |= other._currentValues; _lastDequeueIndex = 0; }
public void ApplyToRegionQueue(RegionQueue queue) { queue.EnqueueAll(Queue); }
public void Absorb(MutablePuzzle other) { Array.Copy(other._cells, _cells, _cells.Length); _currentChangeSet.Queue.EnqueueAll(RegionQueue.GetFull()); }
private void FindTuple(MutablePuzzle puzzle, RegionQueue regions, Region region, SudokuValues placedDigits) { var combinations = Helpers.GetCombinationIndices(Puzzle.LineLength, _size); for (int j = 0; j < combinations.Length; j++) { var comb = combinations[j]; if (placedDigits.HasAnyOptions(comb)) { // skip any tuples that include placed digits continue; } var indices = ArrayPool <int> .Shared.Rent(_size); var count = comb.CopyIndices(indices); var possibleValues = SudokuValues.None; for (int i = 0; i < count; i++) { var cell = region[indices[i]]; possibleValues = possibleValues.AddOptions(cell); } ArrayPool <int> .Shared.Return(indices); var optionsCount = possibleValues.GetOptionCount(); if (optionsCount == _size) { // we found a tuple! for (var i = 0; i < Puzzle.LineLength; i++) { var otherCell = region[i]; if (otherCell.IsSingle) { continue; } if (!otherCell.HasAnyOptions(possibleValues)) { continue; } if (comb.HasAnyOptions(SudokuValues.FromIndex(i))) { continue; } var newCell = region.RemoveOptions(i, possibleValues); puzzle.RemoveOptions(newCell); regions.Enqueue(RegionType.Row, newCell.Coordinate.Row); regions.Enqueue(RegionType.Column, newCell.Coordinate.Column); regions.Enqueue(RegionType.Box, newCell.Coordinate.Box); #if DEBUG Program.Debugger.AddAction($"{possibleValues} tuple in {region}."); #endif } } } }