CS 206 - Introduction to Data Structures
Recursion to solve Sudoku
Due April 11 prior to 11:59:59 pm EDT
Sudoku is the main and default assignment. If, however, you just do not want to deal with sudoku, there is an alternative which is described at the end of the assignment. I urge you to do the sudoku assignment, but both are worth equal credit.
Sudoku is a game / logic puzzle with a simple set of rules. This assignment is to write a recursive sudoku solver. If you are unfamiliar with sudoku you should learn the rules and solve a couple of puzzles before starting. Puzzles are available on sudoku.com. I prefer the interface on the New York Times website.
A recursive backtracking Sudoku solver
There are many approaches to solving Sudoku puzzles. I describe one here, you need not follow my exact approach. Here is pseudocode for my approach:
//at its simplest this could be just a 2d array (specifically 9x9) of int
boolean isSolved(Puzzle p)
return true if the puzzle is completely solved false otherwise
boolean isSolvable(Puzzle p)
return true if the puzzle still might be solvalble, false otherwise
List legalmovesat(Puzzle p, int xloc, int yloc)
return the list of numbers the can be legally put into the position given the board
Puzzle copy(Puzzle p)
return a new instance of puzzle that is an exact copy of the provided puzzle. Importantly, making a change in the copy should have no effect on the original.
Puzzle solve(Puzzle p, int xloc, int yloc)
if not isSolvable(p)
if (p(xloc, yloc) != 0)
return solve(p, xloc, yloc+1)
legalmoves = legalmovesat(p, xloc, yloc)
foreach legalmove : legalmoves
set p(xloc, yloc) to legalmove
np = solve(copy(p), xloc, yloc+1)
Generally, this approach starts in one corner of the puzzle and fills in a legal guess, then recursively goes to the next square, backtracking when it gets to points in which the puzzle cannot be solved. Note that while this approach can certainly be used by humans to solve sudoku puzzles, it is not the way that any reasonable person would.
You are free to implement other, more human-like solution approaches. Whatever your approach, your solution must use recursion with backtracking.
Suggestions for coding
Please note that these are only suggestions. You can approach the problem in any way. That said, I would suggest starting as follows:
- Write the system for reading in the board first. Use iteration (for and while loops).
- Write the copy method for puzzles. This could be written later but it should be easy so get it done. Use iteration.
- Consider rewriting the read and copy methods to be purely recursive. (This could be done much later, but recursion is fun, so why not do it now?) (See the requirements section below)
- Write the "legalmovesat" method. This should be, by far the most complex piece of code you write for this assignment. Use iteration. Make sure that this is perfectly correct before doing anything else. If it is not prefect, the rest of the program will fail. Consider breaking down the problem as follows: first create a utility function boolean isLegal(int number, int row, int column)Within that utility function first check if the number is legal "vertically". Then check if it is legal horizontally, then finally check it it is legal within inits 3x3 group. I suggest writing bothin of these functions so they can be testable directly. For instance, in a main function, read in a board. Then call isLegal on some number and some position. You should be able to check that the answer to this is correct by hand. Once you have isLegal written, then legalMovesAt is just a loop from 1 to 9 calling "is legal move". Again, check this by directly calling it from your main function.
- Write the isSolvable method. This can be written by just making calls to legalmovesat from every square that is not filled in. If you find a square for which legalmovesat returns a zero length list, then the puzzle is not solvable. (There are many other ways to write is solvable, this is probably the easiest.) Again, use iteration.
- Write the isSolved. This should be really easy. just check is every square is filled. Again, use iteration.
- Write solve
- When the solver works 100% of the time, consider going back through you code and remove or at least recuce the use of, iteration.
Zeros (0) in this file represent blanks (unknowns) in the puzzle, they are the spaces your program needs to fill in. In the directory /home/gtowell/Public/206/a7/ are several puzzles (*.csv) of differing levels of difficulty. All are solvable. All have solutions in files (*.csv.soln).
- You may use iteration to read the csv file as in the pseudocode above. You should not use iteration otherwise. As an incentive to avoid other iteration, each use of iteration will be penalized on a sliding scale. Other than as the use of loops to read in the csv file gour have 5 free uses of iteration. After that, the sixth use, -1 point; the seventh use -2 points; etc. This count is applied at the code, not at runtime. So, if you have 9 uses of iteration in your code, then you loose 10 points (1+2+3+4). To avoid loosing points you may do some pretty silly seeming recursions. So be it.
- When your program has reached a solution, it should print that solution.
- Use an appropriate set of data structures and classes. You may use data structure implementations provided by Java or those discussed in class. (An appropriate data structure for the sudoku board might be as simple as a 2d array.)
- Command line input. The puzzle file must be given (or givable) on the command line. For instance, if the main method is the class Solver, then
java Solver puzzle.csv
- Exception handling. Your program should not die; under any circumstances. It should gracefully handle at least the following issues:
The only exception you need not handle is a stack overflow. You really should not get a stack overflow, and you cannot handle it gracefully anyway.
- What happens when the puzzle file is missing
- What happens when the puzzle file is corrupt.
From the Goodrich textbook, do the following problems:
- page 222, C5.19
- page 222, C5.20
- page 222, C5.21
- page 222, C5.18. Use only recursion for this. Do NOT use the stack code from the previous assignment.
- Write a recursive function that will allow you to answer the question What is the largest number of recursive function calls that Java allows? In your Readme, be sure to explicitly give an answer to this question. Also, does java stop recusion at the same place every machine? Test this on your personal laptop and the machines in the CS lab. Report the results of this test in your readme.
- Recursive functions are usually a single function which calls itself. Write a "recursive loop" of 3 methods such that the first calls the second, the second calls the third and the third calls the first. The number of times you go arround this loop should be controlled by a parameter that is passed arround the loop. The methods in the loop can be quite short (several could be as short as one line of code).
Your program will be graded based on how it runs on the
department’s Linux server, not how it runs on your computer.
The submission should include the following items:
- README: This file should follow the format of this sample README (https://cs.brynmawr.edu/cs206/README.txt)
- Within the README file, include a brief (max 1 paragraph) reflection on what went well and/or poorly and why
- Source files: Every .java file used in the final version of every part of your project (including the imported files)
- Unique Data files used: If any
The following steps for submission assume that you created a project named AssignmentN in the directory /home/YOU/cs206/
- For this assignment N=7
- Put the README file into the project directory
- Go to the directory /home/YOU/cs206
- Enter /home/gtowell/bin/submit -c 206 -p N -d AssignmentN
For more on using the submit script click here