public static Grid Minimize(Grid grid) { IList removeCandidates = new ArrayList(); for (int cellNumber = 0; cellNumber < 81; cellNumber++) { int row = cellNumber / 9; int column = cellNumber % 9; if (grid.cells[row, column] != 0) { removeCandidates.Add(cellNumber); } } while (removeCandidates.Count > 0) { int removeIndex = random.Next(removeCandidates.Count); int removeCellNumber = (int)removeCandidates[removeIndex]; int row = removeCellNumber / 9; int column = removeCellNumber % 9; int value = grid.cells[row, column]; grid.cells[row, column] = 0; if (!ValidNumberPlace(grid)) { grid.cells[row, column] = value; } else { //return Minimize(grid); } removeCandidates.RemoveAt(removeIndex); } return grid; }
public static Grid Solve(Grid grid) { IList solutions = Solve((Grid)grid.Clone(), 1); if (solutions.Count == 0) { return null; } else { return (Grid)solutions[0]; } }
public object Clone() { Grid clone = new Grid(this.BlocksAcross); for (int row = 0; row < cellsInRow; row++) { for (int column = 0; column < cellsInRow; column++) { clone.cells[row, column] = cells[row, column]; } } return clone; }
public static bool ValidNumberPlace(Grid grid) { // Check only one solution exists IList solutions = Solve((Grid)grid.Clone(), 2); if (solutions.Count == 1) { return true; } // Either unsolvable or multiple solutions return false; }
public static bool CheckMinimality(Grid grid) { Grid temp = (Grid)grid.Clone(); for (int row = 0; row < temp.CellsInRow; row++) { for (int column = 0; column < temp.CellsInRow; column++) { if (temp.cells[row, column] != 0) { int value = temp.cells[row, column]; temp.cells[row, column] = 0; if (ValidNumberPlace(temp)) { return false; } temp.cells[row, column] = value; } } } return true; }
protected override void OnClicked(int controlId, GUIControl control, Action.ActionType actionType) { if (control == btnSolve) { // Solve grid Grid solution = Solver.Solve(grid); if (solution != null) { for (int row = 0; row < grid.CellsInRow; row++) { for (int column = 0; column < grid.CellsInRow; column++) { int cellControlId = (1000 * (row + 1)) + column; CellControl cntlFoc = (CellControl)GetControl(cellControlId); if (cntlFoc.editable) { cntlFoc.CellValue = solution.cells[row, column]; cntlFoc.M_dwDisabledColor = m_dwCellIncorrectTextColor; cntlFoc.editable = false; } } } } } else if (control == btnNewGame) { //new game GUIWaitCursor.Show(); int minrating = 0; int maxrating = 0; ClearGrid(); Grid puzzle = new Grid(); switch ((LevelName)_Settings.Level) { case LevelName.Kids: minrating = 550; maxrating = 999; break; case LevelName.Easy: minrating = 450; maxrating = 650; break; case LevelName.Medium: minrating = 250; maxrating = 550; break; case LevelName.Hard: minrating = 0; maxrating = 250; break; } puzzle = GenerateLevel(puzzle, minrating, maxrating); gameRating = Solver.Rate(puzzle); //puzzle = Solver.Generate(3); Grid solution = Solver.Solve(puzzle); if ((LevelName)_Settings.Level == LevelName.Easy) { puzzle = Solver.FillOutCells(puzzle, solution, 10); gameRating = Solver.Rate(puzzle); } else if ((LevelName)_Settings.Level == LevelName.Kids) { puzzle = Solver.FillOutCells(puzzle, solution, 20); gameRating = Solver.Rate(puzzle) * 2; } for (int row = 0; row < grid.CellsInRow; row++) { for (int column = 0; column < grid.CellsInRow; column++) { int cellControlId = (1000 * (row + 1)) + column; CellControl cntlFoc = (CellControl)GetControl(cellControlId); cntlFoc.CellValue = puzzle.cells[row, column]; if (cntlFoc.CellValue > 0) { cntlFoc.editable = false; } else { cntlFoc.SolutionValue = solution.cells[row, column]; } } } grid = puzzle; ResetCandidates(); GUIWaitCursor.Hide(); StartTimer(); gameRunning = true; if (_Settings.Show || _Settings.Block) { isScoreGame = false; } else { isScoreGame = true; } } else if (control == btnBlockInvalidMoves) { _Settings.Block = btnBlockInvalidMoves.Selected; if (btnBlockInvalidMoves.Selected) { if (btnShowInvalidMoves.Selected) { _Settings.Show = btnShowInvalidMoves.Selected = false; } isScoreGame = false; } _Settings.Save(); } else if (control == btnClear) { ClearGrid(); ResetCandidates(); } else if (control == btnShowInvalidMoves) { _Settings.Show = btnShowInvalidMoves.Selected; if (btnShowInvalidMoves.Selected) { if (btnBlockInvalidMoves.Selected) { _Settings.Block = btnBlockInvalidMoves.Selected = false; } isScoreGame = false; } ShowInvalid(); _Settings.Save(); } else if (control == btnLevel) { switch ((LevelName)_Settings.Level) { case LevelName.Kids: _Settings.Level = (int)LevelName.Easy; break; case LevelName.Easy: _Settings.Level = (int)LevelName.Medium; break; case LevelName.Medium: _Settings.Level = (int)LevelName.Hard; break; case LevelName.Hard: _Settings.Level = (int)LevelName.Kids; break; } UpdateButtonStates(); _Settings.Save(); } else if (control == btnHelpOnce) { int candidateIndex = random.Next(81 - grid.CountFilledCells()); int m = -1, row = 0, column = 0; isScoreGame = false; for (row = 0; row < 9 && m < candidateIndex; row++) { for (column = 0; column < 9 && m < candidateIndex; column++) { int cellControlId = (1000 * (row + 1)) + column; CellControl cntlFoc = (CellControl)GetControl(cellControlId); if (cntlFoc.editable == true && cntlFoc.CellValue == 0) { m++; if (m == candidateIndex) { cntlFoc.CellValue = cntlFoc.SolutionValue; grid.cells[row, column] = cntlFoc.SolutionValue; } } } CheckCandidates(); } } else if (control == btnResetGame) { ResetGame(); } base.OnClicked(controlId, control, actionType); }
public static Grid FillOutCells(Grid grid, Grid solution, int number) { for (; number > 0; number--) { int candidateIndex = random.Next(81 - grid.CountFilledCells()); int m = -1, i = 0, j = 0; for (i = 0; i < 9 && m < candidateIndex; i++) { for (j = 0; j < 9 && m < candidateIndex; j++) { if (grid.cells[i, j] == 0) { m++; if (m == candidateIndex) { grid.cells[i, j] = solution.cells[i, j]; } } } } } return grid; }
public static bool FindCandidateInBox(Grid grid, int row, int col, int Num) { int firstRow = (row / 3) * 3; int firstCol = (col / 3) * 3; for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { if (grid.IsCellEmpty(firstRow + i, firstCol + j) && grid.Possibilities(firstRow + i, firstCol + j).Contains(Num) && !(firstRow + i != row || firstCol + j != col)) { return true; } } } return false; }
public static bool FindCandidateInCol(Grid grid, int row, int col, int Num) { for (int i = 0; i < grid.CellsInRow; i++) { if (grid.IsCellEmpty(i, col) && i != row && grid.Possibilities(i, col).Contains(Num)) { return true; } } return false; }
/// <summary> /// Find all Unique Candidates in grid /// and fill out the uniqueCandidates Array in the grid /// </summary> /// <param name="grid">Grid</param> /// <returns>the number of Unique Candidates</returns> public static int FindUniqueCandidates(Grid grid) { // Grid grid = (Grid)gridOrg.Clone(); grid.resetUniqueCandidates(); nodes = 0; int uniquesCand = 0; unsolvableCell = false; //find Unique Candidates in rows for (int searchRow = 0; searchRow < grid.CellsInRow; searchRow++) { for (int searchCol = 0; searchCol < grid.CellsInRow; searchCol++) { if (!grid.IsCellEmpty(searchRow, searchCol)) { continue; } IList candidates = grid.Possibilities(searchRow, searchCol); IList candidates2 = new ArrayList(candidates); if (candidates.Count > 1) { for (int cand = 0; cand < candidates.Count; cand++) { if (FindCandidateInRow(grid, searchRow, searchCol, (int)candidates[cand])) { candidates2.Remove(candidates[cand]); } } } if (candidates2.Count == 1) { grid.uniqueCandidates[searchRow, searchCol] = (int)candidates2[0]; } } } //find Unique Candidates in colums for (int searchCol = 0; searchCol < grid.CellsInRow; searchCol++) { for (int searchRow = 0; searchRow < grid.CellsInRow; searchRow++) { if (!grid.IsCellEmpty(searchRow, searchCol)) { continue; } IList candidates = grid.Possibilities(searchRow, searchCol); IList candidates2 = new ArrayList(candidates); if (candidates.Count > 1) { for (int cand = 0; cand < candidates.Count; cand++) { if (FindCandidateInCol(grid, searchRow, searchCol, (int)candidates[cand])) { candidates2.Remove(candidates[cand]); } } } if (candidates2.Count == 1) { grid.uniqueCandidates[searchRow, searchCol] = (int)candidates2[0]; } } } //find Unique Candidates in boxes for (int searchRow = 0; searchRow < grid.CellsInRow; searchRow++) { for (int searchCol = 0; searchCol < grid.CellsInRow; searchCol++) { if (!grid.IsCellEmpty(searchRow, searchCol)) { continue; } IList candidates = grid.Possibilities(searchRow, searchCol); IList candidates2 = new ArrayList(candidates); if (candidates.Count > 1) { for (int cand = 0; cand < candidates.Count; cand++) { if (FindCandidateInBox(grid, searchRow, searchCol, (int)candidates[cand])) { candidates2.Remove(candidates[cand]); } } } else { if (candidates.Count == 1) { uniquesCand++; } else { unsolvableCell = true; } } if (candidates2.Count == 1) { grid.uniqueCandidates[searchRow, searchCol] = (int)candidates2[0]; } } } for (int i = 0; i < 9; i++) { for (int j = 0; j < 9; j++) { if (grid.uniqueCandidates[i, j] != 0) { nodes++; } } } nodes = nodes + (uniquesCand / 2); return nodes; }
/// <summary> /// rate a grid /// returns it as int /// the lower the harder /// </summary> /// <param name="grid">Grid</param> /// <returns></returns> public static int Rate(Grid gridOrg) { Grid grid = (Grid)gridOrg.Clone(); int rate = 0; rateAll = 0; // for(int trys = 0; trys<10;trys++) // { // grid = (Grid)gridOrg.Clone(); // rate = 0; while (grid.CountFilledCells() < (grid.CellsInRow * grid.CellsInRow)) { int cand = FindUniqueCandidates(grid); rate += cand; if (cand > 0) { int candidateIndex = random.Next(cand); int m = -1, i = 0, j = 0, candidateRow = 0, candidateCol = 0; for (i = 0; i < 9 && m < candidateIndex; i++) { for (j = 0; j < 9 && m < candidateIndex; j++) { if (grid.uniqueCandidates[i, j] != 0) { m++; if (m == candidateIndex) { candidateRow = i; candidateCol = j; } } } } grid.cells[candidateRow, candidateCol] = grid.uniqueCandidates[candidateRow, candidateCol]; } else { //rate = rate - ((grid.BlocksAcross * grid.BlocksAcross) - grid.CountFilledCells()); //no more unique cells -> difficult grid rate = grid.CountFilledCells(); break; } } // rateAll += rate; // MediaPortal.GUI.Library.Log.WriteFile(MediaPortal.GUI.Library.LogType.Log, "Soduko Rate end "+trys+" notes: {0}", rate); // } return rate; }
/// <summary> /// Solve given sudoku grid and solutions upto maximum number specified /// </summary> /// <param name="g"></param> /// <returns></returns> public static IList Solve(Grid grid, int maxSolutions) { ArrayList solutions = new ArrayList(); // If grid is solved then return as solution if (grid.CountFilledCells() == (grid.CellsInRow * grid.CellsInRow)) { solutions.Add(grid.Clone()); return solutions; } // Solve singles //Singles(grid); // Choose unsolved cell int leastCandidatesRow = -1; int leastCandidatesColumn = -1; IList leastCandidates = null; for (int row = 0; row < grid.CellsInRow; row++) { for (int column = 0; column < grid.CellsInRow; column++) { if (grid.cells[row, column] == 0) { IList candidates = grid.Possibilities(row, column); // If cell has no possible value then grid is not solvable so quit now if (candidates.Count == 0) { return solutions; } else if (leastCandidates == null || leastCandidates.Count > candidates.Count) { leastCandidatesRow = row; leastCandidatesColumn = column; leastCandidates = candidates; } } } } // For all candidates of unsolved cell if (leastCandidates != null) { while (leastCandidates.Count > 0) { // Set candidate int candidateIndex = random.Next(leastCandidates.Count); grid.cells[leastCandidatesRow, leastCandidatesColumn] = (int)leastCandidates[candidateIndex]; leastCandidates.RemoveAt(candidateIndex); Grid nextLevelGrid = (Grid)grid.Clone(); IList nextLevelSolutions = Solve(nextLevelGrid, maxSolutions); solutions.AddRange(nextLevelSolutions); // Trim number of solutions so we don't exceed maximum required if (solutions.Count > maxSolutions) { solutions.RemoveRange(0, solutions.Count - maxSolutions); } if (solutions.Count == maxSolutions) { return solutions; } } } return solutions; }
public void HiddenSingles(Grid grid) { // First try rows for (int row = 0; row < grid.CellsInRow; row++) { int[] hiddenSingles = new int[grid.CellsInRow]; for (int value = 0; value < grid.CellsInRow; value++) { hiddenSingles[value] = -1; } // Now get possibilities for all cells for (int column = 0; column < grid.CellsInRow; column++) { IList candidates = grid.Possibilities(row, column); foreach (int candidate in candidates) { if (hiddenSingles[candidate - 1] == -1) { hiddenSingles[candidate - 1] = column; } else { hiddenSingles[candidate - 1] = grid.CellsInRow; } } } for (int value = 0; value < grid.CellsInRow; value++) { if (hiddenSingles[value] >= 0 && hiddenSingles[value] < grid.CellsInRow) { // Got a hidden single grid.cells[row, hiddenSingles[value]] = value; } } } }
/// <summary> /// Apply singles strategy to supplied grid as much as possible /// </summary> /// <param name="grid"></param> public static void Singles(Grid grid) { int row = 0; int column = 0; while (row < grid.CellsInRow) { while (column < grid.CellsInRow) { if (grid.cells[row, column] == 0) { IList candidates = grid.Possibilities(row, column); if (candidates.Count == 1) { grid.cells[row, column] = (int)candidates[0]; // Restart search from top left row = 0; column = 0; } else { column++; } } else { column++; } } row++; } }
public static Grid Generate(int blocksAcross) { // First generate a random completed grid that is valid Grid empty = new Grid(blocksAcross); Grid solution = Solve(empty); Grid puzzle = (Grid)solution.Clone(); return Minimize(puzzle); /* Random random = new Random(DateTime.Now.Millisecond); IList removeCandidates = new ArrayList(); for (int cellNumber = 1; cellNumber <= 81; cellNumber++) { removeCandidates.Add(cellNumber); } while (removeCandidates.Count > 0) { int removeIndex = random.Next(removeCandidates.Count); int row = removeIndex / puzzle.CellsInRow; int column = removeIndex % puzzle.CellsInRow; if (puzzle.cells[row, column] != 0) { int value = puzzle.cells[row, column]; puzzle.cells[row, column] = 0; IList solutions = Solve((Grid)puzzle.Clone(), 2); if (solutions.Count == 2 || solutions.Count == 0) { puzzle.cells[row, column] = value; } else { cellsRemoved; } } } IList solns = Solve((Grid)puzzle.Clone(), 10); return puzzle; */ }