63
Sudoku Solvers Man versus Machine Simon Johansson Andreas Broström G.a. Huddingevägen 438 Norrtullsgatan 33 125 42 Älvsjö 113 27 Stockholm 0704-74 54 84 0707-90 07 14 [email protected] [email protected] Degree Project in Computer Science, First Level, DD143X School of Computer Science and Communication KTH Royal Institute of Technology Supervisor: Roberto Bresin Examiner: Mårten Björkman

Man versus Machine - KTH Solvers Man versus Machine ... An algorithm is backtracking if it can go back ... The purpose of our project is to create and implement a solver that can solve

  • Upload
    vudung

  • View
    217

  • Download
    0

Embed Size (px)

Citation preview

Page 1: Man versus Machine - KTH Solvers Man versus Machine ... An algorithm is backtracking if it can go back ... The purpose of our project is to create and implement a solver that can solve

Sudoku Solvers Man versus Machine

Simon Johansson Andreas Broström G.a. Huddingevägen 438 Norrtullsgatan 33 125 42 Älvsjö 113 27 Stockholm 0704-74 54 84 0707-90 07 14 [email protected] [email protected] Degree Project in Computer Science, First Level, DD143X School of Computer Science and Communication KTH Royal Institute of Technology Supervisor: Roberto Bresin Examiner: Mårten Björkman

Page 2: Man versus Machine - KTH Solvers Man versus Machine ... An algorithm is backtracking if it can go back ... The purpose of our project is to create and implement a solver that can solve

 

 

Page 3: Man versus Machine - KTH Solvers Man versus Machine ... An algorithm is backtracking if it can go back ... The purpose of our project is to create and implement a solver that can solve

3

Abstract The purpose of this bachelor thesis is to create and implement a Sudoku solver based on human strategies. We want to see how our solver compares to a brute-force solver and in which aspects it is the most efficient. We tested the two solvers in terms of solving speed, number of misses or wrong moves required to find a solution, and ability to solve harder Sudokus. Our conclusions are that the human solver is comparable to well known computer based Sudoku solvers and it is generally more efficient in terms of solving speed and number of misses. The human solver, however, does not guarantee solutions to advanced Sudokus, even though it solved all puzzles that matched the complexity of Sudokus found in newspapers.

Sudokulösare

Människa mot Maskin

Sammanfattning Syftet med den här kandidatuppsatsen är att skapa och implementera en sudokulösare baserat på mänskliga strategier. Vi vill se hur vår lösare står sig mot en brute-force lösare och i vilka avseenden den kan anses vara mest effektiv. Vi har jämfört de två lösarnas lösningshastighet, antal missar eller felaktiga beräkningssteg och förmågan att lösa svårare sudokus. Våra slutsatser är att den mänskliga lösaren är jämförbar med välkända datorbaserade lösare och den är generellt sett effektivare när det gäller lösningshastighet och antal missar. Den mänskliga lösaren kan dock inte garantera en lösning till mer avancerade sudokus, även fast den löste alla de pussel som hade en motsvarande svårighetsgrad som de man kan hitta i tidningen.

 

Page 4: Man versus Machine - KTH Solvers Man versus Machine ... An algorithm is backtracking if it can go back ... The purpose of our project is to create and implement a solver that can solve

4

Statement of collaboration The responsibilities are divided into three subsections: Implementation of the solvers, testing environment and execution, and writing. Implementation of the solvers Simon has been responsible for the human solver and Andreas the brute-force solver. Both of us have worked on the basic classes of which both solvers inherit from. Testing environment and execution Andreas has been responsible for setting up the testing environment and writing the code needed to perform the tests. Writing Both of us have in general been doing the writing together but some of the more individual responsibilities are: Simon: Background of techniques, general approach, approach of implementations excluding brute-force and results. Andreas: General background, background of algorithms, approach of brute-force and testing.

 

Page 5: Man versus Machine - KTH Solvers Man versus Machine ... An algorithm is backtracking if it can go back ... The purpose of our project is to create and implement a solver that can solve

5

Table of contents

STATEMENT  OF  COLLABORATION  .................................................................................................................  4  TERMINOLOGY  ......................................................................................................................................................  7  INTRODUCTION  ....................................................................................................................................................  8  PREFACE  ......................................................................................................................................................................................  8  

Sudoku  ......................................................................................................................................................................................................................  8  Sudoku  Solvers  ......................................................................................................................................................................................................  8  Solving  techniques  and  algorithms  ..............................................................................................................................................................  9  

PROBLEM  STATEMENT  .............................................................................................................................................................  9  PURPOSE  .....................................................................................................................................................................................  9  OUTLINE  ...................................................................................................................................................................................  10  

BACKGROUND  ....................................................................................................................................................  11  SUDOKU  ....................................................................................................................................................................................  11  SOLVING  SUDOKUS  .................................................................................................................................................................  11  Algorithms  .............................................................................................................................................................................  11  

Brute-­‐force  algorithm  .....................................................................................................................................................................................  12  Human  algorithm  ..............................................................................................................................................................................................  12  

Techniques  ............................................................................................................................................................................  12  Naked  Single  ........................................................................................................................................................................................................  13  Hidden  Single  ......................................................................................................................................................................................................  13  Naked  Pair/Triple  .............................................................................................................................................................................................  13  Hidden  Pair/Triple  ...........................................................................................................................................................................................  13  Naked  Quad  ..........................................................................................................................................................................................................  13  Box  Line  Reduction  ...........................................................................................................................................................................................  13  Pointing  Pairs/Triples  .....................................................................................................................................................................................  13  

APPROACH  ...........................................................................................................................................................  14  IMPLEMENTATION  ..................................................................................................................................................................  14  Human  rule  based  solver  ................................................................................................................................................  15  Brute-­‐force  solver  ..............................................................................................................................................................  15  

TESTING  ...................................................................................................................................................................................  17  Environment  .........................................................................................................................................................................  17  Execution  ...............................................................................................................................................................................  18  

RESULTS  ...............................................................................................................................................................  19  Comparison  of  average  solving  speed  .......................................................................................................................  19  Comparison  in  number  of  misses  .................................................................................................................................  21  Harder  Sudokus  ..................................................................................................................................................................  26  

CONCLUSIONS  .....................................................................................................................................................  27  RECOMMENDATIONS  AND  POSSIBLE  EXTENSIONS  ...............................................................................  30  REFERENCES  .......................................................................................................................................................  31  APPENDIX  A  -­‐  RESULTS  ...................................................................................................................................  32  HUMAN  -­‐  SOLVING  TIME  &  NUMBER  OF  MISSES  ................................................................................................................  32  HUMAN  -­‐  HARDER  PUZZLES  ..................................................................................................................................................  34  BRUTE-­‐FORCE  -­‐  SOLVING  TIME  &  NUMBER  OF  MISSES  ....................................................................................................  34  BRUTE-­‐FORCE  -­‐  HARDER  PUZZLES  ......................................................................................................................................  37  

APPENDIX  B  -­‐  CODE  ..........................................................................................................................................  38  SHARED  ....................................................................................................................................................................................  38  

Page 6: Man versus Machine - KTH Solvers Man versus Machine ... An algorithm is backtracking if it can go back ... The purpose of our project is to create and implement a solver that can solve

6

Cell.java  ..................................................................................................................................................................................  38  Solver.java  .............................................................................................................................................................................  39  SudokuSolver.java  ..............................................................................................................................................................  42  

SOLVERS  ...................................................................................................................................................................................  44  HumanSolver.java  ..............................................................................................................................................................  44  BruteforceSolver.java  .......................................................................................................................................................  55  

TESTING  ...................................................................................................................................................................................  57  run.sh  .......................................................................................................................................................................................  57  run_both_tests.sh  ................................................................................................................................................................  57  SudokuToExcel.java  ..........................................................................................................................................................  57  

APPENDIX  C  -­‐  SUDOKU  EXAMPLES  ..............................................................................................................  62  NE.SE  ........................................................................................................................................................................................  62  HARDER  PUZZLES  ...................................................................................................................................................................  63  

Page 7: Man versus Machine - KTH Solvers Man versus Machine ... An algorithm is backtracking if it can go back ... The purpose of our project is to create and implement a solver that can solve

7

Terminology Algorithm:

An algorithm in this thesis refers to an ordinary computer science algorithm that can be used to solve a Sudoku.

Backtrack: An algorithm is backtracking if it can go back to a previous state, often with a recursive call.

Box: A sub grid that consists of 3×3 cells. There are 9 boxes in a normal Sudoku. Brute-force:

Also known as exhaustive search. Finds a solution by going through all possible solutions.

Candidate: Possible numbers that can be placed in a cell without breaking the Sudoku constraints.

Cell: A cell is the smallest building block of a Sudoku. A Sudoku normally consists of 9×9 cells. Each cell contains a value between 1 and 9.

Clue: A given number. In the beginning of a Sudoku game some of the numbers are already entered in the cells, these are called clues.

Grid: The Sudoku board. Normally consists of 9 rows × 9 columns of cells and 9 boxes. Pair: A relation between two cells, often related to their candidates. Used in techniques. Quad: A relation between four cells, often related to their candidates. Used in techniques. Region: Either refers to a row, column or box in the Sudoku. Rule: Refers to technique. Set:

Refers to either a pair or a triple. Technique:

A technique in this thesis refers to a technique used by a human to solve a Sudoku. A technique typically begins with matching a pattern, which leads to either being able to enter a new number in a cell or removing candidates from some cell(s).

Triple: A relation between three cells, often related to their candidates. Used in techniques. Unit: Refers to region.

Page 8: Man versus Machine - KTH Solvers Man versus Machine ... An algorithm is backtracking if it can go back ... The purpose of our project is to create and implement a solver that can solve

8

Introduction

Preface This document is written for the course Degree Project in Computer Science, First Level, DD143X/dkand13 at the Royal Institute of Technology. We are both 3rd year students at the Computer Science programme at the Royal Institute of Technology, our supervisor for our work is Roberto Bresin and examiner is Mårten Björkman. In this thesis we investigate how solvers based on human techniques compare to known computer algorithms when solving Sudokus.

Sudoku Sudoku is a popular logic-based puzzle where the objective is to fill a 9×9 grid with numbers, with a subset of the solution already given, so that each column, each row, and each of the nine 3×3 sub-grids contains all of the numbers from 1 to 9.

Figure 1, a basic instance of a 9x9 Sudoku.

Figure 2, a solution of the instance given in fig. 1.

A Sudoku can vary in difficulty depending of various aspect including number of given numbers. Figure 1 gives an example of a basic Sudoku instance with 30 given numbers and the solution is presented in Figure 2 with filled in numbers displayed in red.

Sudoku Solvers We chose to make a human-like Sudoku solver because we wanted to see how the techniques a human use to solve a Sudoku compares to computer solvers. We find this interesting because we want to see if the solvers used on computer really are better than the methods used by a human or if the computer solves the puzzles faster simply because it can perform faster calculations then a human.

Page 9: Man versus Machine - KTH Solvers Man versus Machine ... An algorithm is backtracking if it can go back ... The purpose of our project is to create and implement a solver that can solve

9

Solving techniques and algorithms The different algorithms that are used to solve Sudokus vary in complexity depending on approach. The brute-force algorithm fills in the missing numbers without any sense of logic and check afterwards if it was a valid placement or not. These algorithms use exhaustive search to solve Sudokus, which means a large amount of backtracking and guessing; Hence not suitable to be used by a human. An advantage with this method is that it will always find a solution. However this also means that it will try all different solutions and since there are 6.67 * 10^21 possible Sudokus it could take a very long time in the worst-case scenario. [1][2] A human rule based algorithm uses a series of techniques that are based upon the given restrictions of Sudoku. The techniques are then applied by the solver in order (from easiest to hardest) to find a possible number placement. One rule might be to check for any naked singles in a row, meaning searching for locations where one and only one number can be placed according to the Sudoku restrictions. A problem with this algorithm is that it does not guarantee that a solution will be found because the rules are not exhaustive, i.e. there are Sudokus that cannot be solved using only rules [3].

Problem statement A Sudoku can be solved using a brute-force algorithm [4] but it is more interesting to understand how a human would solve the same puzzle, and to implement his/her strategies. Therefore we want to find out how a human rule based solver compares to known computer based solvers and in which aspects a human is more efficient. Because there are a lot of different solving techniques and algorithms available we have initially limited this project to compare the following: A human rule based solver that we will create, a solver based on exhaustive search, and another solver based on exhaustive search that uses backtracking.

Purpose The purpose of our project is to create and implement a solver that can solve a Sudoku without guessing, just like a human. We will measure how good our solver is by implementing other well-known solvers and compare them in terms of speed, number of misses or wrong moves required to find a solution, and ability to solve harder Sudokus. We will therefore:

● Develop a solver that will match the behaviour of a human solving a Sudoku by only using non-guessing rules.

● Test that solver against as many different Sudokus of increasing difficulty as possible. ● Compare that solver against other solvers, where we hope that the human rule based

solver shall be the most efficient in one of the three aspects we compare: solving speed, number of misses or wrong moves required to find a solution, and ability to solve harder Sudokus.

Page 10: Man versus Machine - KTH Solvers Man versus Machine ... An algorithm is backtracking if it can go back ... The purpose of our project is to create and implement a solver that can solve

