예제 #1
0
        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);
        }
예제 #2
0
        /// <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);
        }
예제 #3
0
        /// <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);
        }
예제 #4
0
        /// <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);
        }
예제 #5
0
 /// <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);
 }
예제 #6
0
 /// <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);
 }
예제 #7
0
        /// <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);
        }
예제 #8
0
        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);
        }
예제 #9
0
        /// <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++;
                            }
                        }
                    }
                }
            }
        }
예제 #10
0
        /// <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);
        }
예제 #11
0
        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++;
                }
            }
        }
예제 #12
0
        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());
                        }
                    }
                }
            }
        }