public SudokuGrid ConstructGrid() { SudokuGrid grid = new SudokuGrid { Cells = new Cell[9][] }; for (int i = 0; i < 9; i++) { grid.Cells[i] = new Cell[9]; for (int j = 0; j < 9; j++) { grid.Cells[i][j] = new Cell { BlockLoc = (i / 3) * 3 + (j / 3) + 1,//Block number = row/3*3+column/3 Candidates = new List <char> { '1', '2', '3', '4', '5', '6', '7', '8', '9' }, Num = '0', ReadOnly = true, XLocation = i, YLocation = j }; } } AddNeighbours(grid); return(grid); }
/// <summary> /// /// </summary> /// <returns>the puzzle in form of SudokuGrid</returns> public SudokuGrid Setter() { PuzzleSolverAdvDS solve = new PuzzleSolverAdvDS(); SudokuGrid grid = ConstructGrid(); //Using Backtracking Solver to fill in a blank grid to get a starting solution - possibly the part of the generator that causes performance issues bool testing = false;//testing condition if (!testing) { try { if (!solve.CompileBacktracker(grid, 2)) { MessageBox.Show("Generator did not find a puzzle to generate"); } } catch (Exception ex) { MessageBox.Show("Something has gone terribly wrong...\r\nError: " + ex); return(grid); } } else { #region Manual Testing Puzzle StringToGrid(grid, "600438079900705080800000032200004060000000000040600003180000005070806001560941008"); #endregion } RemoveNumbers(grid, solve); return(grid); }
/// <summary> /// Function that recieves a puzzle and the string version of the puzzle and tests the difficulty of the puzzle by solving it using the Human-Strategy solver /// </summary> /// <param name="puzzleGrid"></param> /// <param name="puzzleString"></param> /// <returns>returns the difficulty rating of the puzzle</returns> public long GetDifficulty(SudokuGrid puzzleGrid, string puzzleString, PuzzleSolverAdvDS solver) { long rating = 0; int counter = 0; for (int x = 0; x < 9; x++) { for (int y = 0; y < 9; y++) { if (puzzleString[counter] == '0') { puzzleGrid.Cells[x][y].Candidates = new List <char> { '1', '2', '3', '4', '5', '6', '7', '8', '9' }; } else { puzzleGrid.Cells[x][y].Candidates = new List <char> { }; } puzzleGrid.Cells[x][y].Num = puzzleString[counter]; counter++; } } solver.Solver(puzzleGrid, 1); rating = solver.g_Rating; puzzleGrid.Difficulty = solver.g_Difficulty; return(rating); }
/// <summary> /// checks for if the puzzle is valid in the sense that is has more than 7 unique numbers at any point in the puzzle, more than 16 givens, and one solution /// </summary> /// <param name="grid"></param> /// <returns></returns> public bool CheckValidity(SudokuGrid grid) { bool minOfEight = false; int givens = 0; List <char> numList = new List <char> { '1', '2', '3', '4', '5', '6', '7', '8', '9' }; for (int x = 0; x < 9; x++) { for (int y = 0; y < 9; y++) { if (grid.Cells[x][y].Num != '0') { numList.Remove(grid.Cells[x][y].Num); if (numList.Count <= 1) { minOfEight = true; } givens++; } } } if (!minOfEight || givens < 17) { return(false); } char[][] sudokuArray = new char[9][] { new char[9], new char[9], new char[9], new char[9], new char[9], new char[9], new char[9], new char[9], new char[9] }; for (int r = 0; r < 9; r++) { for (int c = 0; c < 9; c++) { sudokuArray[r][c] = grid.Cells[r][c].Num; } } PuzzleSolverAdvDS solve = new PuzzleSolverAdvDS(); if (solve.CompileBacktracker(grid, 4)) { string firstSol = GridToString(grid); grid = RestartPuzzle(grid, sudokuArray); if (solve.CompileBacktracker(grid, 1)) { string secSol = GridToString(grid); if (firstSol == secSol)//valid puzzle { grid = RestartPuzzle(grid, sudokuArray); return(true); } else { grid = RestartPuzzle(grid, sudokuArray); return(false); } } } return(true); }
/// <summary> /// Reassigns the values in the puzzle to what they were prior to being solved /// </summary> /// <param name="grid"></param> /// <param name="sudokuArray">contains the original puzzle prior to solve</param> /// <returns></returns> public SudokuGrid RestartPuzzle(SudokuGrid grid, char[][] sudokuArray) { for (int x = 0; x < 9; x++)//O(n^2) { for (int y = 0; y < 9; y++) { grid.Cells[x][y].Num = sudokuArray[x][y]; } } return(grid); }
/// <summary> /// Takes a SudokuGrid object and converts into a char[][] type /// </summary> /// <param name="grid"></param> /// <param name="puzzle"></param> /// <returns></returns> private char[][] SudokuGridToArray(SudokuGrid grid, char[][] puzzle) { for (int x = 0; x < 9; x++) { for (int y = 0; y < 9; y++) { puzzle[x][y] = grid.Cells[x][y].Num; } } return(puzzle); }
/// <summary> /// This converts a SudokuGrid into a string of numbers from 0-9, where 0 is an empty cell /// </summary> /// <param name="grid"></param> /// <returns></returns> public string GridToString(SudokuGrid grid) { string sudokuExport = ""; for (int i = 0; i < 9; i++) { for (int j = 0; j < 9; j++) { sudokuExport += grid.Cells[i][j].Num; } } return(sudokuExport); }
public bool ValidateInput(UniformGrid SudokuPuzzle, SudokuGrid g_grid, TextBox g_selectedCell) { if (g_selectedCell.Text == "") { return(true); } double index_ = SudokuPuzzle.Children.IndexOf(g_selectedCell); int row = (int)index_ / 9; int col = (int)index_ % 9; g_grid.Cells[row][col].Num = g_selectedCell.Text[0]; if (g_grid.Cells[row][col].Num == '0') { return(true); } bool valid = true; for (int n = 0; n < 8; n++) { if (g_grid.Cells[row][col].Num == g_grid.Cells[row][col].NeighbourCells[0][n].Num) { int index = g_grid.Cells[row][col].NeighbourCells[0][n].XLocation * 9 + g_grid.Cells[row][col].NeighbourCells[0][n].YLocation; if (((TextBox)SudokuPuzzle.Children[index]).Background != Brushes.Red) { g_grid.Cells[row][col].Num = '0'; valid = false; break; } } if (g_grid.Cells[row][col].Num == g_grid.Cells[row][col].NeighbourCells[1][n].Num) { int index = g_grid.Cells[row][col].NeighbourCells[1][n].XLocation * 9 + g_grid.Cells[row][col].NeighbourCells[1][n].YLocation; if (((TextBox)SudokuPuzzle.Children[index]).Background != Brushes.Red) { g_grid.Cells[row][col].Num = '0'; valid = false; break; } } if (g_grid.Cells[row][col].Num == g_grid.Cells[row][col].NeighbourCells[2][n].Num) { int index = g_grid.Cells[row][col].NeighbourCells[2][n].XLocation * 9 + g_grid.Cells[row][col].NeighbourCells[2][n].YLocation; if (((TextBox)SudokuPuzzle.Children[index]).Background != Brushes.Red) { g_grid.Cells[row][col].Num = '0'; valid = false; break; } } } return(valid); }
/// <summary> /// For each cell, add all neighbouring cells to the list of cells property /// </summary> /// <param name="grid"></param> public void AddNeighbours(SudokuGrid grid) { for (int i = 0; i < 9; i++) { for (int j = 0; j < 9; j++) { int nbCounter = 0;//nbCounter is neighbourcounter grid.Cells[i][j].NeighbourCells = new Cell[3][] { new Cell[8], new Cell[8], new Cell[8] }; for (int k = 0, p = 0; k < 9; k++) { if (j != k) { grid.Cells[i][j].NeighbourCells[0][p++] = grid.Cells[i][k];//add neighbour in i nbCounter++; } } nbCounter = 0; for (int l = 0, p = 0; l < 9; l++) { if (l != i) { grid.Cells[i][j].NeighbourCells[1][p++] = grid.Cells[l][j];//add neighbour in column nbCounter++; } } nbCounter = 0; int[] blockIndexes = BlockIndexGetter(grid.Cells[i][j].BlockLoc); for (int x = blockIndexes[0], p = 0; x < blockIndexes[0] + 3; x++) { for (int y = blockIndexes[1]; y < blockIndexes[1] + 3; y++) { if (grid.Cells[x][y] != grid.Cells[i][j]) { grid.Cells[i][j].NeighbourCells[2][p++] = grid.Cells[x][y];//add neighbour in block nbCounter++; } } } } } }
/// <summary> /// Used to check if the puzzle is solved /// </summary> /// <param name="grid"></param> /// <returns></returns> public bool CheckIfSolved(SudokuGrid grid) { for (int row = 0; row < 9; row++) { List <char> numberList = new List <char> { '1', '2', '3', '4', '5', '6', '7', '8', '9' }; for (int col = 0; col < 9; col++) { if (grid.Cells[row][col].Num == '0') { if (grid.Cells[row][col].Candidates.Count == 0) { MessageBox.Show("A strategy has malfunctioned and caused a contradiction or the puzzle is invalid");//Catches if a strategy makes a mistake by causing a cell to have no candidates } return(false); } else if (numberList.Contains(grid.Cells[row][col].Num)) { numberList.Remove(grid.Cells[row][col].Num); } for (int index = 0; index < 3; index++) { for (int i = 0; i < 8; i++) { if (grid.Cells[row][col].NeighbourCells[index][i].Num == grid.Cells[row][col].Num) { return(false); } } } } if (numberList.Count > 0) { return(false); } } return(true); }
public void StringToGrid(SudokuGrid puzzleGrid, string puzzleString) { int counter = 0; for (int x = 0; x < 9; x++) { for (int y = 0; y < 9; y++) { if (puzzleString[counter] == '0') { puzzleGrid.Cells[x][y].Candidates = new List <char> { '1', '2', '3', '4', '5', '6', '7', '8', '9' }; } else { puzzleGrid.Cells[x][y].Candidates = new List <char> { }; } puzzleGrid.Cells[x][y].Num = puzzleString[counter]; counter++; } } }
public void RemoveNumbers(SudokuGrid grid, PuzzleSolverAdvDS solve) { ///This section consists of constantly removing parallel numbers, e.g. [0,0] and [8,8] or [2,5] and [5,2], and checking if the puzzle is still valid (i.e. still has only one solution) int removed = 0; List <string> cellsChecked = new List <string>(81); List <int> rowList = new List <int> { 0, 1, 2, 3, 4, 5, 6, 7, 8 }; List <int> colList = new List <int> { 0, 1, 2, 3, 4, 5, 6, 7, 8 }; rowList = Shuffler_intList(rowList); colList = Shuffler_intList(colList); foreach (int row in rowList) { if (removed >= g_MaxRemoves) { break; } foreach (int col in colList) { if (removed >= g_MaxRemoves) { break; } if (!cellsChecked.Contains(row.ToString() + col.ToString())) { int altRow = NumberSwitch(row); int altCol = NumberSwitch(col); if (grid.Cells[altRow][altCol].Num != '0' && grid.Cells[row][col].Num != '0') { bool valid = false; List <char> numList = new List <char> { '1', '2', '3', '4', '5', '6', '7', '8', '9' }; for (int x = 0; x < 9 && !valid; x++)//checks for if the puzzle is valid in the sense that is has more than 7 unique numbers at any point in the puzzle { for (int y = 0; y < 9 && !valid; y++) { if (grid.Cells[x][y].Num != '0') { if ((x == altRow && y == altCol) == false && (x == row && y == col) == false) { numList.Remove(grid.Cells[x][y].Num); } if (numList.Count <= 1) { valid = true; } } } } if (valid) { char[][] sudokuArray = new char[9][] { new char[9], new char[9], new char[9], new char[9], new char[9], new char[9], new char[9], new char[9], new char[9] }; for (int r = 0; r < 9; r++) { for (int c = 0; c < 9; c++) { sudokuArray[r][c] = grid.Cells[r][c].Num; } } grid.Cells[row][col].Num = '0'; grid.Cells[altRow][altCol].Num = '0'; if (solve.CompileBacktracker(grid, 4)) { string firstSol = GridToString(grid); grid = RestartPuzzle(grid, sudokuArray); grid.Cells[row][col].Num = '0'; grid.Cells[altRow][altCol].Num = '0'; if (solve.CompileBacktracker(grid, 1))//tries Backtracking algorithm using reversed candidate lists so that if a solution that is different to the previous solution exists, it will be found, invalidating the puzzle { string secSol = GridToString(grid); if (firstSol == secSol)//valid puzzle { grid = RestartPuzzle(grid, sudokuArray); grid.Cells[row][col].Num = '0'; grid.Cells[altRow][altCol].Num = '0'; if (grid.Cells[row][col] == grid.Cells[altRow][altCol]) { removed++; } else { removed += 2; } } else//Multiple solutions { grid = RestartPuzzle(grid, sudokuArray); } } } else//Invalid puzzle, should never occur { grid = RestartPuzzle(grid, sudokuArray); } } if (grid.Cells[row][col] == grid.Cells[altRow][altCol]) { cellsChecked.Add(row.ToString() + col.ToString()); } else { cellsChecked.Add(row.ToString() + col.ToString()); cellsChecked.Add(altRow.ToString() + altCol.ToString()); } } } } } if (removed < g_MaxRemoves) { cellsChecked = new List <string>(); foreach (int row in rowList) { if (removed >= g_MaxRemoves) { break; } foreach (int col in colList) { if (removed >= g_MaxRemoves) { break; } if (!cellsChecked.Contains(row.ToString() + col.ToString())) { if (grid.Cells[row][col].Num != '0') { bool valid = false; List <char> numList = new List <char> { '1', '2', '3', '4', '5', '6', '7', '8', '9' }; for (int x = 0; x < 9 && !valid; x++)//checks for if the puzzle is valid in the sense that is has more than 7 unique numbers at any point in the puzzle { for (int y = 0; y < 9 && !valid; y++) { if (grid.Cells[x][y].Num != '0') { if ((x == row && y == col) == false) { numList.Remove(grid.Cells[x][y].Num); } if (numList.Count <= 1) { valid = true; } } } } if (valid) { char[][] sudokuArray = new char[9][] { new char[9], new char[9], new char[9], new char[9], new char[9], new char[9], new char[9], new char[9], new char[9] }; for (int r = 0; r < 9; r++) { for (int c = 0; c < 9; c++) { sudokuArray[r][c] = grid.Cells[r][c].Num; } } grid.Cells[row][col].Num = '0'; if (solve.CompileBacktracker(grid, 4)) { string firstSol = GridToString(grid); grid = RestartPuzzle(grid, sudokuArray); grid.Cells[row][col].Num = '0'; if (solve.CompileBacktracker(grid, 1)) { string secSol = GridToString(grid); if (firstSol == secSol)//valid puzzle { grid = RestartPuzzle(grid, sudokuArray); grid.Cells[row][col].Num = '0'; removed++; } else { grid = RestartPuzzle(grid, sudokuArray); } } } else { grid = RestartPuzzle(grid, sudokuArray); } } } cellsChecked.Add(row.ToString() + col.ToString()); } } } } }