10

Outline First of all we have included an abstract that summarizes this thesis in terms of what it is about and what our results and conclusions are. A table of content follows to give an overview of the document. Then we have included a statement of collaboration that will show the reader which student performed what work. After that we have a section named terminology with terms regularly used in the thesis. Then there is the introduction section. This is meant to introduce the reader to our problem and what the rest of the thesis will cover; ‘problem statement’ and ‘purpose’ are included here. After the introduction the thesis presents a more in depth background of Sudoku and Sudoku solvers. In the section that covers Sudoku solvers different algorithms and techniques are discussed. After that the approach is presented. The approach covers what kind of solvers we implemented, why we implemented them, how we did that, and how we tested them. The thesis takes up our result and conclusions towards the end of the thesis. The result section contains a lot of graphs and tables extracted from the results in the appendix while the conclusions contains discussion of those results. The last two sections are ‘Recommendations and possible extensions’ and ‘References’. The former chapter includes our recommendations of extensions and also include some recommendations if anyone would like to replicate something covered in this thesis. Some of the results and most of the code are included in appendices A and B respectively. Appendix C contains some examples of the Sudokus that we have used in our testing.

Page 11: Man versus Machine - KTH Solvers Man versus Machine ... An algorithm is backtracking if it can go back ... The purpose of our project is to create and implement a solver that can solve

11

Background

Sudoku Sudoku is a logic based number puzzle represented by a square grid. The most common variant of Sudoku has a grid consisting of 9 * 9 cells that are divided into boxes that consist of 3 * 3 cells each. Numbers ranging from 1 to 9 shall be placed in the cells, filling the grid, so that every number occurs only once in each row, column and box. It exists different difficulty levels in Sudoku, where difficulty is based on how many clues are given from the beginning and partially on the layout of these. A Sudoku usually has a minimum of 17 clues and only one, distinct, solution. As previously mentioned there are 6.67 * 10^21 different Sudokus [1][2] but not all of them are playable by humans, at least not without guessing [3]. A common property of the unsolvable Sudokus is that they have multiple solutions, which means that not enough clues has been given to provide a distinct solution [5]. Sudoku became popular in Japan in the mid 80’s but similar games had existed before that. It became widely popular around 2004 when it started to appear in newspapers where it became an appreciated alternative to the traditional crosswords. Today Sudoku does not only appear in newspapers but also as computer games and in international Sudoku championships. [6]

Solving Sudokus A Sudoku game begins with some of the cells already filled in with clues and the aim is to fill the remaining empty cells. There is only one rule in Sudoku [7]:

“Each row, column and box must end up containing all of the numbers from 1 to 9.” This rule has an important side-effect, which is the basis of all solving techniques:

“Each number can only appear once in a row, column or box.”

Thus a Sudoku game ends when there is a number in every cell and the one rule of Sudoku is satisfied. There are many different ways to solve a Sudoku. Different algorithms and techniques work well in different occasions. In this section we will discuss some of the more common algorithms and techniques that can be used when solving Sudokus with a focus on the techniques that we are studying in this thesis [5].

Algorithms To solve a Sudoku with the help of a computer you would normally use some kind of algorithm or a combination of algorithms. In this section we will present some of the better-known algorithms with a focus on those we are going to investigate in this thesis.

Page 12: Man versus Machine - KTH Solvers Man versus Machine ... An algorithm is backtracking if it can go back ... The purpose of our project is to create and implement a solver that can solve

12

Brute-force algorithm One of the better-known algorithms that are used when solving Sudokus on a computer is called brute-force. The brute-force algorithm is sometimes called an exhaustive search algorithm and it has become famous in computer science because of its striking characteristics: It always finds a solution because it will try all possible solutions hence it is not considered to be very effective [8]. A Sudoku solver that uses brute-force will visit all the empty cells and try to fill it with a number from the available choices. If no violations are found after an insertion it will continue to the next empty cell and start over. As soon as a violation to the Sudoku rules are found the algorithm will backtrack and increment the previous cell. [9]

Human algorithm

The algorithm that is used by most humans competing in Sudoku challenges is sometimes referred to as the pencil-and-paper algorithm [10] but we have chosen to call it the human algorithm. The human algorithm uses a number of techniques to solve a Sudoku without guessing [3]. A common trait of this algorithm is the use of candidates. Candidates are defined as all the possible numbers that could be placed in a cell given the Sudoku constraints. Candidates are often represented by humans as smaller numbers written in or beside the cell that they belong to (see figure 3).

Figure 3, a figure that shows a Sudoku box with all candidates filled in. [7]

A Sudoku solver that uses the human algorithm is often built with a loop that loops over techniques, beginning with easier and ending with harder techniques to emulate the general human behaviour [5].

Techniques The human algorithm uses techniques to solve a Sudoku, which can also be described as rules that each consists of a pattern followed by an action [3][10]. If a pattern is matched when performing a technique during a Sudoku session, the technique’s corresponding action will be executed before proceeding to the next technique. If an action is performed it will either place a number in a specific cell or remove one or more candidates from one or more cells. The concepts of the different techniques are often the same across the resources available but have no standardised terminology or general description of these techniques. Therefore, we decided on using the techniques and naming convention as described at sudokuwiki [5]. The following techniques are some of the most basic ones of solving a Sudoku and are the first six rules that the human solver uses at sudokuwiki [5].

Page 13: Man versus Machine - KTH Solvers Man versus Machine ... An algorithm is backtracking if it can go back ... The purpose of our project is to create and implement a solver that can solve

13

Naked Single This technique is very simple and often the best way to begin a Sudoku game. Pattern: A cell only has a single candidate left. Action: Places that single candidate number in that cell.

Hidden Single Pattern: A region only has a single cell in which it can place a remaining number. Action: Places that number in that single cell.

Naked Pair/Triple Pattern: Two/three cells in the same region have a union of two/three candidates in common. Action: The candidates in this union are removed from the same unit.

Hidden Pair/Triple Pattern: Two/three cells in the same region have the last remaining two/three candidates for that region in common. Action: Any candidate(s) that are not a member of the pair/triple in the found cells are removed.

Naked Quad Pattern: Four cells in the same region have a union of four candidates in common. Action: The candidates in this union are removed from the same unit.

Box Line Reduction Pattern: The only occurrences of a candidate of cells in a row or column are in the same box. Action: Remove all other occurrences of this candidate in the rest of this box.

Pointing Pairs/Triples Pattern: The only occurrences of a candidate in a box are aligned in cells on a row or column. Action: Remove all other occurrences of this candidate in the rest of this row or column.

Page 14: Man versus Machine - KTH Solvers Man versus Machine ... An algorithm is backtracking if it can go back ... The purpose of our project is to create and implement a solver that can solve

14

Approach After settling the problem statement, purpose and goals of this thesis we did some extended research about Sudoku solvers, and focused especially on those incorporating human based strategies. We found that most human based solvers use the same fundamental concept of applying rules in a specific order, and they did, more or less, only differ in terminology of these rules [10][5]. With these resources available we decided that we would base our human solver upon these established concepts. In terms of finding a solver utilizing a brute-force algorithm we found a range of different implementations in varying complexity. In the long run we settled on using a simple and fast solver written in java as a reference [11]. At first, this thesis was to cover two exhaustive search solvers in addition to the human rule based solver. The problem was that one of the brute-force algorithms used in one of the solvers did not terminate during initial testing due to unacceptable computing complexity. That is why we decided on only using two solvers and comparing these against each other. The puzzles we decided to use in our testing are the ones available at ne.se. Ne.se provides sixty puzzles in ranging difficulty from easy to hard [12]. We chose this set of puzzles because it is from a reliable source, they are of mixed complexity and typically the kind of Sudoku you would expect to find in a newspaper. In accordance to our goals we ought try to solve all of these puzzles with our human solver. Before we were done with the implementation of our solver we had the hypothesis that our human solver would match the brute-force solver in performance up to a certain point where the puzzles would become too difficult and the rules used in our solver would get too complicated to match the speed of trial and error.

Implementation The two solvers are both written in java and derives from a basic solver class (found in Appendix B, Shared) that handles initialization of the grid, reading Sudoku files, and verification of a solved Sudoku. The individual solvers then have additional methods for solving the Sudoku based on their different algorithm and/or techniques. We shared as many methods as possible between the two solvers to minimize the differences between the solvers to produce more reliable testing results. Both solvers begins with some administrative work like loading and parsing a Sudoku from file and also initialization of the grid, boxes and cells. Each cell is initialized with a number that is either a clue or a zero value if no clue was given in that cell. Each cell also gains a boxID at initialization, which lets the cell know which box it belongs to.

Page 15: Man versus Machine - KTH Solvers Man versus Machine ... An algorithm is backtracking if it can go back ... The purpose of our project is to create and implement a solver that can solve

15

Human rule based solver The human solver uses a set of rules that the solver tries to match in a prioritized order. Each rule has a pattern and if successfully matched applies an action to the Sudoku. Before the main solving method is called, the candidates for each cell are initiated by checking the clues given. This is a precondition on which all of the followed techniques require. The main loop is located in the method called solve. Solve goes through all of the rules in an order of increasing complexity and decreasing probability of finding a match. If a rule pattern is found and the following action made a change to the Sudoku, the matched rule method returns true and the main loop starts over and tries to match the first rule again. A rule method will return false if a matched rule did not change the Sudoku or if the pattern was not matched at all. The main loop will repeatedly go through all of the rules until none of them returns true. When that happens the loop will break and the Sudoku will be verified by calling the method valid from the Solver class. The solve method will finally return true if the Sudoku is correctly solved and otherwise return false. The rule order can be seen in the following pseudo code example of the main loop. The description of these rules can be found in the background section of this thesis and the implementation of these in the code appendix (Appendix B, Solvers). boolean solve() := while(true) if nakedSingle() else if hiddenSingle() else if nakedSet() else if hiddenSet() else if nakedQuad() else if boxLineReduction() else if pointingSet() else break return valid() We settled on using these six rules because it proved to be enough for completing the set of Sudoku puzzles we earlier stated we would try to solve. There are more complex rules available at sudokuwiki [5].

Brute-force solver The brute-force solver is implemented with a smart exhaustive search that uses both ‘look ahead’ and backtracking. With ‘look ahead’ we mean that we implemented this algorithm to be smarter than the normal brute-force approach would with the help of candidates. Instead of trying 1-9 in every cell we first remove all numbers that exist in the same box, row and column (we find the cells candidates); Thereby lowering the amount of numbers that will be tried.

Page 16: Man versus Machine - KTH Solvers Man versus Machine ... An algorithm is backtracking if it can go back ... The purpose of our project is to create and implement a solver that can solve

16

The actual solving is done by the method solve. Unlike solve implemented in the human solver that relies on a loop to run this method is implemented with backtracking in mind. This means that the solve method in the brute-force solver will call itself recursively to find a solution. The simple thoughts of brute-force and backtracking made the implementation of this solver easy and fast which is reflected in how many lines of code we have, which is approximately 70 in the brute-force solver compared to the approximately 660 lines in the human solver. The solver will first go through the grid, look for the first cell with a value of zero and extract the coordinates to the cell that contained the value zero. If, however, no zero was found the algorithm will return the method valid from the class Solver that validates the puzzle. If a zero was found it will look at all values of neighbouring cells in the same box, row and column and save these as possible candidates. It will then iterate over these candidates; calling solve again for each one of them. If a dead end is reached the current solve will return false to the one calling it which will make the caller try the next candidate. The solver is described in the following pseudo code example and the real implementation of the brute-force solver can be found in the code appendix (Appendix B, Solvers). boolean solve() := x = 0, y = 0 for x,y in grid: if grid[x][y].value == 0 found = true break if !(found) return valid() candidates = boolean[10] for i := 0 -> 9: candidates[grid[x][i].value] = true candidates[grid[i][y].value] = true for (cells in same box as cell x,y): candidates[cell.value] = true for j := 1 -> 9: if !(candidates[j]): grid[x][y].value = j if solve() return true grid[x][y].value = 0 return false

Page 17: Man versus Machine - KTH Solvers Man versus Machine ... An algorithm is backtracking if it can go back ... The purpose of our project is to create and implement a solver that can solve

17

Testing

Environment To test our implementations we first modified the code and added some test-code: We added a counter of misses or wrong moves in both HumanSolver and the BruteforceSolver (found in Appendix B, Solvers). In the human solver the miss counter represents the number of rules that the solver has tried to match but didn’t succeed. In the brute-force solver it represents the numbers of wrong turns at a branch, the number of times the algorithm reached a dead end and had to backtrack. We also added a timer to see how long it took for the solver to complete. This code was added to SudokuSolver (found in Appendix B, Shared) since it was identical in both our solvers. To make this timer as fair as possible it only concerns the method calls to solve(). This means that we don’t include the time required to load the Sudoku from file into the grid, initialize the boxes, cells and candidates. We also wanted to be able to test our solvers from the command line, so we added support for sending parameters to SudokuSolver. There are a total of four parameters that can be sent:

1 filename: This will be interpreted as the path to the puzzle you want to solve. 2 solverID: This is specified as an identifier of which solver to use; “human” for

HumanSolver and “brute” for BruteforceSolver. 3 printer: This is used so that the user can tell the program how to print the results;

