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); } } } } } } }
protected override void OperateOn(SudokuModel model) { for (var row = 0; row < model.Size; ++row) { for (var col = 0; col < model.Size; ++col) { EliminateDuplicates(model, col, row); } } }
public Solver(SudokuModel model) { _model = model; var multiStrategy = new MultiStrategy( new LoneRemainingCell(), new SetIsolation(), new TrialAndError(new LoneRemainingCell())); multiStrategy.ContainedStrategyFinished += HandleScanFinished; _eliminationStrategy = multiStrategy; }
public void Run(SudokuModel model) { var initTime = DateTime.Now; var initElim = model.EliminatedCount; OperateOn(model); TimeLastRun = DateTime.Now - initTime; TotalTime += TimeLastRun; EliminatedLastRun = model.EliminatedCount - initElim; TotalEliminated += EliminatedLastRun; ++Runs; }
public static void EliminateDuplicates(SudokuModel model, int col, int row) { if (model.IsSolved(col, row)) { var value = model.GetValue(col, row); foreach (var region in model.GetIntersectingRegions(col, row)) { foreach (var other in model.GetCells(region.Type, region.I)) { if (other.Column != col || other.Row != row) { model.Eliminate(other.Column, other.Row, value); } } } } }
protected override void OperateOn(SudokuModel model) { if (_strategies.Length == 0) { return; } var i = 0; do { var strategy = _strategies[i]; strategy.Run(model); if (ContainedStrategyFinished != null) { ContainedStrategyFinished(strategy); } // If we've eliminated something, jump back to the first strategy; otherwise // go to the next strategy. i = (strategy.EliminatedLastRun != 0) ? 0 : (i + 1); } while (i < _strategies.Length); }
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; }
void tOperateOn(SudokuModel model) { // we retain the index, as it's more efficient // to keep operating in the same area than to start over at cell[0,0] // every time. var sz = model.SizeSquared; for (int i = 0; i < sz; ++i) { int index; lock (this) { index = _index; _index += 36; _index %= sz; } var col = index % 25; var row = index / 25; if (OperateOn(col, row, model)) { return; } // go to the next cell } // if we've gone through the whole model // without eliminating anything, then there's no use // trying anymore. }
protected override void OperateOn(SudokuModel model) { // we retain the index, as it's more efficient // to keep operating in the same area than to start over at cell[0,0] // every time. var sz = model.SizeSquared; Parallel.For(0, 625, (i, loopState) => { int index; lock (this) { index = _index; _index += 36; _index %= sz; } var col = index % 25; var row = index / 25; if (OperateOn(col, row, model)) { loopState.Stop(); } // go to the next cell }); // if we've gone through the whole model // without eliminating anything, then there's no use // trying anymore. }
void OpenFile(string name) { _name = name; // Open and read the file try { TextReader reader = new FileInfo(name).OpenText(); var text = reader.ReadToEnd(); reader.Dispose(); var lines = text.Split(new[] {"\r\n"}, StringSplitOptions.RemoveEmptyEntries); // Create a new model and solver, and add event listeners if (_model != null) { _model.ModelChanged -= HandleModelModelChanged; _solver.ScanFinished -= HandleSolverScanFinished; _solver.Finished -= HandleSolverFinished; } _model = new SudokuModel(lines.Length); _solver = new Solver(_model); _model.ModelChanged += HandleModelModelChanged; _solver.ScanFinished += HandleSolverScanFinished; _solver.Finished += HandleSolverFinished; // Update the screen _grid.Model = _model; _txtProgress.Clear(); // Load data into the model for (var row = 0; row < lines.Length; ++row) { var cells = lines[row].Split(','); for (var col = 0; col < lines.Length; ++col) { if (!string.IsNullOrEmpty(cells[col])) { _model.SetValue(col, row, cells[col][0] - 'A'); } } } } catch (FileNotFoundException) {} }
protected abstract void OperateOn(SudokuModel model);
/// <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; }