public SudokuSolvingIterationAssumptionTechnique(SudokuGrid grid) : base(grid) { rowsOfNumbers = new SortedSet<byte>[Grid.Metrics.MaximumNumber]; columnsOfNumbers = new SortedSet<byte>[Grid.Metrics.MaximumNumber]; Grid.IterateLine(i => { rowsOfNumbers[i] = new SortedSet<byte>(); columnsOfNumbers[i] = new SortedSet<byte>(); }); blocksOfNumbers = new SortedSet<byte>[Grid.Metrics.MaximumNumber / Grid.Metrics.BlockHeight, Grid.Metrics.MaximumNumber / Grid.Metrics.BlockWidth]; Grid.IterateBlocksXY((x, y) => { blocksOfNumbers[y, x] = new SortedSet<byte>(); }); forbiddenCandidates = new SortedSet<byte>(); Grid.CellNumberChanged += (s, e) => RegisterCellAsClue(e.Cell); emptyCellsCount = Grid.Metrics.CellsTotal; //Grid.IterateLinesXY((x, y) => //{ // SudokuGridCell cell = Grid.Cells[y, x]; // if (cell.IsClue) // { // RegisterCellAsClue(cell); // } //}); }
/// <summary> /// Initializes a new instance of grid cell. /// </summary> /// <param name="parentGrid">The grid including this cell.</param> /// <param name="position">The cell's position at the specified grid.</param> /// <param name="number">The number substituted into this cell.</param> internal SudokuGridCell(SudokuGrid parentGrid, SudokuGridPosition position, byte number) { ParentGrid = parentGrid; Position = position; if (number == EmptyCellNumber) { this.number = number; Candidates = new CandidatesSortedSet(this); Candidates.ContradictionFound += (s, e) => ContradictionFound = true; switch (parentGrid.Constraints) { case SudokuGridConstraints.Traditional: for (byte i = 1; i <= parentGrid.Metrics.MaximumNumber; ++i) { Candidates.Add(i); } break; case SudokuGridConstraints.Diagonal: break; case SudokuGridConstraints.Even: break; case SudokuGridConstraints.Odd: break; case SudokuGridConstraints.Areas: break; } } else { Number = number; } }
private static void ShowSolution(SudokuGrid grid) { Console.WriteLine("Found solution:"); Console.WriteLine(); var sb = new StringBuilder(); char horDelim = '-'; char vertDelim = '|'; for (byte i = 0; i < 25; ++i) { sb.Append(horDelim); } string horDelims = sb.ToString(); sb.Clear(); for (int i = 0; i < 2; ++i) { sb.Append(" "); } string leftOffset = sb.ToString(); var defaultForeColor = Console.ForegroundColor; Action<string> writeColoredDelim = (data) => { Console.ForegroundColor = ConsoleColor.DarkGray; Console.Write(data); Console.ForegroundColor = defaultForeColor; }; writeColoredDelim(leftOffset + horDelims + "\n"); for (byte i = 0; i < grid.Metrics.MaximumNumber; ++i) { writeColoredDelim(leftOffset + vertDelim); for (byte j = 0; j < grid.Metrics.MaximumNumber; ++j) { Console.Write(" " + grid[i, j]); if ((j + 1) % 3 == 0) { writeColoredDelim(" " + vertDelim); } } Console.WriteLine(); if ((i + 1) % 3 == 0) { writeColoredDelim(leftOffset + horDelims + "\n"); } } Console.WriteLine(); }
// BUG: used to avoid buggy duplicate-code decision in solver classes -- get rid of as soon as possible internal static void AssignNewCell(SudokuGrid grid, SudokuGridCell cell) { cell.NumberChanged += (s, e) => grid.OnCellNumberChanged(new CellNumberChangedEventArgs((SudokuGridCell)s)); grid.cells[cell.Position.Y, cell.Position.X] = cell; }
protected SudokuSolvingTechnique(SudokuGrid grid) { Grid = grid; // BUG: the solver changes cells' collection via exactly the same pointer initialGridCells = grid.Cells; }
private SudokuGridCell[,] MakeAssumptionInCell(ref SudokuGridPosition? minCandidatesCellPos) { if (!minCandidatesCellPos.HasValue) { // TODO: optimize: lookup that kind of cell repetitively when its number of candidates changes (decreases): compare against the minimum value from a variable (where to put it?) minCandidatesCellPos = FindFirstCellWithMinimumCandidates(Grid).Position; } var minCandidatesCell = Grid.Cells[minCandidatesCellPos.Value.Y, minCandidatesCellPos.Value.X]; byte assumedNumber = minCandidatesCell.Candidates.ToArray()[0]; assumptionsGrid = (SudokuGrid)Grid.GetType() .GetConstructor(BindingFlags.Instance | BindingFlags.NonPublic, null, CallingConventions.HasThis, new[] { typeof(SudokuGridConstraints) }, null) .Invoke(new [] { (object)Grid.Constraints }); // BUG: !!! as we use the standard grid here, which was not initially intended to be used anywhere except for decode-and-construct scenarios, by the time we reach this code the assumptionsGrid's cells are not initialized yet -- consider introducing some sort of temporary 'grid' (most probably, a kind of 'cells-only layer'). For that reason one of the ctor's code sections was moved into the Reset() method var assumptionsGridSolver = new SudokuSolvingIterationAssumptionTechnique(assumptionsGrid); // WI: cell-to-cell iteration is a very intensive process -- use cells array cloning instead with targeted minCandidatesCell... altering var minCandidatesCellPosCopy = minCandidatesCellPos.Value; assumptionsGrid.IterateLinesXY((x, y) => { SudokuGridCell currCell; var currPos = new SudokuGridPosition(x, y, false); if (currPos.Equals(minCandidatesCellPosCopy)) { currCell = new SudokuGridCell(assumptionsGrid, currPos, assumedNumber); assumptionsGridSolver.lastFilledPos = currPos; assumptionsGridSolver.currCheckingPos = currPos; assumptionsGridSolver.currCheckingPos.Shift(1, assumptionsGrid.Metrics); } else { currCell = new SudokuGridCell(assumptionsGrid, currPos, Grid.Cells[y, x].Number); if (currCell.Candidates != null) { // just to bring into accord with the latest value from the 'parent' grid currCell.Candidates.IntersectWith(Grid.Cells[y, x].Candidates); } } SudokuGrid.AssignNewCell(assumptionsGrid, currCell); //assumptionsGrid.Cells[y, x] = currCell; }); //List<SudokuGridCell[,]> assumptionGridSolutuons = assumptionGridSolver.SearchSolutions(); //if (assumptionGridSolutuons.Count > 0) // correct assumption was made //{ // return assumptionsGrid.Cells; //} //SudokuGridCell[,] solution; if (assumptionsGridSolver.SearchSolutionDebug()) // correct assumption was made { //return solution; return assumptionsGrid.Cells; } // incorrect assumption was made (executes on contradiction only) minCandidatesCell.Candidates.Remove(assumedNumber); // if there were only two candidates, with assumedNumber being one of them, then the remaining one is a clue if (minCandidatesCell.IsClue) { minCandidatesCellPos = null; var newPos = new SudokuGridPosition(minCandidatesCell.Position.X, minCandidatesCell.Position.Y, false); lastFilledPos = newPos; currCheckingPos = newPos; currCheckingPos.Shift(1, Grid.Metrics); } return null; }
private SudokuGridCell FindFirstCellWithMinimumCandidates(SudokuGrid grid) { byte minCandidates = grid.Metrics.MaximumNumber; SudokuGridCell minCandidatesCell = null; grid.IterateLinesXY((x, y) => { var currCell = grid.Cells[y, x]; if (currCell.Candidates != null && currCell.Candidates.Count < minCandidates) { minCandidates = (byte)currCell.Candidates.Count; minCandidatesCell = currCell; } }); return minCandidatesCell; }
public static byte[] ToBinary(FileStream textFile, SudokuGrid grid, SudokuConvertionAlgorithm algorithm) { string content; textFile.Position = 0; using (var sr = new StreamReader(textFile)) { content = sr.ReadToEnd(); } textFile.Position = 0; return ToBinary(content, algorithm, grid.Constraints, grid.Metrics); }
public static byte[] ToBinary(SudokuGrid grid, SudokuConvertionAlgorithm algorithm) { var sb = new StringBuilder(grid.Metrics.CellsTotal); grid.IterateLinesXY((x, y) => sb.Append(grid.Cells[y, x].Number)); return ToBinary(sb.ToString(), algorithm, grid.Constraints, grid.Metrics); }