“human” for a human readable print and “computer” to be used later to get results. 4 test: This specifies which test the user wants to run; “run” for solving speed (runtime),

“miss” for counting of misses and “both” for both the tests above. To be able to run a test on all the available puzzles we wrote a small bash-script, called run.sh (found in Appendix B, Testing), which loops over all available puzzles. It takes some options defined below and sends them to SudokuSolver in the right order. Valid options are:

1 -s: Corresponds to solverID above. 2 -p: Corresponds to printer above. 3 -t: Corresponds to test above.

Example usage: sh run.sh -s human -p computer -t both The number of misses of a puzzle for a certain solver is always the same, so in that aspect it is enough to test each puzzle once with each solver. Unfortunately this is not the case when it comes to solving speed. So to get reliable results of the solving speed per puzzle we made one more bash script, called run_both_tests.sh (found in Appendix B, Testing), that calls run.sh multiple times and saves all output to a text file. It consists of two loops running a fixed number of loops; One that calls run.sh with the human solver and one with the brute-force solver. The loop that runs the human solver appends all output to a file called “human.txt” and the loop that runs the brute-force solver appends all output to “brute.txt”. Both of these are located in a test folder.

Page 18: Man versus Machine - KTH Solvers Man versus Machine ... An algorithm is backtracking if it can go back ... The purpose of our project is to create and implement a solver that can solve

18

To handle all the information in the text files we wrote a new java class named SudokuToExcel (found in Appendix B, Testing). The purpose of this class was to take the two text files produced by run_both_tests.sh and get them into a nicer format for comparisons. It needs a sorted version of human.txt and brute.txt before beginning (!). When it starts it will create a new excel file called result.xls, read from one file at a time; Converting the file from a text file into an ArrayList where an element in the ArrayList corresponds to a row in the file. Then we loop over all these elements, only printing one row per unique Sudoku id, calculating average, minimum and maximum solving time as we go. The end result is a file, which we can open in other programs and get some nice charts and tables from.

Execution The test was performed on one of the desktop computers in the computer lab grön at Lindstedsvägen 3, 4th floor, KTH Royal Institute of Technology. The computer that we performed the tests on is running ubuntu 12.04 LTS and its system specifications are: Memory: 3.8 GiB Processor: Intel® Core™2 Quad CPU Q9550 @ 2.83GHz × 4 OS type: 64-bit We restarted the computer before carrying out the test to make sure no one was logged in and performing tasks in the background. This was done to make sure our tests were as accurate as possible. Then we ran the run_both_tests.sh with the loops running 100 times each. After that was done we executed SudokuToExcel and everything was done for the results. We ran it on all the 60 Sudokus that are available from ne.se [12]. To test the ability to solve harder Sudokus even further we also tested on the 10 first puzzles in Advanced Puzzle Pack 2 from angusj [13] and a weekly unsolvable (that we know is unsolvable for a human) from sudokuwiki [5]. Examples of the Sudokus used in the testing can be found in the examples appendix (Appendix C). The results from the tests can be seen in the next section and they are discussed in the ‘Conclusions’.

Page 19: Man versus Machine - KTH Solvers Man versus Machine ... An algorithm is backtracking if it can go back ... The purpose of our project is to create and implement a solver that can solve

19

Results The test results are presented in three different subsections, each of these presents a view of the results reflecting the three aspects we want to compare. The results of the human solver are presented in blue colour and the brute-force solver in red. All of the Sudoku identifiers presented on the bottom axis are the same identifiers used at ne.se [12]. All results can be found in the results appendix (Appendix A).

Comparison of average solving speed The three charts in this section present the results of the average solving speed for the easy, medium and hard Sudoku puzzles respectively. Solving speed is presented in milliseconds on the left axis and Sudoku identifiers on the bottom axis. All the Sudokus are individually solved and measured 100 times to get a good average solving speed. All these results can be found as numbers in the results appendix (Appendix A). Sudokus of easy difficulty

Figure 4. Average solving speed of the sixteen easy Sudoku puzzles.

Page 20: Man versus Machine - KTH Solvers Man versus Machine ... An algorithm is backtracking if it can go back ... The purpose of our project is to create and implement a solver that can solve

20

Sudokus of medium difficulty

Figure 5. Average solving speed of the twenty-nine medium Sudoku puzzles.

Page 21: Man versus Machine - KTH Solvers Man versus Machine ... An algorithm is backtracking if it can go back ... The purpose of our project is to create and implement a solver that can solve

21

Sudokus of hard difficulty

Figure 6. Average solving speed of the fifteen hard Sudoku puzzles.

Comparison in number of misses The six charts presented in this section are the results of the number of misses the two solvers had for each of the Sudoku puzzles. The time aspect is omitted here because the amounts of misses are a constant factor because we do not use probabilistic algorithms in either of the solvers. The results are presented in two charts per level of difficulty because the differences between the solvers were too vast. All these results can be found as numbers in the results appendix (Appendix A). The left axis represents the number of misses for each of the Sudoku ID’s presented on the bottom axis.

Page 22: Man versus Machine - KTH Solvers Man versus Machine ... An algorithm is backtracking if it can go back ... The purpose of our project is to create and implement a solver that can solve

22

Sudokus of easy difficulty

Figure 7. Number of misses of the sixteen easy Sudoku puzzles solved by the human solver.

Figure 8. Number of misses of the sixteen easy Sudoku puzzles solved by the brute-force solver.

Page 23: Man versus Machine - KTH Solvers Man versus Machine ... An algorithm is backtracking if it can go back ... The purpose of our project is to create and implement a solver that can solve

23

Sudokus of medium difficulty

Figure 9. Number of misses of the twenty-nine medium Sudoku puzzles solved by the human solver.

Page 24: Man versus Machine - KTH Solvers Man versus Machine ... An algorithm is backtracking if it can go back ... The purpose of our project is to create and implement a solver that can solve

24

Figure 10. Number of misses of the twenty-nine medium Sudoku puzzles solved by the brute-force solver.  

Page 25: Man versus Machine - KTH Solvers Man versus Machine ... An algorithm is backtracking if it can go back ... The purpose of our project is to create and implement a solver that can solve

25

Sudokus of hard difficulty

Figure 11. Number of misses of the fifteen hard Sudoku puzzles solved by the human solver.

Figure 12. Number of misses of the fifteen hard Sudoku puzzles solved by the brute-force solver.

Page 26: Man versus Machine - KTH Solvers Man versus Machine ... An algorithm is backtracking if it can go back ... The purpose of our project is to create and implement a solver that can solve

26

Harder Sudokus This section presents the results when attempting to solve harder Sudokus. The Sudokus used in this test are available from the Advanced Puzzle Pack 2 on A. Johnson’s website [13]. The results displayed below in Figure 13 are the results gained from running ‘sh run.sh -s brute -p human -t both’ and ‘sh run.sh -s human -p human -t both’. (These are also available in Appendix A).

BruteforceSolver: Solved  puzzles_harder/puzzle001.ss  in:  27ms  with  5124  misses. Solved  puzzles_harder/puzzle002.ss  in:  23ms  with  2941  misses. Solved  puzzles_harder/puzzle003.ss  in:  28ms  with  4185  misses. Solved  puzzles_harder/puzzle004.ss  in:  16ms  with  2215  misses. Solved  puzzles_harder/puzzle005.ss  in:  25ms  with  3169  misses. Solved  puzzles_harder/puzzle006.ss  in:  23ms  with  4250  misses. Solved  puzzles_harder/puzzle007.ss  in:  27ms  with  3668  misses. Solved  puzzles_harder/puzzle008.ss  in:  21ms  with  2418  misses. Solved  puzzles_harder/puzzle009.ss  in:  25ms  with  7317  misses. Solved  puzzles_harder/puzzle010.ss  in:  27ms  with  3763  misses. Solved  puzzles_harder/unsolvable.ss  in:  25ms  with  23598  misses. -­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐ HumanSolver: Failed  to  solve  puzzles_harder/puzzle001.ss. Failed  to  solve  puzzles_harder/puzzle002.ss. Failed  to  solve  puzzles_harder/puzzle003.ss. Failed  to  solve  puzzles_harder/puzzle004.ss. Failed  to  solve  puzzles_harder/puzzle005.ss. Failed  to  solve  puzzles_harder/puzzle006.ss. Failed  to  solve  puzzles_harder/puzzle007.ss. Failed  to  solve  puzzles_harder/puzzle008.ss. Failed  to  solve  puzzles_harder/puzzle009.ss. Failed  to  solve  puzzles_harder/puzzle010.ss. Failed  to  solve  puzzles_harder/unsolvable.ss.

Figure 13. This is the output from an attempt of solving a harder set of Sudokus with both of the solvers respectively. The lines above the delimiter are the results from the brute-force solver and the ones below the output from the human solver.

Page 27: Man versus Machine - KTH Solvers Man versus Machine ... An algorithm is backtracking if it can go back ... The purpose of our project is to create and implement a solver that can solve

27

Conclusions Our hypothesis, which we presented in the approach, has proven to be quite accurate. The human solver certainly matched the brute-force solver in performance up to a certain point where the puzzles became too difficult. This was not because our rules got too complicated to match the brute-force solver but rather that our rules were not enough to solve the harder Sudokus. In our opinion this thesis turned out above expectations. We succeeded in covering everything in the purpose, and we found a lot of great answers to our concerns and problem statement. We will begin this section by addressing the questions in the purpose, then continue to interpret the results from the section above and lastly we will give an answer to the problem statement:

● Develop a solver that will match the behaviour of a human solving a Sudoku by only using non-guessing rules.

We have developed a solver that we think matches a human solving a Sudoku acceptably. It fulfils the requirement of only using non-guessing rules since we only implemented rules that use pattern matching; Hence ‘non guessing’. The behaviour of a human is not that easy to capture because a human behaviour can sometimes seem quite random; Sometimes they begin in the top-left corner and sometimes the lower-right, it is impossible to say for sure. Therefore we believe that our loop with all rules we implemented in an order of increasing complexity is as close as we can get. When we developed the human solver we looked at the rules at sudokuwiki [5] as described in approach. We only implemented six of the 32 rules defined there because we saw that those six, basic, rules were enough to solve all the Sudokus that we wanted to test on. As a result of this our human solver matches the behaviour of a general human trying to solve a typical Sudoku found in a newspaper and not the behaviour of a Sudoku professional that competes in solving Sudoku. To match that person we would have needed to implement more, if not all, rules found on sudokuwiki [5].

● Test that solver against as many different Sudokus of increasing difficulty as possible. We have tested our solver against 71 different Sudokus of increasing difficulty. We would have wanted to test on even more puzzles but this goal became a bit blunted by the fact that we did not find the extensive database of Sudokus that we were hoping for. However we still think that we fulfilled this goal by choosing archetype Sudokus from a reliable source [6] and testing against very hard puzzles [13]. We also tried to compensate for the somewhat low amount of Sudokus by testing each puzzle several (100) times to get accurate data. We did not include more puzzles in the test because of several things. Firstly, converting those 60 puzzles from ne.se to the .ss format took at least 2 hours. We continued to search but we did not find any more Sudokus as reliable as those first 60. Lastly we did not think that the time

Page 28: Man versus Machine - KTH Solvers Man versus Machine ... An algorithm is backtracking if it can go back ... The purpose of our project is to create and implement a solver that can solve

28

spent looking for and/or converting puzzles was worthwhile when what we really wanted to do was to implement the solvers.

● Compare that solver against other solvers, where we hope that the human rule based solver shall be the most efficient in one of the three aspects we compare: solving speed, number of misses or wrong moves required to find a solution, and ability to solve harder Sudokus.

Overall our human solver performed above expectations and it seems very efficient in both solving speed and number of misses. The last aspect is harder to analyse since we don’t really know how many more rules we must implement to be able to solve the last 11 Sudokus and how that would affect our solving time and number of misses. Regarding the ‘other solvers’ we only implemented one of the two we first thought of. We felt we could do this because we ended up implementing the smarter of the two anyway, which is already stated in our approach. A comparison between our human solver and the brute-force solver on the different aspects mentioned above is included below.

1 Solving speed The human solver is faster in the majority of the average solving speed tests than the brute-force solver with only a few exceptions. By looking at the result of the speed tests we can see that only three Sudokus (with id 0830(easy), 0939(easy), and 0845(medium)) of the total 60 puzzles were solved faster with the brute-force solver (see Figure 4, Figure 5 and Figure 6). Why these particular Sudokus were solved faster with brute-force can be motivated by comparing the result of number of misses for those Sudoku IDs. The amount of backtracking done is minimal in relation to any of the other 57 Sudokus. In fact, none of the three Sudokus exceed 1000 misses (see Figure 8, Figure 10 and Figure 12). We can also see that the number of misses for these three Sudokus when running the human solver is somewhat close to the average amount of misses. This might be the reason why the brute-force solver managed to beat the human solver in terms of speed, if only in these three cases, because the puzzles were suitable to solve with a backtracking solving approach. A reason why the human solver is faster could be that the solving techniques are very time efficient given the probability to find a matching pattern and eliminating possible candidates. However, it is important that we take into consideration that the rules used are quite simple. More complex rules might not showcase this level of time efficiency and in the long run might not be able to beat the stability in solving speed of the brute-force solver.

