|
CMSC 201 Programming Project
Four
The Knight's
Tour
Out: Tuesday 11/7/06 Due Date: Sunday 11/19/06, before midnight
The design document for this project, design4.txt,
is due: Before Midnight, Sunday 11/12/06
|
The Objective
The purpose of this assignment is to give you practice with arrays,
command-line arguments, file handling, and recursion.
The Background
A chess board is an 8x8 grid of squares. A knight
in chess moves around the board according to one of the following rules:
- two squares in the x-direction and one square in the y-direction
- one square in the x-direction and two squares in the y-direction
A knight's
tour starts by convention in the upper-left square (position [0,0]), and
moves around the board using legal knight moves, such that every square is
visited exactly once. A closed knight's tour returns to the
starting square. Here's a
link with more information about the Knight's Tour problem. If you really
want to know more about the nuts and bolts of the mathematics behind the
Knight's Tour (and similar math puzzles), try the MathWorld page on
the subject.
The Task
Your task is to write a program that will find a legal knight's
tour (not necessarily a closed knight's tour) for a given board size, assuming
that one exists. If no solution is found, then the program should print a
message indicating that no legal solution exists.
Your program should use
recursion to implement a backtracking search solution to this problem.
Backtracking search works by starting from the initial position [0,0] and
generating a list of successor moves. These moves are tried, one at
a time. Each move generates a new position, which then leads to another
set of successor moves. This process continues until either (a) a solution
is found (the board has been entirely filled), or (b) a dead end is reached.
Backtracking refers to the behavior of the program if a dead end is
encountered (i.e., if the knight reaches a position where no legal moves
remain--because all reachable squares have already been visited) before a
solution is found. In this case, the recursive function will "bottom out" and
should return a failure signal to the calling function. The recursion will
"unwind" in this way to a point on the board where there is another legal move
to try. If recursion "unwinds" all the way to the starting point, and no
legal moves remain, then no solution exists.
The size of the board will
be specified by two command-line arguments, as described below. The program
should work for any positive integer-valued board dimensions. Here is
a program trace showing how recursive backtracking search would work for a small
3x3 board. Note that the program records an unvisited board space with a
"0" at that position on the board, and a visited space with the order in which
it was visited. The program starts at [0,0], indicating that first square
by recording a "1" in array position [0,0]. It then tries the first move it
finds, which is to move the knight to [1,2] (recorded as "2"). This puts
the program into a series of "single-choice" boards, where it only has one
possible move. After 7 moves, at the 8th level of recursion, one square
(the center square) is still empty, but it can't move there. It backtracks
to the last move where it had more than one choice, which was the very first
move, and tries the other choice, [2,1]. This leads to the same impasse:
after 7 moves, the center square is empty, but the knight can't reach it.
At this point, there are no more moves to try, and the program gives
up.
% a.out
[0] trying 0, 0
[1] trying 1,
2
[2] trying 2, 0
[3] trying 0,
1
[4] trying 2, 2
[5] trying 1, 0
[6] trying 0,
2
[7] trying 2, 1
Here's what the board looks like after the first seven moves:
There are no moves
remaining, but the tour is incomplete. At this point, the program backtracks to
the very first move (which was the only move where there was more than one
choice). Here's what the board looks like after backtracking to the first
move:
[1] trying 2,
1
[2] trying 0, 2
[3] trying 1,
0
[4] trying 2, 2
[5] trying 0, 1
[6] trying 2,
0
[7] trying 1,
2
Here's what the board looks like after trying the final seven
moves, just before it backtracks all the way to the start, and discovers there
are no moves remaining:
No solution found for 3 rows
and 3 columns!
Program Requirements
- Your program must take three command-line arguments that specify the
dimensions of the board (rows and columns) and an output file, in the
following format:
a.out <ROWS>
<COLS> <OUTPUTFILE>
For example,
a.out 3 3 tour3x3.out
would look for
a knight's tour on a 3-by-3 board, and put the output of the program into a
file called tour3x3.out.
- Your program must be implemented recursively, as discussed
above.
- Your program must use this function, which we have provided, to
generate the sequence of moves to consider:
int FindNextMoves (int **board, int **nextMoves, int rows, int cols, int row,
int col)
You should copy the files knightmoves.o and
knightmoves.h from the directory
/afs/umbc.edu/users/s/b/sbogar1/pub. This function takes the current
board and a second array, the dimensions of these two arrays (rows
and cols), and the current row and column of the knight. (Note
that this function assumes the representation described previously, that the
board has a "0" in each unvisited square, and a sequence number (greater than
0) in visited squares.) FindNextMoves fills in the second array with the
possible next moves, by placing the value TRUE in the array at locations
where the knight can legally move next, and FALSE where the knight
cannot move. You must consider the moves in this array in
row-major order. That is, you should look through the array, from
row 0 through row ROWS-1, and within each row from column
0 through column COLS-1, to see what moves are
possible. You must try the moves in that order. If you do not,
you may find a valid solution that is not the "correct" solution for the
project, and you will not receive full credit.
- Your program must output the first solution it finds as a formatted ROWSxCOLS grid of numbers,
representing the order of moves that the knight makes. Since the knight
always starts at [0,0], the upper left corner will be designated as
location 1. The other grid locations should contain the move
number when the knight visits that location. If no solution is found, a
failure message should be printed. The solution (or failure message) should be
printed into the output file specified on the command line. See the
sample run.
- After printing the board (or a failure message), your program must output
(to the output file) the following information. See the sample run.
- The number of successor moves generated during search.
This is the total number of all successor moves that
were ever generated by the FindNextMoves function.
- The number of positions actually visited (tested) during search.
This is the number of successor moves that actually generated a
recursive call to the search function.
Neither of these counts
should include the initial knight position [0,0], since that position
is not a successor to any other position.
- You must use separate compilation for this project. You MUST have a file
called proj4.c that contains main(), but you may have as many .c and .h
files as you wish, with a minimum of 3 files.
- For extra credit, you may provide a command line option "-opt" which
attempts to find the "optimal tour"; that is, the one that requires the fewest
moves to be tested in finding the solution. (Note that you don't need to
actually find the optimal tour; you just need to implement a solution that is
more likely to find the optimal tour than the default behavior of the program.
You must also provide an explanation of why you think your algorithm
will work.)
This extra credit program should be invoked as follows:
% a.out
-opt
Note that the only difference between
the extra-credit program and the "normal" version should be the order in which
successor moves are tried. If you wish to receive extra credit for this
option, you must indicate in your proj4.c file header that you have
implemented this option, along with a short summary of how your program finds
the optimal tour. (Be warned: This is quite a bit harder than
the basic problem, so be sure that you have that completely working before you
start working on the extra credit.)
Program Hints
- Be sure to allocate space for the nextMoves array that you will pass to
the FindNextMoves function, and to free the array when you no longer need that
information.
- You may want to use the functions Get2DSpace and
Free2DSpace from the Lecture 16 notes to allocate and free up space
for the board and the nextMoves array.
- The knightmoves.o file contains two other functions you may find
useful. LegalIndices() takes a current row and column, and the
dimensions (rows and columns) of the board. It returns TRUE if the
current row and column are legal array indices for the board, and
FALSE otherwise. ClearArray takes a two-dimensional array
(int **) and its dimensions (rows and cols), and sets all of the
array's elements to zero. The function prototypes for these functions are
given in knightmoves.h.
Sample Run
% a.out
Usage: a.out ROWS COLS OUTPUTFILE
% a.out 3 3 3x3soln.txt
% cat 3x3soln.txt
No solution found for 3 rows and 3 columns!
Number of moves generated: 14
Number of moves tried: 14
% a.out 3 7 3x7soln.txt
% cat 3x7soln.txt
1 4 7 18 15 10 13
6 19 2 9 12 21 16
3 8 5 20 17 14 11
Number of moves generated: 3825
Number of moves tried: 3818
% a.out 6 6 6x6soln.txt
% cat 6x6soln.txt
1 8 5 20 3 10
6 19 2 9 34 21
15 28 7 4 11 32
18 25 16 33 22 35
29 14 27 24 31 12
26 17 30 13 36 23
Number of moves generated: 183667
Number of moves tried: 183634
%
Submitting the Program
To submit your program, type the following command at the Unix prompt
submit cs201 Proj4 followed by the .c and .h files necessary for
compilation
To verify that your project was submitted, you can execute the following
command at the Unix prompt. It will show all files that you submitted in a
format similar to the Unix 'ls' command.
submitls cs201 Proj4
Acknowledgements
Thanks to Matt Gaston for providing an earlier
version of this assignment. Knights Tour animation borrowed from Dan
Thomasson.
CSEE
| 201 | 201 F'06 | lectures | news | help
Wednesday, 25-Oct-2006 10:40:39 EDT