protected override void OperateOn(SudokuModel model) { for (var iType = 0; iType < 3; ++iType) { var type = (RegionType)iType; for (var i = 0; i < model.Size; ++i) { var region = new Region(type, i); var tuple = new Tuple<SudokuModel, Region>(model, region); if (GetCheckedIteration(tuple) < model.GetLastChangedIterRegion(type, i)) { _checkedIteration[tuple] = model.ChangeCount; foreach (var unsolved in model.GetUnsolvedValues(type, i)) { var timesFound = 0; Cell? foundAt = null; foreach (var cell in model.GetCells(type, i)) { if ((model.GetPossibilitySetCell(cell.Column, cell.Row) & (1 << unsolved)) != 0) { ++timesFound; foundAt = cell; if (timesFound > 1) { break; } } } if (timesFound == 1) { if (foundAt != null) { model.SetValueOptimized(foundAt.Value.Column, foundAt.Value.Row, unsolved, type, i); } } } } } } }
static void IsolateSet(int set, Region region, SudokuModel model) { var cells = model.GetCells(region.Type, region.I); var cellsNotContainedBySet = cells.Where(cell => (model.GetPossibilitySetCell(cell.Column, cell.Row) | set) != set).ToList(); var numCellsContainedBySet = cells.Length - cellsNotContainedBySet.Count; if (numCellsContainedBySet != set.HiBitCount()) { return; } // we now know that each of the numbers in the set must be exclusively in // one of the contained cells, so we eliminate that set from all other cells' // possibility bits. var mask = ~set; foreach (var cell in cellsNotContainedBySet) { var poss = model.GetPossibilitySetCell(cell.Column, cell.Row); model.SetPossibilitySetCell(cell.Column, cell.Row, poss & mask); } }
protected override void OperateOn(SudokuModel model) { // We could look at all 2^N possible sets on all 3N of the model's regions, // but it is more efficient to only use the // possiblity set of each cell, and isolate that set on each intersecting region. for (var row = 0; row < model.Size; ++row) { for (var col = 0; col < model.Size; ++col) { if (!model.IsSolved(col, row)) { foreach (var region in model.GetIntersectingRegions(col, row)) { var checkedIter = GetCheckedIteration(region); if (checkedIter < model.GetLastChangedIterRegion(region.Type, region.I)) { _checkedIteration[region] = checkedIter; IsolateSet(model.GetPossibilitySetCell(col, row), region, model); } } } } } }
bool OperateOn(int col, int row, SudokuModel model) { if (!model.IsSolved(col, row)) { // obviously can't eliminate anything in a solved cell. // try each int i that is a possibility for the cell, and see if an error results foreach (var i in model.GetPossibilitySetCell(col, row).HighBitPositions()) { var clone = new SudokuModel(model); clone.SetValue(col, row, i); _elimStrategy.Run(clone); if (clone.IsConsistent()) { continue; } // If so, we can eliminate that from the original model. model.Eliminate(col, row, i); return true; // return immediately after eliminating something, since // this is a slow algorithm, and we want our faster // algorithms to see if they make some more eliminations first. } } return false; }
/// <summary> /// Copy constructor /// </summary> /// <param name = "model"></param> public SudokuModel(SudokuModel model) { // Initialize our variables var size = model.Size; _size = size; _sizeSqrt = Convert.ToInt32(Math.Sqrt(size)); _sizeSquared = size * size; _sizeCubed = _sizeSquared * size; _possibilitySetModel = (1 << _size) - 1; _possibilitySetCell = new int[Size, Size]; _remainingPossibilityCount = new int[Size, Size]; _value = new int[Size, Size]; _lastChangedIterCell = new int[Size, Size]; // Initialize the Cell objects, and the cache values for (var col = 0; col < size; ++col) { for (var row = 0; row < size; ++row) { _possibilitySetCell[col, row] = model.GetPossibilitySetCell(col, row); _remainingPossibilityCount[col, row] = model.GetRemainingPossibilityCount(col, row); _value[col, row] = model.GetValue(col, row); _lastChangedIterCell[col, row] = model.GetLastChangedIterCell(col, row); CellChanged = null; } } CellChanged += HandleCellChanged; _solved = new int[3, _size]; _lastChangedIterRegion = new int[3, _size]; _cellsRegion = new Cell[3, _size][]; _intersectingRegions = new Region[Size, Size][]; for (var i = 0; i < _size; ++i) { _lastChangedIterRegion[0, i] = model._lastChangedIterRegion[0, i]; _lastChangedIterRegion[1, i] = model._lastChangedIterRegion[0, i]; _lastChangedIterRegion[2, i] = model._lastChangedIterRegion[0, i]; SetLastChangedIterRegion(RegionType.Column, i, -1); SetLastChangedIterRegion(RegionType.Row, i, -1); SetLastChangedIterRegion(RegionType.Square, i, -1); _solved[0, i] = model._solved[0, i]; _solved[1, i] = model._solved[1, i]; _solved[2, i] = model._solved[2, i]; var colCells = new Cell[_size]; for (var j = 0; j < _size; ++j) { colCells[j] = new Cell(i, j); } _cellsRegion[(int)RegionType.Column, i] = colCells; var rowCells = new Cell[_size]; for (var j = 0; j < _size; ++j) { rowCells[j] = new Cell(j, i); } _cellsRegion[(int)RegionType.Row, i] = rowCells; var sqCells = new Cell[_size]; var sqrCol = i % _sizeSqrt; var sqrRow = i / _sizeSqrt; var startCol = sqrCol * _sizeSqrt; var startRow = sqrRow * _sizeSqrt; for (var c = 0; c < _sizeSqrt; ++c) { for (var r = 0; r < _sizeSqrt; ++r) { sqCells[r * _sizeSqrt + c] = new Cell(c + startCol, r + startRow); } } _cellsRegion[(int)RegionType.Square, i] = sqCells; } SolvedCount = model.SolvedCount; EliminatedCount = model.EliminatedCount; ChangeCount = model.ChangeCount; LastChangedCell = model.LastChangedCell; }