2 Number of misses or wrong moves required to find a solution The results from this test might be interpreted as extremely successful from the human solvers point of view if not properly examined. As the two solvers uses different approaches it is difficult to equally compare wrong moves and numbers missed by presenting them side by side.

Page 29: Man versus Machine - KTH Solvers Man versus Machine ... An algorithm is backtracking if it can go back ... The purpose of our project is to create and implement a solver that can solve

29

The miss count is measured as unmatched rules in human solver and as number of backtracking steps in the brute-force solver. To get a more comparable view of the data we can multiply the number of misses by 9^3 and interpret the resulting amount as the unmatched patterns for each of the rows, columns and boxes individually per technique. This is a good approximation as most of the rules goes through all of the three region types (row, column and box), containing nine units each, to find a pattern match. If we do this modification to the miss count and compare it of both solvers, we get about 12000 misses for the human solver and about 94000 misses for the brute-force solver. Even though the difference is not as extreme as before the human solver still has a significantly lower amount of misses. (These numbers are calculated from the data in Appendix A). Why the human solver performs better in this test might be because the techniques used depends on matching patterns before applying actions while the brute-force solver actively uses backtracking as tool to search for an solution.

3 Ability to solve harder Sudokus The human solver managed to solve all of the 60 Sudokus from ne.se [12] in difficulties ranging from easy to hard in accordance to the grading performed by ne.se. The testing results of the very hard Sudokus from our additional Sudoku resource [13] can be seen in the last section of results (see Figure 13). While the brute-force solver had a solving speed comparable to previous ones the human solver failed to find a solution to these 11 puzzles. The reason why the human solver failed is because the six rules we have implemented are not enough to solve these particular Sudokus. If we import the Sudokus to the human like solver available at sudokuwiki [5] we can see that techniques like “simple colouring” is required to find a solution. While the online solver manages to complete most of the harder Sudokus, the 11th one in this harder set is unsolvable even for this solver using all of its 32 techniques. A conclusion of this test is that there are Sudoku puzzles that are unsolvable using the definition of human techniques from sudokuwiki [5]. Final conclusions To get a good answer to our problem statement we summarize the conclusions above. We have found that the human solver is comparable to known computer based solvers in terms of solving speed and number of misses. When solving harder Sudokus we cannot be sure if our human solver can produce a solution. However, when solving typical Sudokus found in newspapers we have found that our solver is comparable to the brute-force solver. In our case we have also found that the human solver is generally more efficient than the brute-force solver in the aspects of solving speed and number of misses.

 

Page 30: Man versus Machine - KTH Solvers Man versus Machine ... An algorithm is backtracking if it can go back ... The purpose of our project is to create and implement a solver that can solve

30

Recommendations and possible extensions We hope that this thesis can be a useful resource in future work. Some extensions that we have thought about are:

● Compare the solvers above even further and/or include more kinds of solvers in the comparison.

● Develop a solver that uses several algorithms in different occasions to solve puzzles of different characteristics.

● Build a better and more complex human solver with more rules that will solve more puzzles.

● Compare our human solver above to an already existing human solver in an attempt to make a better human solver.

If someone would like to replicate something in this thesis we would like to give some recommendations so that they would know what to expect:

● Find a reliable database of Sudokus that you can access or a good Sudoku generator before beginning with the testing. You can either do this by searching the web or by building your own. We found some previous work on Sudokus done by students of previous years that described they found a free database containing 10000 puzzles that they could use for testing. We made the assumption that we could simply use the same database for our testing but when we tried to find it we discovered that it had been removed. This alone ended up costing us several hours of work of looking for reliable puzzles and when we finally found them on ne.se [6] they were in PDF format so we had to convert all 60 of them manually before we could continue with the testing.

● Don’t underestimate the time required to implement the solvers, especially the human techniques. By the time we were supposed to be done with the implementation of the solvers we had written them hastily and the code was neither nice looking, effective or easy to understand. It took us at least twice the time it took to write the first version of code to clean, optimize and document it with comments.

Have fun! This is probably the most fun study either of us has done and we hope that you will enjoy it as well. Our only regret is that we didn’t really have the time to implement more rules to the human solver.

Page 31: Man versus Machine - KTH Solvers Man versus Machine ... An algorithm is backtracking if it can go back ... The purpose of our project is to create and implement a solver that can solve

31

References [1] Felgenhauer B, Jarvis F. Enumerating possible Sudoku grids. [Internet]. 2005 [cited 2013 Mar 21]. Available from: http://www.afjarvis.staff.shef.ac.uk/sudoku/ [2] Felgenhauer B, Jarvis F. Mathematics of Sudoku I. [Internet]. 2006 [cited 2013 Mar 21]. Available from: http://www.afjarvis.staff.shef.ac.uk/sudoku/felgenhauer_jarvis_spec1.pdf [3] Mepham M. Solving Sudoku. [Internet]. 2005 [cited 2013 Apr 9]. Available from: http://www.sudoku.org.uk/PDF/Solving_Sudoku.pdf [4] Björkman M. Project Ideas. [Internet]. 2013 [cited 2013 Feb 4]. Availible from: http://www.csc.kth.se/utbildning/kth/kurser/DD143X/dkand13/ProjectIdeas/ [5] Stuart A. Sudoku Solver. [Internet]. 2005 [updated 2012 Oct 22; cited 2013 Mar 4]. Available from: http://www.sudokuwiki.org/sudoku.htm [6] Nationalencyklopedin. sudoku. [Internet]. c2013 [cited 2013 Apr 8]. Availible from: http://www.ne.se/lang/sudoku [7] Johnson A. Solving Sudoku. [Internet] c2005 [cited 2013 Apr 10 ]. Available from: http://angusj.com/sudoku/hints.php [8] Kann V. Föreläsning 7, Metod 2: Totalsökning. [Internet]. c2012 [cited 2013 Apr 10]. Available from: http://www.csc.kth.se/utbildning/kth/kurser/DD1352/adk12/schema/ADK12-F7.pdf [9] Moler C. Cleve’s Corner: Solving Sudoku with MATHLAB. [Internet]. 2009 [cited 2013 Apr 9]. Available from: http://www.mathworks.se/company/newsletters/news_notes/2009/clevescorner.html [10] Crook J. F. A Pencil-and-Paper Algorithm for Solving Sudoku Puzzles. Notices of the AMS. [Internet]. 2009 [cited 2013 Feb 1]; 56(4):460-468. Available from: http://www.ams.org/notices/200904/200904-full-issue.pdf [11] st0le. Sudoku Solver(Bruteforce). [Internet]. 2010 [cited 2013 Mar]. Available from: http://code.activestate.com/recipes/577314-sudoku-solver-bruteforce/?in=user-4174421 [12] Nationalencyklopedin. Sudoku. [Internet]. c2013 [cited 2013 Apr 8]. Availible from: http://www.ne.se/static/entertainment/sudoku.jsp [13] Johnson A. Simple Sudoku. [Internet]. c2002 [cited 2013 Feb 25]. Available from: http://angusj.com/sudoku/

Page 32: Man versus Machine - KTH Solvers Man versus Machine ... An algorithm is backtracking if it can go back ... The purpose of our project is to create and implement a solver that can solve

32

Appendix A - Results

Human - solving time & number of misses

ID Complexity Average  solving  speed  (ms)

Minimum  solving  speed  (ms)

Maximum  solving  speed  (ms)

Number  of  misses

0818 easy 6.25 6 7 9

0830 easy 7.94000005722046 7 51 19

0842 easy 6.78999996185303 6 16 14

0903 easy 6.15000009536743 5 35 10

0915 easy 7.92000007629394 7 9 17

0927 easy 5.80000019073486 5 24 9

0939 easy 7.23000001907349 6 53 18

0948 easy 49.1100006103516 9 66 42

0951 easy 8.15999984741211 7 72 14

1012 easy 6.94999980926514 6 50 13

1024 easy 4.30999994277954 4 9 1

1036 easy 7.38000011444092 7 8 16

1048 easy 6.98999977111816 6 7 17

1109 easy 4.8600001335144 4 49 3

1121 easy 7.69000005722046 7 10 18

1136 easy 5.44999980926514 5 9 12

0815 medium 6.84999990463257 6 9 10

0821 medium 17.1100006103516 7 18 24

0827 medium 49.0299987792969 13 51 16

0833 medium 10.5799999237061 8 11 15

0839 medium 15.1400003433228 11 16 17

0845 medium 12.1099996566772 7 13 16

Page 33: Man versus Machine - KTH Solvers Man versus Machine ... An algorithm is backtracking if it can go back ... The purpose of our project is to create and implement a solver that can solve

33

0851 medium 34.2200012207031 14 35 23

0906 medium 10.8599996566772 6 11 18

0912 medium 9.97999954223633 8 11 21

0918 medium 7.96999979019165 7 8 8

0924 medium 22.75 12 23 22

0930 medium 8.63000011444092 7 9 18

0936 medium 50.7099990844727 18 52 22

0942 medium 25.8500003814697 7 27 32

1001 medium 6.30000019073486 6 8 10

1009 medium 47.810001373291 15 50 32

1015 medium 7.69999980926514 7 9 13

1021 medium 8.35000038146973 8 9 17

1027 medium 13.2299995422363 5 14 22

1033 medium 7.5 7 8 16

1039 medium 10.3999996185303 8 11 17

1045 medium 6.80000019073486 6 19 7

1051 medium 15.1199998855591 8 16 12

1106 medium 48.060001373291 9 49 26

1112 medium 62.0200004577637 5 67 29

1118 medium 8.84000015258789 8 12 20

1124 medium 8.19999980926514 8 9 17

1130 medium 8.5 8 9 11

1140 medium 7.82000017166138 6 8 13

0812 hard 9.11881160736084 9 10 15

0824 hard 12.5100002288818 12 18 13

0836 hard 10.1300001144409 10 11 18

0848 hard 13.2600002288818 13 14 9

Page 34: Man versus Machine - KTH Solvers Man versus Machine ... An algorithm is backtracking if it can go back ... The purpose of our project is to create and implement a solver that can solve

34

0909 hard 7.05000019073486 6 11 8

0921 hard 10.7799997329712 8 12 22

0933 hard 17.3799991607666 9 18 17

0945 hard 8.82999992370606 8 27 17

1006 hard 11.9799995422363 7 13 12

1018 hard 8.64999961853027 8 11 15

1030 hard 6.07999992370606 5 14 8

1042 hard 18.8099994659424 11 19 17

1103 hard 10.0900001525879 9 16 14

1115 hard 8.11999988555908 7 69 17

1127 hard 9.60999965667725 9 10 16

Human - harder puzzles Failed  to  solve  puzzles_harder/puzzle001.ss. Failed  to  solve  puzzles_harder/puzzle002.ss. Failed  to  solve  puzzles_harder/puzzle003.ss. Failed  to  solve  puzzles_harder/puzzle004.ss. Failed  to  solve  puzzles_harder/puzzle005.ss. Failed  to  solve  puzzles_harder/puzzle006.ss. Failed  to  solve  puzzles_harder/puzzle007.ss. Failed  to  solve  puzzles_harder/puzzle008.ss. Failed  to  solve  puzzles_harder/puzzle009.ss. Failed  to  solve  puzzles_harder/puzzle010.ss. Failed  to  solve  puzzles_harder/unsolvable.ss.

Brute-force - solving time & number of misses

ID Complexity Average  solving  speed  (ms)

Minimum  solving  speed  (ms)

Maximum  solving  speed  (ms)

Number  of  misses

0818 easy 23.8899993896484 23 69 4459

0830 easy 6.84999990463257 6 30 941

0842 easy 264.980010986328 76 271 919801

0903 easy 17.3299999237061 16 76 3187

0915 easy 114.839996337891 64 118 256977

Page 35: Man versus Machine - KTH Solvers Man versus Machine ... An algorithm is backtracking if it can go back ... The purpose of our project is to create and implement a solver that can solve

35

0927 easy 48.6399993896484 47 66 10372

0939 easy 2 1 26 180

0948 easy 86.0100021362305 52 90 133623

0951 easy 69.5800018310547 65 90 56787

1012 easy 78.0599975585938 74 84 99532

1024 easy 26.3799991607666 13 27 6183

1036 easy 74.4000015258789 65 77 87382

1048 easy 58.439998626709 55 73 12624

1109 easy 63.0099983215332 57 232 17858

1121 easy 164.229995727539 64 176 472687

1136 easy 101.730003356934 25 111 203181

0815 medium 64.6399993896484 62 68 39988

0821 medium 55.6699981689453 24 58 11707

0827 medium 29.7099990844727 28 113 5600

0833 medium 59.560001373291 7 62 14295

0839 medium 72.8099975585938 52 75 72972

0845 medium 10.1099996566772 7 272 969

0851 medium 65.8000030517578 62 68 41840

0906 medium 61.2999992370606 18 63 22786

0912 medium 61.4700012207031 58 69 19584

0918 medium 62.4000015258789 58 121 29138

0924 medium 62.1100006103516 57 75 28757

0930 medium 60.7799987792969 56 63 21218

0936 medium 16.4599990844727 15 86 3195

0942 medium 57.9099998474121 2 62 12900

1001 medium 62.3400001525879 58 71 29881

1009 medium 72.8300018310547 69 85 71609

