Sudoku Kimberley Parnell, Skylar Freeze, Phillip Smith University of North Carolina Wilmington Abstract The goal of this project is to design a variety of algorithms that are capable of solving standard 9x9 Sudoku puzzles of ranging difficulties, in order to learn more about Sudoku solving techniques and to better understand constraint satisfaction problems as a whole. We began by using a naïve brute force algorithm to solve the puzzles. While a brute force approach is capable of solving any puzzle in a given amount of time, it has the chance of requiring a substantial amount runtime to reach the correct solution. An optimized take on the brute force algorithm we developed was also produced, and showed noticeably improvement upon the initial brute force results. In an attempt to find a more logical and efficient algorithm, an iterative depth first search algorithm was also designed and implemented. This method improved the average runtime, but could still potentially take over thirty seconds to solve a difficult problem and averaged roughly five seconds on the hardest difficulty. An improvement to this was the recursive backtracking algorithm, which solved the hardest puzzles attempted in an average of less than a second. Also, a stochastic algorithm was implemented to learn how a stochastic technique could be applied to a Sudoku puzzle. All algorithms presented were written in the Python programming language and all algorithms, with the exception of the brute force algorithm, were tested on the same 75 Sudoku puzzles, 25 from each difficulty level (easy, medium, and hard). The brute force and optimized brute force puzzles were tested solely against the 25 easy level puzzles, as well as their own set of ‘simple’ puzzles, to test their efficiency and range. Also, the results for the depth first search and backtracking methods were further validated using 1000 additional Sudoku puzzles from each difficulty range. Key Words: Algorithm, Backtracking, Brute Force, Stochastic Search, Stochastic Search, Depth First Search, Constraint Satisfaction 1. Introduction Our group, Team Sudoku, has created and implemented five different algorithms that are capable of solving a standard 9x9 Sudoku puzzle. To complete a standard Sudoku puzzle one must fill a 9x9 grid with the digits 1 to 9 so that each column, row, and subrectangle contain all digits 1 to 9 within them. A starting grid is partially filled by a selection of given values that determine the puzzle difficulty and the uniqueness of the solution. Our algorithms will be tested on a 9x9 sized puzzle and we will analyze how well each of these algorithms solves a puzzle, based on the depth, speed, and coverage. Algorithms will be assessed based on the number of iterations the algorithm has to run before a solution is returned, the time it takes an algorithm to run before it returns a solution and lastly, the range of puzzles an algorithm is able to handle. 2. Formal Problem Statement Formally speaking, a standard square Sudoku puzzle, based on the original, unmodified game format, is solved by filling an NxN two-dimensional array with N distinct symbols in such a way each cell of the array contains only one symbol and each row, column, and subrectangle of the array is a permutation of the N symbols. Each subrectangle is a MxM two-dimensional array where M is equal to sqrt(N). The number of sub rectangles within the array is equal to N. The solver algorithms will search for a valid (/unique) solution to the inputted Sudoku puzzles. Testing will determine which algorithm solves the puzzles most efficiently. Efficiency will be determined by time elapsed and number of attempts needed. The range of puzzles that the algorithms are able to complete will also be considered. 3. Context The name Sudoku comes from the Japanese, who brought the modern Sudoku puzzle into the mainstream, and consists of the Japanese characters Su, meaning ‘number’, and Doku, meaning ‘single’. Sudoku was originated, however, in Switzerland, by a mathematician named Leonhard Euler. Euler created the modern puzzle using the consolidation of the mathematics pioneered by Isaac Newton. A major contributor in the study of solving Sudoku puzzles through the use of computer programming is Peter Norvig. Norvig wrote an essay on tackling the problem of solving every Sudoku puzzle using two ideas: constraint propagation and search. Constraint propagation is the process of finding a solution to a set of constraints that impose conditions that the variables must satisfy, and idea of searching involves finding an item with specified properties among a collection of items which are coded into a computer program, that look for clues to return what is wanted. The results from his essay showed that the average time to solve a random puzzle was 0.01 seconds, and more than 99.95% took less than 0.1 seconds. His results were produced from the solving of a million randomly generated puzzles. 4. Difficultly in Sudoku In Sudoku, a standard 9x9 grid, as we have focused on for the purposes of this project, must have at least 17 given values to be deemed ‘solvable.’ A ‘solvable’ Sudoku puzzle is one that has a unique solution. A puzzle with 16 or fewer given values will have more than one possible solution, preventing it from being a ‘true’ Sudoku puzzle. This statistic was determined by a study completed and published in 2012 by a student at University College Dublin, which was later supported at a mathematical conference in Boston Massachusetts. The average puzzle one can find in a newspaper has approximately 25 give values, with the number tending to decrease as the puzzle difficulty grows. In Sudoku, there are five levels of difficulty, ranging from Easy (level 1) to Master (level 5). The level of difficulty of a given puzzle is determined by the manner in which a player is required to go about solving the puzzle. The difficulty levels are broken down in a way such that: • Level 1 - The puzzle is solvable by reducing possibilities of square to a single value. • Level 2 – Player must locate the occurrence of number pairs within the puzzle. • Level 3 – The player must utilize special techniques such as ‘X-Wing’1 or ‘Ywing’2 techniques, requiring the player to take a more tactical approach. • Level 4 – Requires the use of ‘Forcing Chains’ where the Sudoku player must make a guess of a possible solution, then trace that guess to determine if it can fit and produce a valid solution (aka ‘Guess and Check’) • Level 5 – Requires the Sudoku player to use trial and error to map out a possible solution, or to make use of lookup tables. These puzzles cannot be solved by logic alone. Difficulty can also be affected by how the given values are placed within the grid. 5. Backtracking The backtracking algorithm solves each unassigned/empty space (represented by a ‘0’ in this algorithm) one at a time, the order determined by its current row and column. It then searches through a list of numbers ranging from 1 to 9, to check if the constraints were satisfied. The three constraints that need to be satisfied to find the unique solution of the puzzle are that no two of the same numbers are presented in the current row, column or 3x3 subrectangle. The algorithm continues to the next blank space to do this same process so long as the constraints are satisfied and until the Sudoku puzzle is solved. If it is determined that the space that was previously solved will not solve the Sudoku puzzle, the algorithm backs up 1The X-Wing Technique is described as a technique in which a player “take(s) two rows (the base sets). If (they) can find two columns, such that all candidates of a specific digit in both rows are contained in the columns, all…candidates (for the digit) in the columns that are not part of the rows can be eliminated. The result is called an X-Wing in the rows. If (one) exchange(s) the terms rows and columns in the description above, (the result is) an XWing in the columns” (Hobiger). 2 The Y-Wing Technique follows the same methodology as the XWing Technique, the difference being in that the player utilizes three instances of the digit to narrow down potential positions for the candidate digit, rather than the two used in the X-Wing technique. from its current state and finds other valid solutions which will satisfy all constraints. Figure 5.1 Figure 5.1 shows the data after running 25 puzzles, ranging with the level of difficulties of easy, medium and hard. Puzzles that were easy resulted in the least of amount of average time. The average time for easy, medium and hard puzzles were recorded as 0.1903, 0.2171 and 0.2052 seconds, respectively. There was no distinct correlation between puzzles with the difficulty of medium and hard, and the backtracking algorithm was able to successfully solve all three difficulties. To further analyze the correlation between ranging difficulties of Sudoku puzzles based on computational time, data from a sample size of 1000 Sudoku puzzles, ranging from the same level of difficulties was recorded. With a larger sample size than previously recorded, the data shows a correlation between the level of difficulty and time, as it takes the backtracking algorithm the most time to solve the hardest level of difficulty. The number of recorded iterations the backtracking algorithm implemented had a correlation with the ranging level of difficulties, as well. The algorithm tended to require more instances of backtracking the harder the difficulty of the puzzle, because there would be a larger set of numbers that would satisfy the constraints, therefore requiring more recursions. For its complexity, the backtracking algorithm has a Big-O notation of O(n!)n, where n factorial represents the number of possible values within a Sudoku puzzle. The algorithm will go through each number from 1-9 to see if it satisfies the constraints, this is represented by the n factorial in the Big O. Once it finds the value or values that could be a possible solution it pushes the value or values into an ordered stack and pops the first value that into the unassigned space. The algorithm will go to the next unassigned space and do this same process again. If the algorithm is at an unassigned space where there are no possible numbers that can satisfy the constraints, it will then keep the unassigned space as a ‘0’ and backtrack to the last assigned space. Once it goes back to the last assigned space, the algorithm will assign the current space to the next popped number from the stack. The number of times the algorithm would backtrack, to show that it requires another number from the stack of possible values, is represented as the nth power. 6. Brute Force The brute force algorithm created for this project was completely randomized and given minimal logic. It featured no optimization in order to distinctly differentiate itself from the backtracking algorithm developed for this same problem. Our algorithm represented an extremely naïve solving system in contrast to the different logic-based algorithms that we designed. The algorithm begins by reading through each value in the array, one row at a time. When it lands upon a ‘0’ (the symbol in our programming for an empty cell), the algorithm sends two lists to an outside method: a list of all the integers in that value’s row and a list of all of the integers in that value’s column. The outside method, genRandom, then continuously generates a value between 1 and N until it finds one that does not already exist in the given row or column. If the generator runs through all N integers it will return its state as broken, recognizing that the current randomized solution is incorrect and does not fit within the constraints of a valid Sudoku solution. After a random value has been generated, it will be returned to the main algorithm and replace the ‘0’ value at its index. The algorithm will then continue through the rest of the array until it reaches the end, having found a valid solution. The algorithm will also run an outside method after finishing each set of sub rectangles to ensure no repeated values within the sub rectangles, verifying that the generated solution is remaining within the constraints of a valid and correct solution. While effective on the smallest tested puzzle size (4x4), the brute force algorithm becomes exponentially less efficient as the puzzle size increases. As the algorithm is randomized and does not utilize any optimization, it relies solely on luck. The range of attempts needed to solve the solution using the brute force algorithm was highly variant and had no distinguishable correlation. In relation to that, there was also a high variance in runtime needed to solve the puzzles. Because of this, the brute force algorithm developed is a very inefficient and ineffective method of solving the Sudoku problem. Figure 6.1 the basic algorithm we developed for a brute force approach was unable to solve any puzzles in the easy set of 25 puzzles in under 2 million attempts, the algorithm in its optimized form had approximately 60% coverage of the same puzzles, the majority of which were solvable in half a million attempts or less. The optimized algorithm was also run against the previously presented puzzle for one hundred attempts. Adding the additional constraint in regards to the subrectangles greatly reduced the needed attempts and the variance of results. Figure 6.2 Optimized Brute Force Variation 300 250 200 150 100 50 1 8 15 22 29 36 43 50 57 64 71 78 85 92 99 0 The variance for the times and attempts needed for our brute force algorithm to solve a given puzzle was tested by running the same puzzle through the algorithm one-hundred times. The results (as seen in Figure 6.1 above) were highly inconsistent and relied solely on the luck of the draw from the random number generator. In addition to a very basic brute force algorithm, we also created an optimized brute force algorithm. The optimized form of the algorithm utilizes the same general process as the original, however it takes the subrectangles into account when generating a randomized number. This optimized algorithm has increased effectiveness, though it is still limited in contrast to the backtracking and DFS algorithms we developed. The optimized brute force algorithm we developed improved the randomized algorithm’s ability to solve the puzzles. While While the original brute force algorithm we developed took an average of approximately eleven-thousand attempts to solve (minimum of 154, maximum of 51,735), the optimized algorithm took an average of approximately 60 attempts (minimum of 3, maximum of 247). The average runtime was also decreased, with an initial average of 2.65 seconds, and an average of .06 seconds in the optimized form. In decreasing the chances of error coming from the random generator, the effectiveness and efficiency of the solver was increased. In regards to complexity, both algorithms share a Big-O notation of O(n), n being the number of unknown values in the puzzle. For each unknown value, there are a maximum of nine possible solutions, depending on givens. For each additional unknown value n, the runtime of the program increases. The algorithm does not attempt to make corrections to detected errors, and instead breaks out of the grid and ends the algorithm upon finding an incorrect guess. This means that the longest runtime of the algorithm will be a correctly guessed solution which makes it to the end of the grid rather than breaking out of the algorithm early. Since the algorithm is completely randomized, it keeps no record of guessed solutions, making it potentially infinite, as it can continue to make the same errors repeatedly without correcting itself. Because of this, the algorithm is NP, nondeterministic. 7. Stochastic Search The other randomized algorithm developed for solving the Sudoku problem was a stochastic search algorithm. The stochastic search algorithm runs through the given puzzle array and locates all empty ‘0’ cells. For each empty cell, it generates a random number that does not already correctly exist in the row and column for that given cell. After creating a randomized solution for the puzzle, the generated solution is then checked against the correct solution. All correct guesses are saved to the puzzle being solved, while all incorrect guesses are reset back to zero. This algorithm was run against a series of easy, medium, and hard level puzzles. While there was a minor positive correlation between the difficulty of the puzzle and the time and attempts needed, the increase was minimal. There was also enough variance in the results that a lower difficulty puzzle might not consistently run more efficiently than a higher level puzzle. Stochastic Search Results Difficulty Average Attempts Min/Max Attempts Standard Deviation (Attempts) Average Time Easy 7.12 Medium 8.0 Hard 8.33 5/12 5/11 5/11 0.0076 0.00677 0.00894 0.04196s 0.04775s 0.05917s The complexity for the Stochastic Search algorithm that we developed is also O(n). It also depends on random generation of numbers, and while it is unlikely, there is a worst case scenario in which the generator will continue to guess an incorrect solution infinitely. Because of this, the algorithm is also NP, nondeterministic, though less obviously so than the Brute Force algorithm. This algorithm is much more efficient than the brute force form of randomized search we developed, however, due the requirement of having a solution to compare the generated solution to, this algorithm is not very practical. A user would need to supply the puzzle’s solution, making this algorithm obsolete in real world and practical application. 8. Iterative DFS (Depth First Search) The iterative DFS algorithm begins by creating a fixed list that holds the placement of the initially provided Sudoku entries and an empty list to hold what values were attempted for each empty square. It then starts iterating over the Sudoku squares, stepping over squares that are in the fixed list. When it finds a blank square it calls an outside method to determine the first possible entry that does not violate any constraints provided. That entry is returned, placed in the blank square, and that value is added to the tried list for that square. This is controlled by a while loop whose exit condition is the puzzle being solved. If the algorithm reaches a blank square ‘X’ which has no possible moves it will reset the previous entry ‘Y’ to blank, empty the tired entries for X and every entry past it, and start again from Y. This algorithm uses a depth first search technique to choose which values will be entered into the blank squares first. A tree is created whose branches are the possible entries for each blank square sorted in ascending order and the lowest possible entry is always chosen first. This algorithm was able to solve the easiest Sudoku puzzles in an average of 0.049123 seconds with an average of 2146.76 steps. However, when presented with medium or hard puzzles this algorithm performed much slower than the recursive backtracking algorithm requiring an average of 3.924969 seconds for the medium difficulty and 3.874782 for the hardest difficulty. This indicates that the algorithm’s runtime is not affected by the difficulty of the puzzle and rather the number of blank entries and location of the given entries. With a correlation between runtime and the number of fixed entries at the beginning of the puzzle. The time complexity of this algorithm has a worst case of O(∑𝑚 0 𝑚^𝑛) where n is the number of blank entries in a given Sudoku puzzle and m is the number of possible entries for a blank square. Each entry can have a maximum of nine possible values. However, repetition is not allowed so the sum will go from zero to m. Figure 8.1 Runtime of Iterative DFS 50 Time 40 30 20 10 0 1 3 5 7 9 11 13 15 17 19 21 23 25 Puzzle Number Easy Times Difficult y Average Attempts Min/Ma x Attempts Average Time Med Times Hard Times Iterative DFS Results Easy Medium Hard 2146.76 186451.2 182351.4 116/837 6 725/206988 3 164/86956 6 0.04912 s 3.924962s 3.874782s 8. Interpretation and conclusions All of our algorithms succeeded in meeting the goal of our problem statement, which was to solve a standard 9x9 Sudoku puzzle. The brute force algorithm was the most naïve and was written directly from the problem statement. It is capable of solving any puzzle, but it is a NP solution and the least efficient algorithm we designed and implemented. It doesn’t keep up with any information about previous attempts it has made as it solves a puzzle. In contrast, the iterative DFS algorithm does a lot of book-keeping, tracking both possible moves for an entry and tried moves for that entry in the form of Python lists. The Iterative DFS algorithm also offers a structured approach to solving the puzzle, attempting entries in a DFS branching style. This improvement allowed for solving medium and hard level Sudoku puzzles, which the brute force algorithm was incapable of doing in a reasonable amount of time. The recursive backtracking algorithm was the overall most effective, solving hard level puzzles in an average of 0.2052 seconds, compared to the Iterative DFS algorithm which solved hard level puzzles in an average of 3.874782 seconds. This is because the recursive backtracking algorithm did no book keeping, other than the current layout of the board and was unencumbered by the lists the iterative DFS algorithm kept up with. It managed to iterate over the possible entries and did not require a list to store entries that were previously tried. The Stochastic algorithm was very effective at solving any level Sudoku puzzle. However, it had the advantage of using the solution to solve the problem. All of our algorithms we affected more by the number of given entries and the placement on the board of those givens rather than the difficulty of the puzzle. The more blank squares there were the more our algorithms iterate to fill them in. Also, the more blank entries towards the beginning of the puzzle resulted in longer runtimes which required more backtracking. This leads us to believe, in conclusion, that (at least in regards to a computer program,) the difficulty of a Sudoku puzzle to be computationally solved is directly correlated to the placement and number of provided entries, rather than the human techniques required solve said puzzle. This causes some easy puzzles to require less time to solve than some medium puzzles and some medium puzzles taking less time than certain hard puzzles. 9. Future Work Our project handled the most standard and universally known puzzle size, which is the 9x9 Sudoku puzzle. In future efforts towards this problem, we would aim to have our algorithms be applicable to a greater variety of puzzle sizes, such as 16x16 or 25x25 puzzles. We could use this information to study the impact that puzzle size has on the efficiency of the solver algorithms. We could also potentially look at solving modified, non-standard puzzles which do not require the square approach of an equal number of columns and rows. In regards to our testing, another addition we could also look into would be to add more factors to analyze the efficiency of our algorithms, such as measuring CPU usage. With this data we could then determine the correlation between CPU memory usage, algorithm runtime, and the puzzle’s given level of difficulty. For additional algorithms, we could work to apply more techniques, such as analyzing a more ‘human’ approach. One such example of this would be the grid (i.e. if in a 9x9 grid the number ‘3’ exists at grid positions (0,1) and (2, 7), through examination, the algorithm could determine that the last instance of ‘3’ within that column of subrectangles must be at index ‘1’ for the middle subrectangle, limiting the field of possibilities for the final ‘3’ to (1, 35)). There are a number of mathematical approaches and logic-based techniques that could be studied as possible algorithmic approaches in the future. 11. Questions For an MxM subrectangle of a Sudoku puzzle that is NxN, what is the value of M in relation to N? o M = sqrt(N) Why does our Brute Force method of solving Sudoku result in such greatly varied runtimes and needed attempts? o It uses minimal logic and depends entirely on the luck of the random generator’s guesses. What is the meaning of Stochastic? o Stochastic means “randomly determined”. What solving technique do most humans used when faced with a “difficult” Sudoku puzzle? o Brute Force. What is the Big-O notation of a DepthFirst Search? o O(V + E): V stands for the vertex’s and E represents the edges between them. 11. Sources [1] https://en.wikipedia.org/wiki/Sudoku [2] http://norvig.com/sudoku.html [3] http://www.nature.com/news/mathemati cian-claims-breakthrough-in-sudokupuzzle-1.9751 [4] http://www.playr.co.uk/sudoku/ratings.p hp [5] http://www.sudokuwiki.org/x_wing_stra tegy [6] http://www.sudoku.org.uk/SolvingTech niques/Y-Wing.asp [7] http://blog.dictionary.com/sudoku/