Difference between revisions of "N-Queens/Sudoku Assignment"
Line 50: | Line 50: | ||
==Visualization== | ==Visualization== | ||
===N-Queens=== | ===N-Queens=== | ||
− | {{Viz| | + | {{Viz|NQueensVizApp|nqueens.viz.solution}} |
[[File:NQueensViz.png]] | [[File:NQueensViz.png]] |
Revision as of 21:14, 16 March 2018
Contents
Motivation
Not everything in the world should be divided and conquered. Backtracking is a powerful technique which can be readily parallelized. We will gain experience with backtracking by solving the N-Queens problem and Sudoku in parallel.
N-Queens in particular can be used to explain the call stack as the chessboard *IS* the call stack. Whoa.
Further, by employing constraint propagation and search we can dramatically improve performance.
Background
The n-queens problem is a fundamental coding puzzle which asks: how can N queens be placed on an NxN chessboard so that they cannot attack each other? In chess, a queen can move horizontally, vertically, and diagonally across the board. Thus, to solve the n-queens problem, we must effectively figure out how to place the queens in such a way that no two of them occupy the same row, column, or diagonal.
We will be using a similar algorithm to solve a Sudoku puzzle. A Sudoku puzzle is composed of a 9-by-9 grid of squares. This grid is also divided into 9 large boxes, each of which is a 3-by-3 of the smaller squares. In a completed puzzle, each of the smaller squares contains a single number from 1 to 9 (inclusive). However, if a square contains a given number, that same number cannot be anywhere else in the same row, column, or box. Thus, for Sudoku, we are given an incomplete board and must fill in the remaining squares while meeting these requirements. For more explanation, take a look at Peter Norvig's essay about solving Sudoku.
In this assignment, you will implement solutions to both the n-queens and Sudoku problems.
Where to Start
All of the classes you will need to implement can be found under nqueens.assignment
or sudoku.assignment
. The nqueens.core
and sudoku.core
packages are utility and building block classes we created for you and the viz source folder contains visualization apps that might help you understand your code from a visual standpoint. Take a look at these classes to get a better understanding of how to use them for your assignment.
N-Queens
There are three classes you will need to modify: DefaultImmutableQueenLocations.java
, SequentialNQueens.java
, and ParallelNQueens.java
. Start with QueenLocations
and then we recommend moving on to the sequential solution before the parallel one. Take a look at the javadocs to see what everything does and what you will need to implement.
A couple of notes and common issues:
- There is an outdated comment in
DefaultImmutableQueenLocations
. There is noNQueensUtils
class; you should look atAbstractQueenLocations
instead. - As
ImmutableQueenLocations
is immutable, you will need to create a new instance of the object whenever you move on from one row to the next. This is wherecreateNext
comes in, along with the private constructor of this class. - The
isNextRowThreatFree
method can easily be completed with a method inAbstractQueenLocations
. Refer to that for help. - The sequential solution uses
MutableQueenLocations
while the parallel solution uses your implementation ofImmutableQueenLocations
. Be careful to use the correctQueenLocations
implementation. - As the name suggests,
placeQueenInRow
will go through the columns of the given row to check if a queen can fit in that location. If it can, it will set that value inMutableQueenLocations
. If the examined row is that last row of the board, you have found one valid solution to the n-queens problem. Update the correct parameter accordingly. Otherwise, recurse and keep going until you reach the last row. - For the parallel implementation of
placeQueenInRow
, we are using the "one-finish" pattern. Do not callfinish
in the recursive method. - The syntax for instantiating a
FinishAccumulator
ofInteger
is:FinishAccumulator<Integer> acc = newIntegerFinishAccumulator(NumberReductionOperator.SUM);
- The syntax for using a
FinishAccumulator
is:finish(register(acc), () -> { //body });
Sudoku
There are three classes you will need to modify: DefaultImmutableSudokuPuzzle.java
, SquareSearchAlgorithms.java
, and ParallelSudoku.java
(we would recommend moving through these classes in this order). Take a look at the javadocs to see what everything does and what you will need to implement.
A couple of notes and common issues:
- As the name suggests,
ImmutableSudokuPuzzle
is immutable, and you will need to create a new instance of the object whenever you move on from one square to the next. This is analogous to the immutable n-queens board. - The
getOptions
method inSudokuPuzzle
should find what value the given square could represent by searching the value of its peers (same row, same column, and same box). Starting withALL_OPTIONS
, the number of options should be removed depending on the peer. If the square is already filled in, it should simply return the correct value. - If you have two Lists,
a
andb
, and you seta = b
, then any changes you make toa
will also be made tob
. Both variables reference the same objects; they are not copies. - You will need to implement
getValue
. Look to the instances fields for what will be useful here. - Your solvers should be able to handle two different approaches to picking the next square in the puzzle to examine: row major and fewest options first. Row major just means going through the puzzle row by row, while fewest options first means solving the puzzle in the order of which squares has the fewest options.
- The row major approach is already done for you
- For fewest options first, go through every square (you can do this by calling
Square.values()
) and see how many options are available for each square. Return the square with the minimal number of options. However, check to make sure the puzzle is not already completed or that you are returning already filled squares.
- Just like n-queens, your
solveKernel
is the recursive method that will be called in the solve method. Again, watch where you put yourfinish
. - In your
solveKernel
method, you should use your desired search algorithm (row major or fewest options first) to select which square you will fill. After selecting a square, you should recursively call the kernel to check every viable option in the context of the puzzle. If there are no more unfilled squares, you should set the value of the solution to the finished puzzle and exit out of the recursion.
Testing Your Solution
Visualization
N-Queens
class: | NQueensVizApp.java | VIZ |
package: | nqueens.viz.solution | |
source folder: | student/src//java |
Sudoku
class: | FxSudokuSolutionApp.java | VIZ |
package: | sudoku.viz.solution | |
source folder: | student/src//java |
Correctness
There is a top-level test suite comprised of sub test suites which can be invoked separately when you want to focus on one part of the assignment.
top level
class: | BacktrackTestSuite.java | |
package: | backtrack.lab | |
source folder: | testing/src/test/java |
sub
class: | NQueensTestSuite.java | |
package: | nqueens.lab | |
source folder: | testing/src/test/java |
class: | SudokuTestSuite.java | |
package: | sudoku.lab | |
source folder: | testing/src/test/java |
Rubric
As always, please make sure to cite your work appropriately.
Total points: 100
N-Queens subtotal: 40
- Correct ImmutableQueenLocations (10)
- Correct sequential implementation (10)
- Correct parallel implementation (20)
Sudoku subtotal: 50
- Correct ImmutableSudokuPuzzle (10)
- Correct SquareSearchAlgorithm (15)
- Correct ParallelSudoku (25)
Whole project:
- Clarity and efficiency (10)