Page 36: Man versus Machine - KTH Solvers Man versus Machine ... An algorithm is backtracking if it can go back ... The purpose of our project is to create and implement a solver that can solve

36

1015 medium 60.6500015258789 57 83 21093

1021 medium 12.039999961853 9 13 2080

1027 medium 90.4599990844726 28 116 144924

1033 medium 58.6100006103516 54 81 16892

1039 medium 63.4300003051758 59 89 32461

1045 medium 70.6999969482422 64 73 63678

1051 medium 58.8400001525879 56 62 16131

1106 medium 216.210006713867 19 231 702962

1112 medium 62.4199981689453 59 73 26854

1118 medium 63.3300018310547 57 281 21307

1124 medium 72.7600021362305 69 183 72035

1130 medium 18.7399997711182 18 37 3476

1140 medium 87.0100021362305 83 114 144910

0812 hard 65.1980209350586 60 68 43550

0824 hard 110.360000610352 60 113 235230

0836 hard 47.9599990844727 47 63 10009

0848 hard 59.1300010681152 8 62 19380

0909 hard 65.0199966430664 62 68 40058

0921 hard 61.9199981689453 59 69 27012

0933 hard 79.3899993896484 63 83 100176

0945 hard 68.4800033569336 65 73 58464

1006 hard 66.2099990844726 64 71 43762

1018 hard 9.5600004196167 8 65 1404

1030 hard 67.0899963378906 64 94 50496

1042 hard 59.8800010681152 57 67 18803

1103 hard 17.5200004577637 16 63 3082

1115 hard 274.529998779297 67 281 1018505

Page 37: Man versus Machine - KTH Solvers Man versus Machine ... An algorithm is backtracking if it can go back ... The purpose of our project is to create and implement a solver that can solve

37

1127 hard 36.4099998474121 35 81 7186

Brute-force - harder puzzles

Solved  puzzles_harder/puzzle001.ss  in:  27ms  with  5124  misses. Solved  puzzles_harder/puzzle002.ss  in:  23ms  with  2941  misses. Solved  puzzles_harder/puzzle003.ss  in:  28ms  with  4185  misses. Solved  puzzles_harder/puzzle004.ss  in:  16ms  with  2215  misses. Solved  puzzles_harder/puzzle005.ss  in:  25ms  with  3169  misses. Solved  puzzles_harder/puzzle006.ss  in:  23ms  with  4250  misses. Solved  puzzles_harder/puzzle007.ss  in:  27ms  with  3668  misses. Solved  puzzles_harder/puzzle008.ss  in:  21ms  with  2418  misses. Solved  puzzles_harder/puzzle009.ss  in:  25ms  with  7317  misses. Solved  puzzles_harder/puzzle010.ss  in:  27ms  with  3763  misses. Solved  puzzles_harder/unsolvable.ss  in:  25ms  with  23598  misses.

Page 38: Man versus Machine - KTH Solvers Man versus Machine ... An algorithm is backtracking if it can go back ... The purpose of our project is to create and implement a solver that can solve

38

Appendix B - Code

Shared

Cell.java import  java.util.HashSet; /** *  This  class  represents  an  abstract  sudoku  cell. *  For  each  Cell  it  holds  the  Cell's  value,  the *  Cell's  candidates  and  the  boxID  that  this *  particular  Cell  belongs  to. * *  @version  1.0 *  @author  Andreas  Broström *  @author  Simon  Johansson */ public  class  Cell  {  private  int  value;  public  int  boxID;  public  HashSet<Integer>  candidates;  /**    *  This  is  called  upon  initialization  and  will    *  set  the  Cell's  value  and  initial  candidates.    *    *  @param  value  is  the  value  that  will  be  held  by    *  the  Cell.    */  public  Cell(int  value){      this.value  =  value;      this.candidates  =  new  HashSet<Integer>(9);      if(value  ==  0){          for(int  i=1;i<=9;i++){              this.candidates.add(i);          }        }    }  /**    *  Sets  the  Cell's  value.    *    *  @param  inputValue  will  overwrite  the  current    *  value  held  by  the  Cell.    */  public  void  setValue(int  inputValue){      this.value  =  inputValue;      this.candidates.clear();  }  /**    *  Gets  the  Cell's  value.    *    *  @return  the  value  of  this  Cell.    */

Page 39: Man versus Machine - KTH Solvers Man versus Machine ... An algorithm is backtracking if it can go back ... The purpose of our project is to create and implement a solver that can solve

39

 public  int  getValue(){      return  this.value;  } }

Solver.java import  java.io.BufferedReader; import  java.io.DataInputStream; import  java.io.FileInputStream; import  java.io.InputStreamReader; import  java.util.ArrayList; import  java.util.HashMap; import  java.util.HashSet; import  java.util.Iterator; /** *  This  class  tries  to  solve  a  sudoku  using  human  techniques *  with  the  help  of  Solver. * *  @version  1.0 *  @author  Andreas  Broström *  @author  Simon  Johansson * */ public  class  Solver  {  public  Cell[][]  grid;  public  HashMap<Integer,  ArrayList<Integer[]>>  boxMap;  /**    *  Loads  a  sudoku  from  file  into  a  String.    *    *  @param  filename  is  the  location  and  name  of  the  simple    *  sudoku  puzzle.  ex:  'puzzles/medium[1027].ss'.    *    *  @return  a  string  representation  of  the  sudoku-­‐file.    */  public  String  load_sudoku(String  filename){      StringBuilder  builder  =  new  StringBuilder();      try{          FileInputStream  fstream  =  new  FileInputStream(filename);          DataInputStream  in  =  new  DataInputStream(fstream);          BufferedReader  br  =  new  BufferedReader(new  InputStreamReader(in));          String  strLine;          while  ((strLine  =  br.readLine())  !=  null)      {              strLine  =  strLine.replace("|","").replace("-­‐",  "").replace("\n",  "").replace(".",  "0");              builder.append(strLine);          }          in.close();      }catch(Exception  e){          System.err.println("Error:  "  +  e.getMessage());      }      return  builder.toString();  }  /**    *  Initlializes  the  sudoku  grid  from  a  string  of  numbers.  It    *  goes  through  all  Cell's,  initializing  and  sets  a  value    *  according  to  strSudoku.  (to  the  file)

Page 40: Man versus Machine - KTH Solvers Man versus Machine ... An algorithm is backtracking if it can go back ... The purpose of our project is to create and implement a solver that can solve

40

   *    *  @param  filename  is  a  simple  sudoku  file  (.ss)  that  is    *  sent  to  load_sudoku  for  loading.    */  protected  void  initGrid(String  filename){      grid  =  new  Cell[9][9];      String  strSudoku  =  load_sudoku(filename);      for(int  row=0;row<9;row++){          for(int  col=0;col<9;col++){              grid[row][col]  =  new  Cell(Integer.parseInt(strSudoku.charAt(9*row  +  col)+""));          }      }  }  /**    *  Initializes  the  boxID's  of  all  Cell's  in  the  grid.  boxID  is    *  an  int  from  1  to  9  which  does  so  that  the  program  quickly    *  can  determine  in  which  box  a  cell  belongs  to.    */  protected  void  initBoxID(){      for(int  row  =  0;  row  <  3;  row++){          for(int  col  =  0;  col  <  3;  col++){              for(int  dRow  =  0;  dRow  <  3  ;dRow++){                  for(int  dCol  =  0;  dCol  <  3;  dCol++){                      grid[row+dRow*3][col+dCol*3].boxID  =  1  +  (dCol  +  dRow  *  3);                  }              }          }      }  }  /**    *  Initializes  and  fills  the  boxMap  with  the  coordinates    *  of  all  Cell's  that  belong  to  a  box  for  each  box.    */  protected  void  initBoxMap(){      boxMap  =  new  HashMap<Integer,  ArrayList<Integer[]>>();      for(int  boxNum  =  1;boxNum<=9;boxNum++){          boxMap.put(new  Integer(boxNum),  new  ArrayList<Integer[]>(9));      }      for(int  rowChunk=0;rowChunk<3;rowChunk++){          for(int  colChunk=0;colChunk<3;colChunk++){              for(int  rowBox=0;rowBox<3;rowBox++){                  for(int  colBox=0;colBox<3;colBox++){                      Integer[]  coords  =  new  Integer[]{rowBox+rowChunk*3,colBox+colChunk*3};                      boxMap.get(1+(rowChunk*3  +  colChunk)).add(coords);                  }              }          }      }  }  /**    *  Finds  all  Cell's  in  a  specific  row.    *    *  @param  rowNr  points  to  a  specific  row  in  the  grid.    *    *  @return  an  ArrayList  with  all  coordinates  to  the    *  Cell's  in  that  particular  row.

Page 41: Man versus Machine - KTH Solvers Man versus Machine ... An algorithm is backtracking if it can go back ... The purpose of our project is to create and implement a solver that can solve

41

   */  public  ArrayList<Integer[]>  getRow(int  rowNr){      ArrayList<Integer[]>  row  =  new  ArrayList<Integer[]>();      for(int  col=0;col<9;col++){          row.add(new  Integer[]{rowNr,col});      }      return  row;  }  /**    *  Finds  all  Cell's  in  a  specific  column.    *    *  @param  colNr  points  to  a  specific  column  in  the  grid.    *    *  @return  an  ArrayList  with  all  coordinates  to  the    *  Cell's  in  that  particular  column.    */  public  ArrayList<Integer[]>  getCol(int  colNr){      ArrayList<Integer[]>  col  =  new  ArrayList<Integer[]>();      for(int  row=0;row<9;row++){          col.add(new  Integer[]{row,colNr});      }      return  col;  }  /**    *  Finds  all  Cell's  in  a  specific  box.    *    *  @param  boxID  points  to  a  specific  box  in  the  grid.    *    *  @return  an  ArrayList  with  all  coordinates  to  the    *  Cell's  in  that  particular  box.    */  public  ArrayList<Integer[]>  getBox(int  boxID){      return  boxMap.get(boxID);  }  /**    *  Checks  if  the  grid  fullfills  the  sudoku  contraints.    *    *  @return  boolean  which  is  true  if  the  puzzle  fullfills    *  the  sudoku  contraints  and  false  otherwise.    */  public  boolean  valid(){      int  cellVal;      ArrayList<Integer[]>  unit;      ArrayList<Integer>  unitValues;      for  (int  unitSelect  =  0;  unitSelect  <  3;  unitSelect++)  {          for  (int  pos  =  0;  pos  <  9;  pos++)  {              unitValues  =  new  ArrayList<Integer>(9);              unit  =  new  ArrayList<Integer[]>(9);              if  (unitSelect  ==  0)  {                  unit  =  getRow(pos);              }  else  if  (unitSelect  ==  1)  {                  unit  =  getCol(pos);              }  else  if  (unitSelect  ==  2)  {

Page 42: Man versus Machine - KTH Solvers Man versus Machine ... An algorithm is backtracking if it can go back ... The purpose of our project is to create and implement a solver that can solve

42

                 unit  =  getBox(pos+1);              }              for  (Integer[]  coordinates  :  unit)  {                  cellVal  =  grid[coordinates[0]][coordinates[1]].getValue();                  if  (cellVal  ==  0)  {                      return  false;                  }  else  if  (!unitValues.contains(cellVal)){                      unitValues.add(cellVal);                  }  else  {                      return  false;                  }              }          }      }      return  true;  } }

SudokuSolver.java /** *  This  class  is  used  as  an  interface  so  that  run.sh *  can  solve  several  sudokus  from  the  command  line *  with  the  option  of  choosing  solver. * *  @version  1.0 *  @author  Andreas  Broström *  @author  Simon  Johansson */ public  class  SudokuSolver  {  static  String  filename;  static  String  printer  =  "human";  static  String  test  =  "both";  static  boolean  solved  =  false;    /**    *  Provides  support  to  be  run  both  with  or    *  without  arguments.    *    *  @param  args  is  either  empty  or  looks  like  this:    *  {filename,  solverID,  printer,  test}    *    *  @param  filename  is  the  path  to  the  sudoku  you    *  want  to  solve.    *    *  @param  printer  is  an  option  that  decides  how  the  result    *  will  be  presented.  "human"  form  human  readable  and    *  "computer"  for  computer  readable.    *    *  @param  test  defines  what  test  is  to  be  presented.  "run"  is    *  the  runtime  of  the  solver,  "miss"  is  the  missCount  and    *  everything  else  gets  interpreted  as  both  of  them.    *    *  @param  solverID  is  an  abbreviation  of  which    *  solver  you  would  like  to  use.    *    *  @example  An  example  use  could  look  like  this:    *  "java  SudokuSolver  puzzles/hard[1115].ss  human  human  run"

Page 43: Man versus Machine - KTH Solvers Man versus Machine ... An algorithm is backtracking if it can go back ... The purpose of our project is to create and implement a solver that can solve

43

   */  public  static  void  main(String[]  args)  {      int  missCount  =  0;      long  t0  =  0;      long  t1  =  0;            /*  Handling  input  to  the  program:        *  what  solver  to  use,  print  format  and  tests.        */      if  (args.length  >  1)  {          filename  =  args[0];                    if  (args.length  >  2)  {              printer  =  args[2];              if  (args.length  >  3)  {                  test  =  args[3];              }          }          if  (args[1].equalsIgnoreCase("brute"))  {              BruteforceSolver  bfs  =  new  BruteforceSolver(filename);              t0  =  System.currentTimeMillis();              solved  =  bfs.solve();              t1  =  System.currentTimeMillis();              missCount  =  bfs.missCount;          }  else  if  (args[1].equalsIgnoreCase("human"))  {              HumanSolver  hs  =  new  HumanSolver(filename);              t0  =  System.currentTimeMillis();              solved  =  hs.solve();              t1  =  System.currentTimeMillis();              missCount  =  hs.missCount;          }  else  {              System.out.println("Not  a  valid  solver!");          }        }  else  {          filename  =  "puzzles/hard[1115].ss";          HumanSolver  hs  =  new  HumanSolver(filename);          t0  =  System.currentTimeMillis();          solved  =  hs.solve();          t1  =  System.currentTimeMillis();          missCount  =  hs.missCount;      }            //Handles  output      if  (solved)  {          if  (test.equalsIgnoreCase("run"))  {              if  (printer.equalsIgnoreCase("human"))  {                  System.out.println("Solved  "  +  filename  +  "  in:  "  +  (t1  -­‐  t0)  +  "ms.");              }  else  if  (printer.equalsIgnoreCase("computer"))  {                  String[]  fileinfo  =  filename.split("/|.ss")[1].split("\\[");                  System.out.println(fileinfo[1].split("\\]")[0]  +  "$"  +  fileinfo[0]  +  "$"  +  (t1  -­‐  t0));              }          }  else  if  (test.equalsIgnoreCase("miss"))  {              if  (printer.equalsIgnoreCase("human"))  {                  System.out.println("Solved  "  +  filename  +  "  in:  "  +  missCount  +  "  misses.");              }  else  if  (printer.equalsIgnoreCase("computer"))  {                  String[]  fileinfo  =  filename.split("/|.ss")[1].split("\\[");                  System.out.println(fileinfo[1].split("\\]")[0]  +  "$"  +  fileinfo[0]  +  "$"  +  missCount);              }          }  else  {

Page 44: Man versus Machine - KTH Solvers Man versus Machine ... An algorithm is backtracking if it can go back ... The purpose of our project is to create and implement a solver that can solve

44

             if  (printer.equalsIgnoreCase("human"))  {                  System.out.println("Solved  "  +  filename  +  "  in:  "  +  (t1  -­‐  t0)  +  "ms  with  "  +  missCount  +  "  misses.");              }  else  if  (printer.equalsIgnoreCase("computer"))  {                  String[]  fileinfo  =  filename.split("/|.ss")[1].split("\\[");                  System.out.println(fileinfo[1].split("\\]")[0]  +  "$"  +  fileinfo[0]  +  "$"  +  (t1  -­‐  t0)  +  "$"  +  missCount);              }          }      }  else  {          System.out.println("Failed  to  solve  "  +  filename  +  ".");      }  } }

Solvers

HumanSolver.java import  java.util.ArrayList; import  java.util.HashSet; import  java.util.Set; /** *  This  class  tries  to  solve  a  sudoku  using  human  techniques *  with  the  help  of  Solver. * *  @version  1.0 *  @author  Andreas  Broström *  @author  Simon  Johansson * *  @see  Solver */ public  class  HumanSolver  extends  Solver{  public  int  missCount  =  0;  private  ArrayList<Integer[]>  unit;  /**    *  Initializes  the  grid,  the  boxID's  and  the  boxMap  and    *  updates  all  candidates  for  the  first  time.    *    *  @param  filename  is  the  name  of  a  sudoku  file  in  the  simple    *  sudoku  format  (.ss).    */  public  HumanSolver(String  filename)  {      initGrid(filename);      initBoxID();      initBoxMap();      updateCandidates();  }  /**    *  Loops  trough  the  rules  until  a  solution  is  found  or  until    *  no  successful  rules  can  be  applied.    *    *  @return  boolean  which  is  true  if  the  sudoku  was  solved  and    *  false  otherwise.

Page 45: Man versus Machine - KTH Solvers Man versus Machine ... An algorithm is backtracking if it can go back ... The purpose of our project is to create and implement a solver that can solve

45

   */  public  boolean  solve()  {      while(true)  {          //Set  refers  to  either  pair  or  triple          if  (ruleNakedSingles())  {              //Naked  single  found          }  else  if  (ruleHiddenSingle())  {              //Hidden  single  found              missCount  +=  1;          }  else  if  (ruleNakedSet())  {              //Naked  set  found.              missCount  +=  2;          }  else  if  (ruleHiddenSet())  {              //Hidden  set  found!              missCount  +=  3;          }  else  if  (ruleNakedQuad())  {              //Naked  quad  found              missCount  +=  4;          }  else  if  (ruleBoxLineReduction())  {              //Box  line  reduction  found              missCount  +=  5;          }  else  if  (rulePointingSet())  {              //Pointing  set  found              missCount  +=  6;          }  else  {              //  No  rule  could  be  matched              break;          }      }      return  valid();  }  /**    *  Go  through  all  cells  and  updates  their  candidates    */  public  void  updateCandidates()  {      for  (int  row  =  0;  row  <  9;  row++)  {          for  (int  col  =  0;  col  <  9;  col++)  {              updateCellClosure(row,col);          }      }  }  /**    *  Removes  the  cell  value  from  the  candidate  lists    *  of  the  other  cells  in  the  same  units    *    *  @param  cellRow  a  coordinate  specifying  in  which  row  the    *  targeted  cell  can  be  found.    *    *  @param  cellCol  a  coordinate  specifying  the  column  of  the    *  targeted  cell  can  be  found.    */  public  void  updateCellClosure(int  cellRow,  int  cellCol)  {      if  (grid[cellRow][cellCol].getValue()  !=  0)  {          int  cellValue  =  grid[cellRow][cellCol].getValue();

Page 46: Man versus Machine - KTH Solvers Man versus Machine ... An algorithm is backtracking if it can go back ... The purpose of our project is to create and implement a solver that can solve

46

         for  (int  unitSelect  =  0;  unitSelect  <  3;  unitSelect++)  {              if  (unitSelect  ==  0)  {                  unit  =  getRow(cellRow);              }              else  if  (unitSelect  ==  1)  {                  unit  =  getCol(cellCol);              }              else  if  (unitSelect  ==  2)  {                  unit  =  getBox(grid[cellRow][cellCol].boxID);              }              for  (Integer[]  elem  :  unit)  {                  int  row  =  elem[0];                  int  col  =  elem[1];                  if  (cellRow  !=  row  ||  cellCol  !=  col)  {                      if  (grid[row][col].candidates.contains(cellValue))  {                          grid[row][col].candidates.remove((Object)cellValue);                      }                  }              }          }      }  }  /**    *  A  rule  that  looks  for  any  single  candidates,  if    *  so  set  the  value  to  the  single  candidate    *    *  @return  boolean  which  is  true  if  the  rule  succeeded    *  and  the  grid  is  changed  or  false  otherwise    */  private  boolean  ruleNakedSingles()  {      for  (int  row  =  0;  row  <  9;  row++)  {          for  (int  col  =  0;  col  <  9;  col++)  {              HashSet<Integer>  cellCandidates  =  grid[row][col].candidates;              if  (cellCandidates.size()==1)  {                  grid[row][col].setValue(cellCandidates.iterator().next());                  updateCellClosure(row,  col);                  return  true;              }          }      }      return  false;  }  /**    *  This  rule  looks  for  hidden  singles,  defined    *  here:  http://www.sudokuwiki.org/Getting_Started    *    *  @return  boolean  which  is  true  if  the  rule  succeeded    *  and  the  grid  is  changed  or  false  otherwise    */  private  boolean  ruleHiddenSingle()  {      int  []  unitCandidates  =  new  int[10];      //  For  each  row,  column  or  boxID      for  (int  unitSelect  =  0;  unitSelect  <  3;  unitSelect++)  {          for  (int  i  =  0;  i  <  9;  i++)  {

Page 47: Man versus Machine - KTH Solvers Man versus Machine ... An algorithm is backtracking if it can go back ... The purpose of our project is to create and implement a solver that can solve

47

             if  (unitSelect  ==  0)  {                  unit  =  getRow(i);              }              else  if  (unitSelect  ==  1)  {                  unit  =  getCol(i);              }              else  if  (unitSelect  ==  2)  {                  unit  =  getBox(i  +  1);              }              for  (int  n  =  1;  n  <=  9;  n++)  {                  unitCandidates[n]  =  0;              }              for  (Integer[]  elem:unit)  {                  int  row  =  elem[0];                  int  col  =  elem[1];                  if  (grid[row][col].getValue()  ==  0)  {                      for  (int  cand:grid[row][col].candidates)  {                          unitCandidates[cand]  +=  1;                      }                  }              }              int  foundDigit  =  0;              for  (int  n  =  1;  n  <=  9;  n++)  {                  //  Check  for  hidden  single                  if  (unitCandidates[n]  ==  1)  {                      //  Found  hidden  single                      foundDigit  =  n;                      break;                  }              }              //  If  a  hidden  single  was  found,  check  what  cell              //  contained  that  hidden  single  and  set  cell  value              if  (foundDigit  !=  0)  {                  for  (Integer[]  elem:unit)  {                      int  row  =  elem[0];                      int  col  =  elem[1];                      if  (grid[row][col].getValue()  ==  0)  {                          if  (grid[row][col].candidates.contains((Object)  foundDigit))  {                              grid[row][col].setValue(foundDigit);                              updateCellClosure(row,col);                              return  true;                          }                      }                  }              }            }      }      return  false;  }  /**    *  This  rule  finds  all  naked  pairs/triples,  defined    *  here:  http://www.sudokuwiki.org/Naked_Candidates    *    *  @return  boolean  which  is  true  if  the  rule  succeeded    *  and  the  grid  is  changed  or  false  otherwise    */  private  boolean  ruleNakedSet()  {

Page 48: Man versus Machine - KTH Solvers Man versus Machine ... An algorithm is backtracking if it can go back ... The purpose of our project is to create and implement a solver that can solve

48

     Set<Integer>  union2,  union3;      Integer[]  elem,  elemA,  elemB,  elemC;      int  row,  col;      //  For  each  row,  column  or  boxID      for  (int  unitSelect  =  0;  unitSelect  <  3;  unitSelect++)  {          for  (int  i  =  0;  i  <  9;  i++)  {              if  (unitSelect  ==  0)  {                  unit  =  getRow(i);              }              else  if  (unitSelect  ==  1)  {                  unit  =  getCol(i);              }              else  if  (unitSelect  ==  2)  {                  unit  =  getBox(i  +  1);              }              //  Puts  all  empty  cell  coordinates  in  freeCells              ArrayList<Integer[]>  freeCells  =  new  ArrayList<Integer[]>();              for  (int  j  =  0;  j  <  9;  j++)  {                  elem  =  unit.get(j);                  row  =  elem[0];                  col  =  elem[1];                  if  (grid[row][col].getValue()  ==  0)  {                      freeCells.add(elem);                  }              }              int  freeSize  =  freeCells.size();              for  (int  a  =  0;  a  <  freeSize;  a++)  {                  for  (int  b  =  a  +  1;  b  <  freeSize;  b++)  {                      elemA  =  freeCells.get(a);                      elemB  =  freeCells.get(b);                      union2  =  new  HashSet<Integer>(grid[elemA[0]][elemA[1]].candidates);                      union2.addAll(grid[elemB[0]][elemB[1]].candidates);                      //  Check  for  naked  pair                      if  (union2.size()  ==  2)  {                          //  Naked  pair  found                          boolean  changed  =  false;                          for  (int  n  =  0;  n  <  freeSize;  n++)  {                              if  (n  !=  a  &&  n  !=  b)  {                                  elem  =  freeCells.get(n);                                  changed  =  grid[elem[0]][elem[1]].candidates.removeAll(union2);                              }                          }                          if  (changed)  {                              return  true;                          }                      }                      //  Check  for  naked  triplet                      else  if  (union2.size()  ==  3)  {                          //  Maybe  a  naked  triplet  found                          for  (int  c  =  b  +  1;  c  <  freeSize;  c++)  {                              union3  =  new  HashSet<Integer>(union2);                              elemC  =  freeCells.get(c);                              union3.addAll(grid[elemC[0]][elemC[1]].candidates);

Page 49: Man versus Machine - KTH Solvers Man versus Machine ... An algorithm is backtracking if it can go back ... The purpose of our project is to create and implement a solver that can solve

49

                             if  (union3.size()  ==  3)  {                                  //  Naked  triplet  found                                  boolean  changed  =  false;                                  for  (int  n  =  0;  n  <  freeSize;  n++)  {                                      if  (n  !=  a  &&  n  !=  b  &&  n  !=  c)  {                                          elem  =  freeCells.get(n);                                          changed  =  grid[elem[0]][elem[1]].candidates.removeAll(union3);                                      }                                  }                                  if  (changed)  {                                      return  true;                                  }                              }                          }                      }                  }              }          }      }      return  false;  }  /**    *  This  rule  that  finds  all  naked  quads,  defined    *  here:  http://www.sudokuwiki.org/Naked_Candidates#NQ    *    *  @return  boolean  which  is  true  if  the  rule  succeeded    *  and  the  grid  is  changed  or  false  otherwise    */  private  boolean  ruleNakedQuad()  {      Set<Integer>  union4;      Integer[]  elem,  elemA,  elemB,  elemC,  elemD;      int  row,  col;      //  For  each  row,col  or  boxID      for  (int  unitSelect  =  0;  unitSelect  <  3;  unitSelect++)  {          for  (int  i  =  0;  i  <  9;  i++)  {              if  (unitSelect  ==  0)  {                  unit  =  getRow(i);              }              else  if  (unitSelect  ==  1)  {                  unit  =  getCol(i);              }              else  if  (unitSelect  ==  2)  {                  unit  =  getBox(i  +  1);              }              //  Puts  all  empty  cell  coordinates  in  freeCells              ArrayList<Integer[]>  freeCells  =  new  ArrayList<Integer[]>();              for  (int  j  =  0;  j  <  9;  j++)  {                  elem  =  unit.get(j);                  row  =  elem[0];                  col  =  elem[1];                  if  (grid[row][col].getValue()  ==  0)  {                      freeCells.add(elem);                  }              }              int  freeSize  =  freeCells.size();              for  (int  a  =  0;  a  <  freeSize;  a++)  {

Page 50: Man versus Machine - KTH Solvers Man versus Machine ... An algorithm is backtracking if it can go back ... The purpose of our project is to create and implement a solver that can solve

50

                 for  (int  b  =  a  +  1;  b  <  freeSize;  b++)  {                      for  (int  c  =  b  +  1;  c  <  freeSize;  c++)  {                          for  (int  d  =  c  +  1;  d  <  freeSize;  d++)  {                              elemA  =  freeCells.get(a);                              elemB  =  freeCells.get(b);                              elemC  =  freeCells.get(c);                              elemD  =  freeCells.get(d);                              union4  =  new  HashSet<Integer>(grid[elemA[0]][elemA[1]].candidates);                              union4.addAll(grid[elemB[0]][elemB[1]].candidates);                              union4.addAll(grid[elemC[0]][elemC[1]].candidates);                              union4.addAll(grid[elemD[0]][elemD[1]].candidates);                              //  Check  for  quad                              if  (union4.size()  ==  4)  {                                  //  Naked  quad  found                                  boolean  changed  =  false;                                  for  (int  n  =  0;  n  <  freeSize;  n++)  {                                      if  (n  !=  a  &&  n  !=  b  &&  n  !=  c  &&  n  !=  d)  {                                          elem  =  freeCells.get(n);                                          changed  =  grid[elem[0]][elem[1]].candidates.removeAll(union4);                                      }                                  }                                  if  (changed)  {                                      return  true;                                  }                              }                          }                      }                  }              }          }      }      return  false;  }  /**    *  This  rule  finds  all  hidden  pairs/triples,  defined    *  here:  http://www.sudokuwiki.org/Hidden_Candidates    *    *  @return  boolean  which  is  true  if  the  rule  succeeded    *  and  the  grid  is  changed  or  false  otherwise    */  private  boolean  ruleHiddenSet()  {      Set<Integer>  remainingDigits  =  new  HashSet<Integer>();      int  row,  col;      //  For  each  row,  column  or  boxID      for  (int  unitSelect  =  0;  unitSelect  <  3;  unitSelect++)  {          for  (int  i  =  0;  i  <  9;  i++)  {              if  (unitSelect  ==  0)  {                  unit  =  getRow(i);                  remainingDigits.clear();              }              else  if  (unitSelect  ==  1)  {                  unit  =  getCol(i);                  remainingDigits.clear();              }

Page 51: Man versus Machine - KTH Solvers Man versus Machine ... An algorithm is backtracking if it can go back ... The purpose of our project is to create and implement a solver that can solve

51

             else  if  (unitSelect  ==  2)  {                  unit  =  getBox(i  +  1);                  remainingDigits.clear();              }              //  Get  remaining  digit  in  this  unit              for  (Integer[]  elem:unit)  {                  row  =  elem[0];                  col  =  elem[1];                  remainingDigits.addAll(grid[row][col].candidates);              }              //  Put  empty  cells  coordinates  in  freeCells              ArrayList<Integer[]>  freeCells  =  new  ArrayList<Integer[]>();              for  (Integer[]  elem:unit)  {                  row  =  elem[0];                  col  =  elem[1];                  if  (grid[row][col].getValue()  ==  0)  {                      freeCells.add(elem);                  }              }              int  freeSize  =  freeCells.size();              for  (int  a  =  0;  a  <  freeSize;  a++)  {                  for  (int  b  =  a  +  1;  b  <  freeSize;  b++)  {                      //  Checking  two  cells  at  a  time                      Set<Integer>  excludingSet  =  new  HashSet<Integer>(remainingDigits);                      for  (int  n  =  0;  n  <  freeSize;  n++)  {                          if  (n  !=  a  &&  n  !=  b)  {                              Integer[]  elem  =  freeCells.get(n);                              row  =  elem[0];                              col  =  elem[1];                              excludingSet.removeAll(grid[row][col].candidates);                          }                      }                      boolean  changed  =  false;                      //  Check  if  hidden  pair                      if  (excludingSet.size()  ==  2)  {                          //  Found  hidden  pair  with  the  content  of  excluding  set                          Integer[]  elem;                          for  (int  k  :  new  int[]{a,  b})  {                              elem  =  freeCells.get(k);                              row  =  elem[0];                              col  =  elem[1];                              if  (grid[row][col].candidates.retainAll(excludingSet))  {                                  changed  =  true;                              }                          }                      }                      if  (changed)  {                          return  true;                      }                      //  Check  for  hidden  triples                      for  (int  c  =  b  +  1;  c  <  freeSize;  c++)  {                          excludingSet  =  new  HashSet<Integer>(remainingDigits);

Page 52: Man versus Machine - KTH Solvers Man versus Machine ... An algorithm is backtracking if it can go back ... The purpose of our project is to create and implement a solver that can solve

52

                         for  (int  n  =  0;  n  <  freeSize;  n++)  {                              if  (n  !=  a  &&  n  !=  b  &&  n  !=  c)  {                                  Integer[]  elem  =  freeCells.get(n);                                  row  =  elem[0];                                  col  =  elem[1];                                  excludingSet.removeAll(grid[row][col].candidates);                              }                          }                          changed  =  false;                          if  (excludingSet.size()  ==  3)  {                              //  Found  hidden  pair  with  the  content  of  excluding  set                              Integer[]  elem;                              for  (int  k  :  new  int[]{a,  b,  c})  {                                  elem  =  freeCells.get(k);                                  row  =  elem[0];                                  col  =  elem[1];                                  if  (grid[row][col].candidates.retainAll(excludingSet))  {                                      changed  =  true;                                  }                              }                          }                          if  (changed)  {                              return  true;                          }                      }                  }              }          }      }      return  false;  }  /**    *  This  rule  find  any  box/line  reductions,  defined    *  here:  http://www.sudokuwiki.org/Intersection_Removal#LBR    *    *  @return  boolean  which  is  true  if  the  rule  succeeded    *  and  the  grid  is  changed  or  false  otherwise    */  private  boolean  ruleBoxLineReduction()  {      ArrayList<ArrayList<Integer[]>>  unitCandidates  =  new  ArrayList<ArrayList<Integer[]>>(10);      int  row,  col;      //  For  each  row  and  column      for  (int  unitSelect  =  0;  unitSelect  <  2;  unitSelect++)  {          for  (int  i  =  0;  i  <  9;  i++)  {              if  (unitSelect  ==  0)  {                  unit  =  getRow(i);                  unitCandidates.clear();                  for  (int  j  =  0;  j  <=  9;  j++)  {                      unitCandidates.add(new  ArrayList<Integer[]>());                  }              }              else  if  (unitSelect  ==  1)  {                  unit  =  getCol(i);                  unitCandidates.clear();                  for  (int  j  =  0;  j  <=  9;  j++)  {                      unitCandidates.add(new  ArrayList<Integer[]>());

Page 53: Man versus Machine - KTH Solvers Man versus Machine ... An algorithm is backtracking if it can go back ... The purpose of our project is to create and implement a solver that can solve

53

                 }              }              //  Add  coordinates  according  to  its  candidates              for  (Integer[]  elem:unit)  {                  row  =  elem[0];                  col  =  elem[1];                  if  (grid[row][col].getValue()  ==  0)  {                      for  (int  cand:grid[row][col].candidates)  {                          unitCandidates.get(cand).add(new  Integer[]{row,col});                      }                  }              }              for  (int  digit  =  1;  digit  <=  9;  digit++)  {                  if  (!(unitCandidates.get(digit).isEmpty())  &&  unitCandidates.get(digit).size()  <=  3)  {                      Integer[]  cellCoords  =  unitCandidates.get(digit).get(0);                      boolean  foundMatch  =  true;                      int  firstRow  =  cellCoords[0];                      int  firstCol  =  cellCoords[1];                      int  firstBoxID  =  grid[firstRow][firstCol].boxID;                      for  (int  n=1;  n<unitCandidates.get(digit).size();  n++)  {                          cellCoords  =  unitCandidates.get(digit).get(n);                          int  nextRow  =  cellCoords[0];                          int  nextCol  =  cellCoords[1];                          int  nextBoxID  =  grid[nextRow][nextCol].boxID;                          if  (firstBoxID  !=  nextBoxID)  {                              foundMatch  =  false;                          }                      }                      if  (foundMatch)  {                          //  Maybe  found  a  box  line  reduction                          boolean  changed  =  false;                          ArrayList<Integer[]>  boxUnit  =  getBox(firstBoxID);                          for  (Integer[]  boxCellCoords:boxUnit)  {                              boolean  inThisUnit  =  false;                              int  boxRow  =  boxCellCoords[0];                              int  boxCol  =  boxCellCoords[1];                              for  (Integer[]  unitCellCoords:unitCandidates.get(digit))  {                                  int  unitRow  =  unitCellCoords[0];                                  int  unitCol  =  unitCellCoords[1];                                  if  (boxRow  ==  unitRow  &&  boxCol  ==  unitCol)  {                                      inThisUnit  =  true;                                  }                              }                              if  (!(inThisUnit))  {                                  if  (grid[boxRow][boxCol].candidates.remove(digit))  {                                      changed  =  true;                                  }                              }                          }                          if  (changed)  {                              return  true;                          }                      }

Page 54: Man versus Machine - KTH Solvers Man versus Machine ... An algorithm is backtracking if it can go back ... The purpose of our project is to create and implement a solver that can solve

54

                 }              }          }      }      return  false;  }  /**    *  This  rule  find  any  pointing  pairs/triples,  defined    *  here:  http://www.sudokuwiki.org/Intersection_Removal    *    *  @return  boolean  which  is  true  if  the  rule  succeeded    *  and  the  grid  is  changed  or  false  otherwise    */  private  boolean  rulePointingSet()  {      ArrayList<ArrayList<Integer[]>>  unitCandidates  =  new  ArrayList<ArrayList<Integer[]>>(10);      int  row,  col;      //  For  every  box      for  (int  boxID  =  1;  boxID  <=  9;  boxID++)  {          unit  =  getBox(boxID);          unitCandidates.clear();          for  (int  j  =  0;  j  <=  9;  j++)  {              //  Initialize  the  arraylist  with  arraylists              unitCandidates.add(new  ArrayList<Integer[]>());          }          //  Add  coordinates  according  to  its  candidates          for  (Integer[]  elem:unit)  {              row  =  elem[0];              col  =  elem[1];              if  (grid[row][col].getValue()==0)  {                  for  (int  cand  :  grid[row][col].candidates)  {                      unitCandidates.get(cand).add(new  Integer[]{row,col});                  }              }          }          for  (int  digit  =  1;  digit  <=  9;  digit++)  {              if  (0  <  unitCandidates.get(digit).size()  &&  unitCandidates.get(digit).size()  <=  3)  {                  Integer[]  cellCoords  =  unitCandidates.get(digit).get(0);                  boolean  alignedRow  =  true;                  boolean  alignedCol  =  true;                  int  firstRow  =  cellCoords[0];                  int  firstCol  =  cellCoords[1];                  //  Check  if  truly  aligned  on  same  row  or  column                  for  (int  n  =  1;  n  <  unitCandidates.get(digit).size();  n++)  {                      cellCoords  =  unitCandidates.get(digit).get(n);                      int  nextRow  =  cellCoords[0];                      int  nextCol  =  cellCoords[1];                      if  (firstRow  !=  nextRow)  {                          alignedRow  =  false;                      }                      if  (firstCol  !=  nextCol)  {                          alignedCol  =  false;                      }                  }                  if  (alignedRow  ||  alignedCol)  {

Page 55: Man versus Machine - KTH Solvers Man versus Machine ... An algorithm is backtracking if it can go back ... The purpose of our project is to create and implement a solver that can solve

55

                     //  Found  pointing  pair                      boolean  changed  =  false;                      ArrayList<Integer[]>  fixUnit;                      if  (alignedRow)  {                          fixUnit  =  getRow(firstRow);                      }                      else  {                          fixUnit  =  getCol(firstCol);                      }                      for  (Integer[]  fixCellCoords  :  fixUnit)  {                          boolean  inThisUnit  =  false;                          row  =  fixCellCoords[0];                          col  =  fixCellCoords[1];                          int  fixBoxID  =  grid[row][col].boxID;                          for  (Integer[]  unitCellCoords:unitCandidates.get(digit))  {                              int  unitRow  =  unitCellCoords[0];                              int  unitCol  =  unitCellCoords[1];                              int  unitBoxID  =  grid[unitRow][unitCol].boxID;                              if  (fixBoxID  ==  unitBoxID)  {                                  inThisUnit  =  true;                              }                          }                          if  (!(inThisUnit))  {                              if  (grid[row][col].candidates.remove(digit))  {                                  changed  =  true;                              }                          }                      }                      if  (changed)  {                          return  true;                      }                  }              }          }      }      return  false;  } }

BruteforceSolver.java /** *  This  class  tries  to  solve  a  sudoku  using  brute-­‐force  and *  backtracking  with  the  help  of  Solver. * *  @version  1.0 *  @author  st0le *  @modified_by  Andreas  Broström  and  Simon  Johansson * *  @see  Solver */ public  class  BruteforceSolver  extends  Solver  {  public  int  missCount  =  0;  /**    *  Initializes  the  grid,  the  boxID's  and  the  boxMap.    *

Page 56: Man versus Machine - KTH Solvers Man versus Machine ... An algorithm is backtracking if it can go back ... The purpose of our project is to create and implement a solver that can solve

56

   *  @param  filename  is  the  name  of  a  sudoku  file  in  the  simple    *  sudoku  format  (.ss)    */  public  BruteforceSolver(String  filename)  {      initGrid(filename);      initBoxID();      initBoxMap();  }  /**    *  Tries  to  solve  the  sudoku  by:  Finding  the  first  0  in  the    *  grid  and  then  looking  for  possible  candidates  to  place  there.    *  If  no  0  was  found  it  breaks  here  (a  solution  has  been  found!)    *  Else  it  loops  through  the  list  of  candidates  and  tries  to  put    *  them  in  the  current  cell.  If  something  goes  wrong  the  algorithm    *  backtracks.    *    *  @return  boolean  which  is  true  if  the  sudoku  was  solved  and    *  false  otherwise.    */  public  boolean  solve()  {      int  x  =  0,  y  =  0;      boolean  found  =  false;      for  (x  =  0;  x  <  9;  x  ++)  {          for  (y  =  0;  y  <  9;  y++)  {              if  (grid[x][y].getValue()  ==  0)  {                  found  =  true;                  break;              }          }          if  (found)  break;      }      if  (!found){          return  valid();      }            boolean  digits[]  =  new  boolean[10];      for  (int  i  =  0;  i  <  9;  i++)  {          digits[grid[x][i].getValue()]  =  true;          digits[grid[i][y].getValue()]  =  true;      }      int  bx  =  3  *  (x  /  3),  by  =  3  *  (y  /  3);      for  (int  i  =  0;  i  <  3;  i++)          for  (int  j  =  0;  j  <  3;  j++)              digits[grid[bx+i][by+j].getValue()]  =  true;      for(int  i  =  1  ;  i  <=  9;  i++)  {          if(!digits[i])  {              grid[x][y].setValue(i);              if(solve())                  return  true;              grid[x][y].setValue(0);          }      }      missCount++;      return  false;

Page 57: Man versus Machine - KTH Solvers Man versus Machine ... An algorithm is backtracking if it can go back ... The purpose of our project is to create and implement a solver that can solve

57

 } }

Testing

run.sh #!/bin/bash while  getopts  s:p:t:  option do  case  "${option}"  in      s)  SOLVER=${OPTARG};;      p)  PRINT=${OPTARG};;      t)  TEST=${OPTARG};;  esac done PUZZLES=$(echo  puzzles/*.ss  |  tr  "  "  "\n") for  PUZZLE  in  $PUZZLES do  java  SudokuSolver  $PUZZLE  $SOLVER  $PRINT  $TEST done

run_both_tests.sh #!/bin/bash echo  ""  >  test/human.txt echo  ""  >  test/brute.txt for  i  in  `seq  1  100`;  do  bash  run.sh  -­‐s  brute  -­‐p  computer  -­‐t  both  >>  test/brute.txt;  done for  i  in  `seq  1  100`;  do  bash  run.sh  -­‐s  human  -­‐p  computer  -­‐t  both  >>  test/human.txt;  done

SudokuToExcel.java import  java.io.BufferedReader; import  java.io.DataInputStream; import  java.io.File; import  java.io.FileInputStream; import  java.io.InputStreamReader; import  java.util.ArrayList; import  jxl.Workbook; import  jxl.write.Label; import  jxl.write.Number; import  jxl.write.WritableSheet; import  jxl.write.WritableWorkbook; /** *  This  class  reads  from  the  textfiles  "human.txt" *  and  "brute.txt".  It  prints  results  to  an  excel *  file  called  result.xls * *  @version  1.0 *  @author  Andreas  Broström

Page 58: Man versus Machine - KTH Solvers Man versus Machine ... An algorithm is backtracking if it can go back ... The purpose of our project is to create and implement a solver that can solve

58

*  @author  Simon  Johansson */ public  class  SudokuToExcel  {  /**    *  Reads  from  file,  extracts  from  string:    *  id,  difficulty,  average  solving  time,    *  minimum  solving  time,  maximum  solving    *  time  and  number  of  misses.    *    *  Prints  results  to  result.xls    */  public  static  void  main(String[]  args)  {      try  {          ArrayList<String>  files;          ArrayList<Integer>  times;          int  col,  row;          String[]  info;          String  difficulty,  id;          String  current_id  =  "";          int  time_ms,  misses,  min_time,  max_time;          Label  label;          Number  number;          WritableWorkbook  workbook  =  Workbook.createWorkbook(new  File("result.xls"));          WritableSheet  sheet  =  workbook.createSheet("Result",  0);          for  (int  solvertype  =  0;  solvertype  <  2;  solvertype++)  {              //Identifier  |  Complexitylevel  |  Avg.  solve  time  |  min  solve  time  |  max  solve  time  |  missCount              if  (solvertype  ==  0)  {                  col  =  0;                  files  =  readFile("human");                  label  =  new  Label(0,  0,  "Human");                  sheet.addCell(label);                  label  =  new  Label(col++,  2,  "ID");                  sheet.addCell(label);                  label  =  new  Label(col++,  2,  "Complexity");                  sheet.addCell(label);                  label  =  new  Label(col++,  2,  "Average  solving  time  (ms)");                  sheet.addCell(label);                  label  =  new  Label(col++,  2,  "Minimum  solving  time  (ms)");                  sheet.addCell(label);                  label  =  new  Label(col++,  2,  "Maximum  solving  time  (ms)");                  sheet.addCell(label);                  label  =  new  Label(col++,  2,  "Number  of  misses");                  sheet.addCell(label);                  row  =  3;              }  else  {                  col  =  0;                  files  =  readFile("brute");                  label  =  new  Label(0,  64,  "Brute");                  sheet.addCell(label);                  label  =  new  Label(col++,  66,  "ID");                  sheet.addCell(label);                  label  =  new  Label(col++,  66,  "Complexity");                  sheet.addCell(label);                  label  =  new  Label(col++,  66,  "Average  solving  time  (ms)");                  sheet.addCell(label);                  label  =  new  Label(col++,  66,  "Minimum  solving  time  (ms)");

Page 59: Man versus Machine - KTH Solvers Man versus Machine ... An algorithm is backtracking if it can go back ... The purpose of our project is to create and implement a solver that can solve

59

                 sheet.addCell(label);                  label  =  new  Label(col++,  66,  "Maximum  solving  time  (ms)");                  sheet.addCell(label);                  label  =  new  Label(col++,  66,  "Number  of  misses");                  sheet.addCell(label);                  row  =  67;              }              //  Fix  first  loop              times  =  new  ArrayList<Integer>();              info  =  files.get(0).split("\\$");              current_id  =  info[0];              time_ms  =  Integer.parseInt(info[2]);              max_time  =  time_ms;              min_time  =  time_ms;              times.add(max_time);              difficulty  =  info[1];              misses  =  Integer.parseInt(info[3]);              for  (String  file  :  files)  {                  info  =  file.split("\\$");                  id  =  info[0];                  if  (current_id.equalsIgnoreCase(id))  {                      if  (time_ms  >  max_time)  {                          max_time  =  time_ms;                      }  else  if  (time_ms  <  min_time)  {                          min_time  =  time_ms;                      }                      times.add(time_ms);                  }  else  {                      //Identifier  |  Complexitylevel  |  Avg.  solve  time  |                      //  min  solve  time  |  max  solve  time  |  missCount                      col  =  0;                      label  =  new  Label(col++,  row,  current_id);                      sheet.addCell(label);                      label  =  new  Label(col++,  row,  difficulty);                      sheet.addCell(label);                      number  =  new  Number(col++,  row,  Average(times));                      sheet.addCell(number);                      number  =  new  Number(col++,  row,  min_time);                      sheet.addCell(number);                      number  =  new  Number(col++,  row,  max_time);                      sheet.addCell(number);                      number  =  new  Number(col++,  row,  misses);                      sheet.addCell(number);                      row++;                      //  update  new  max  and  min                      times.clear();                      max_time  =  time_ms;                      min_time  =  time_ms;                      times.add(time_ms);                      current_id  =  id;                  }                  difficulty  =  info[1];                  time_ms  =  Integer.parseInt(info[2]);

Page 60: Man versus Machine - KTH Solvers Man versus Machine ... An algorithm is backtracking if it can go back ... The purpose of our project is to create and implement a solver that can solve

60

                 misses  =  Integer.parseInt(info[3]);              }              //  small  fix  to  include  the  last  sudokus  stats              col  =  0;              label  =  new  Label(col++,  row,  current_id);              sheet.addCell(label);              label  =  new  Label(col++,  row,  difficulty);              sheet.addCell(label);              number  =  new  Number(col++,  row,  Average(times));              sheet.addCell(number);              number  =  new  Number(col++,  row,  min_time);              sheet.addCell(number);              number  =  new  Number(col++,  row,  max_time);              sheet.addCell(number);              number  =  new  Number(col++,  row,  misses);              sheet.addCell(number);          }          workbook.write();          workbook.close();      }  catch  (Exception  e)  {          System.err.println("ERROR:\n"+e.getMessage());          e.printStackTrace();      }  }  private  static  float  Average(ArrayList<Integer>  times)  {      float  sum  =  0;      for  (int  time  :  times)  {          sum  +=  time;      }      return  sum/times.size();  }    /**    *  Reads  a  file  to  an  arraylist  and  returns    *  (row  for  row).    *    *  @param  filename  name  of  the  file  to  read    *  @return  an  arraylist  with  all  rows  in  the    *  file  as  elements.    */  public  static  ArrayList<String>  readFile(String  filename)  {      ArrayList<String>  files  =  new  ArrayList<String>();      try{          //  Open  the  file  that  is  the  first          //  command  line  parameter          FileInputStream  fstream  =  new  FileInputStream("test/"  +  filename  +  ".txt");          //  Get  the  object  of  DataInputStream          DataInputStream  in  =  new  DataInputStream(fstream);          BufferedReader  br  =  new  BufferedReader(new  InputStreamReader(in));          String  strLine;          //Read  File  Line  By  Line          while  ((strLine  =  br.readLine())  !=  null)      {              //  Print  the  content  on  the  console              files.add(strLine);          }

Page 61: Man versus Machine - KTH Solvers Man versus Machine ... An algorithm is backtracking if it can go back ... The purpose of our project is to create and implement a solver that can solve

61

         //Close  the  input  stream          in.close();      }catch  (Exception  e){//Catch  exception  if  any          System.err.println("Error:  "  +  e.getMessage());      }      return  files;  } }

Page 62: Man versus Machine - KTH Solvers Man versus Machine ... An algorithm is backtracking if it can go back ... The purpose of our project is to create and implement a solver that can solve

62

Appendix C - Sudoku examples

Ne.se 0903 LÄTT SUDOKU

easy[0903].ss ..8|..5|... 2.4|.1.|... ..1|29.|..3 -­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐ ...|452|67. .5.|.7.|9.. ...|...|... -­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐ .1.|.68|5.. 3..|...|... ...|..3|4..

[12] 1039 SUDOKU MEDIUM

medium[1039].ss ...|.62|... 34.|...|6.. ...|.5.|.9. -­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐ ..2|..1|94. ...|...|.6. ..6|.38|15. -­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐ ...|..7|.8. .5.|9..|... 2..|5..|.39

[12]

Page 63: Man versus Machine - KTH Solvers Man versus Machine ... An algorithm is backtracking if it can go back ... The purpose of our project is to create and implement a solver that can solve

63

Harder puzzles Puzzle001 Puzzle001.ss 2..|.57|8.3 7..|...|4.. .43|...|... -­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐ .7.|54.|... 32.|876|.49 ...|.13|.5. -­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐ ...|...|61. ..1|...|..4 4.7|36.|..2 [13] Weekly unsolvable unsolvable.ss 52.|...|6.. 3.7|..8|... ...|.7.|8.. -­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐ 9..|..1|..5 ...|.3.|... 4..|9..|..2 -­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐ ..1|.2.|... ...|6..|4.1 ..9|...|.57 [5]