Chess
In this project, you will implement a game of chess. The user-interface has
been provided for you. What you need to do is provide the back-end
functionality that allows the user to move the chess pieces, keep a record of
all the moves for a game, allow users to undo moves and save and load games.
Overview of Chess
For more details about the game of chess, try the following links:
Functional Specification
Chess is based on some fairly simple rules. Each side has 16 pieces of 6
different types: Pawn, Rook, Knight, Bishop, Queen and King. The game is played
on a board with 64 squares and the object of the game is to capture the other
team's King. Each of the 6 types of piece have different rules for moving
around the board, and can take pieces from the other team under certain
conditions. Your job is to ensure that the two players playing your game of
chess get to take turns (white always goes first), and cannot make a move that
is invalid.
In order to ensure that only valid moves are made, you should allow the player
whose turn it is to click on one of their own pieces on the board. This event
should trigger your program to highlight all the valid moves for the piece that
was selected. If the user then clicks on one of the highlighted squares, the
piece will move. If the user clicks anywhere other than a highlighted square,
the selection of the piece will be cancelled and no move will be made.
Only one chess piece can occupy a single square. Valid moves for each of the
pieces are shown below:
-
Pawn: one their first move, pawns may move either one or two squares
directly ahead of them (unless blocked by any other piece). After their first
move, they may only move one square directly ahead of them per turn. They may
only take pieces of the other color when the opposing piece is in a square
diagonally in front of them. (Pawn
moves from Chess is Fun.) You will need to implement some functionality
to allow a pawn to change to another piece if it reaches the other side of the
board. You are not required to implement the "En Passant" rule for Pawns
(although you are welcome to if you so desire).
-
Rook: Rooks may move horizontally or vertically as many squares as
possible. The range of their movement is only terminated by the edge of the
board or another piece. Rooks may take the first opposing piece that blocks
their movement in any vertical or horizontal direction. (Rook
moves from Chess is Fun.)
-
Knight: Knights always move in the shape of the letter "L". This means
that they move two squares forward and one to the left or right in any
direction. The Knight is the only piece that can jump over other pieces. (Knight
moves from Chess is Fun.)
-
Bishop: The Bishop's movement is similar to the Rook's except that the
Bishop can move diagonally in any direction. (Bishop
moves from Chess is Fun.)
-
Queen: The Queen's movement is a combination of the Rook's and the
Bishop's movement. This means that the Queen can move both horizontally,
vertically and diagonally in any direction. (Queen
moves from Chess is Fun.)
-
King: The King can only move a single square in any direction. The King
cannot move into a 'check' position (a square in which he could be taken by an
opposing piece). (King
moves from Chess is Fun.) You are not required to implement "castling"
for the King and Rook (but again, you may if you wish).
At the beginning of the game, each piece has a set position on the board. Each
time a piece moves, you need to add the move to the history of the game. Any
move may be undone to restore the position of the board before the move took
place. Thus, it would be possible to repeatedly click Undo until the chess
board was reset to its original position.
Check
Your project is required to display a message any time one of the players is in
check. Also, the project should not allow any move that will leave the King in
a check position. Some specific examples that you will need to consider are:
|
In the example to the left, the Rook (R)
has the King (K) in a check position. The King should not be allowed to
move to the square marked in green since the King would still be in check.
|
|
In the example to the left, the King (K) in a position to
take the Pawn (P). However, doing so will
put the King in check because of the Bishop (B).
Thus, the King should not be allowed to make this move.
|
|
In the example to the left, the King (K) is in check
because of the Queen (Q). The King has
several different choices on which square it can move to in order to get out of
check. However, the only valid move for the Rook (R) is to move to the
square marked in green because this will ensure that the King is no longer in
check.
|
Checkmate and Stalemate
Checkmate occurs when the moving player's King is in check, and there
are no valid moves that can be used to remove the king from check. Stalemate
occurs when the moving player's King is not in check, but there are no valid
moves that would not put the king in check. In either case (checkmate or
stalemate), the game is over. In the case of checkmate, the player whose king
is in checkmate loses the game. In the case of stalemate, neither player wins
and the game is declared a draw.
Your program is required to detect when checkmate or stalemate has occurred, in
which case your program should print out an appropriate message and not allow
further moves to be taken. However, even when checkmate or stalemate is
reached, the undo function should still work.
New Game
The user may request a "new game", in which case the current game should be
discarded and the program re-initialized to its original state.
Loading and Saving Games
The user may also save and load a previous game. The user will provide the
filename to be loaded or saved to in a textbox and will then click either the
save or load button. If a game is being loaded, the current game will be
discarded in favour of the new game. If a game is saved, both the current board
position and the history of the game need to be saved. This will be achieved
using the XML file format. Details of the XML file format can be found
here.
The User Interface
The user interface for the chess game has already been written for you. Details
of how to integrate your code with the provided user interface code are
provided here.
Memory Management Errors
Your program must not contain memory management errors. You should use the
Linux tool named valgrind to check your program for
memory management errors. valgrind can detect many
kinds of memory-related bugs, including memory leaks, reading from invalid
memory locations, and writing to invalid memory locations. The TAs will use
valgrind
to check your program for memory management errors when you pass off.
To use valgrind, you should first compile and link
your program using the -g flag, which tells the
compiler and linker to include debugging information in your executable. After
doing that, valgrind may be executed as follows:
valgrind -tool=memcheck --leak-check=yes --show-reachable=yes executable param1 param2 ...
valgrind will print out messages describing all
memory management errors that it detects in your program. This is a valuable
debugging tool. After your program completes, valgrind
will print out information about any heap memory that was not deallocated
before the program terminated. You are required to remove all memory leaks
before passing off. You are not responsible for memory leaks in the
standard C++ library or other libraries on which your program depends. For
example, the C++ string class allocates memory on the heap which it never
deallocates. valgrind will report this as a memory
leak, but you are not responsible for it. You are only responsible for memory
allocated directly by your program. valgrind will
also print out Invalid read and Invalid
write messages whenever your program reads from or writes to an
invalid memory location. You are required to remove all invalid reads and
writes before passing off.
Please note that running your program with valgrind
will cause your program run much slower than usual. Therefore, you might not
want to always run your program with valgrind.
Rather, run valgrind periodically during your
program's development to find and remove memory errors. It is not recommended
that you wait until your program is completely done before running
valgrind.
Exception Handling
Your program must properly handle C++ exceptions. This means that your program
must not abnormally terminate due to an unhandled exception.
Polymorphism
You are required to use polymorphism (i.e., virtual functions) in your
implementation of this program. Specifically, you must use polymorphism to
distinguish between the different kinds of chess pieces. This will probably
involve creating a base class (or interface) that defines virtual methods for
all of the operations on a chess piece, and then creating subclasses of the
base class for each type of piece. This will allow your program to easily deal
with the differences between the pieces, and also make it easy to add new kinds
of pieces.
Design Documentation
The first step in developing a larger program like Chess is to spend some time
understanding the problem that is to be solved. Once you understand the
problem, start to design the classes that you will need by visualizing the
operation of the program in your mind, and creating classes that perform each
of the functions required by the program. For each class that you create, you
should document what responsibilities the class has, and how it interacts with
other classes to perform its responsibilities. This exercise will help you
figure out what classes you need to write, and how those classes work together
to produce a working program. Doing this type of design work before you start
coding will save you time because it will help you avoid spending effort on
dead-end ideas that don't work.
Once you've thought through your design the best that you can without writing
any code, you should make a first attempt at implementing your design. As your
implementation progresses, you will probably find that your design was
incomplete or faulty in some respects. This is to be expected because some
insights only come from actually implementing a design. As you proceed, make
necessary changes to your design, and incorporate them into your code.
To encourage you to follow this type of design process, about a third of the
way through the project you will be asked to document and turn in your Chess
design. Your design document must include three things:
-
A DETAILED description of the data structures that you will use to store
the program's data. Describe in detail what data needs to be stored, and how
you intend to store it (e.g., binary trees, hash tables, queues, arrays,
linked-lists, etc.). Also explain why you chose the data structures that you
did.
-
For each class in your design, document the following:
-
The name and purpose of the class
-
The name and purpose of each data member
-
The name and purpose of each method. For each method, document each of its
parameters and its return value.
The easiest way to document this information is to create a commented header
file (.h file) for each of your classes using the style described in the Code
Evaluation section. Since you will have to create commented header files
anyway, using this format for your design document will help you get a head
start on your code.
-
A DETAILED description of the top-level algoirthms that implement
each of the use cases below:
-
New Game
-
Move Piece
-
Undo Move
-
Save Game
-
Load Game
The best way to document these algorithms is to actually write the code for
them in terms of the specific classes and methods in your design. This
will help you see how your classes will work together at runtime to accomplish
each task.
Submit a hard-copy printout of your design document to the TAs before midnight
on the due date. Please make sure that your name is clearly visible on the
front of your design document. Design documents may not be submitted by
email.
Standard Template Library (STL)
You may use the STL for this project.
Unit Tests
Every class/struct in your program must have a public method with the following
signature
static bool Test(ostream & os);
that will automatically test the class/struct and verify that it works
correctly. The Test method on a class/struct should create one or more
instances of the class/struct, call methods on those objects, and automatically
check that the results returned by the methods are correct. If all tests
succeed, Test should return true. If one or more tests fail, Test should return
false. For each test that fails, an informative error message that describes
the test that failed should be written to the passed-in output stream. This
will tell you which tests failed so that you can fix the problems.
You must also write a test driver program that runs all of your automated test
cases. This program will be very simple, consisting only of a main function
that calls all of the Test methods on your classes/structs. Whenever you make a
change to your classes/structs, you can recompile your test program and run it
to make sure that the new code works and that it didn't break anything that was
already there.
The file UnitTest.h in the CS240 Utilities contains code that is useful for
creating automated test cases.
Shared Library
As part of Project I you created a static library containing the CS240 Utility
classes. For this project you will be required to create a shared library
containing the chess GUI classes, and to use this library to link and
run your program. Specifically, the following files must be packaged as a
shared library:
-
chessgui.o
-
buttonbox.o
-
inputbox.o
-
messagebox.o
Since you will need to change chess.cpp in order to integrate your code with
the GUI, you need not put chess.o in your shared library, although you can if
you want to.
In class we will teach you how to create shared libraries using
g++, and how to link them into a program. When you pass off your
program, the TA will ask you to un-tar your source code and build your program.
Creating and linking the shared library will be part of the build process. Of
course, you will also be asked to demonstrate that your program works.
Make File Automation
You will be required to automate the compilation and testing of your Chess
program using a make file. If you wish, you may start with the
make file that is provided with the user interface files, and enhance it
to perform the functions described below. Your make file will support the
following functions:
-
build the shared library containing the chess GUI classes
-
build the executable Chess program
-
run your automated unit test cases
-
remove all of the files created by the build process
Your make file must recognize the following targets:
Target |
Example |
Meaning |
lib |
$ make lib |
Compile the chess GUI classes, and package them in a shared library named
libchessgui.so.
|
bin |
$ make bin |
Compile and link your Chess program.
This target depends on the lib target, and should perform that target first.
|
test |
$ make test |
Compile and run your automated test program.
The test program should contain a main function that simply calls the Test
methods on all of your classes. If all tests succeed, the program should print
out a message indicating success. If one or more tests fail, the program should
print out a message indicating failure, and also print out a message describing
each test that failed.
|
clean |
$ make clean |
Remove all files and directories created by the other targets. This returns
the project directory to its original state.
|
Code Evaluation
After you have submitted and passed off your program, your source code will be
graded on how well you followed the good programming practices discussed in
class and in the textbook. The criteria for grading your source code can be
found at the following link:
Code Evaluation Criteria
Submitting Your Program
Create a gzip-compressed tar file containing all of your project's source files
and directories. The name of the compressed tar file must have the following
format:
firstname_lastname.tgz
where firstname should be replaced with your first
name and lastname should be replaced with your last
name. For example, if your name is Bob White, you would use the following
command to create your Chess tar file:
$ tar czf Bob_White.tgz chess
(this assumes that your project files are stored in a subdirectory named
chess
).
NOTE: In order to minimize the size of your tar file, please make sure that it
only contains C++ source files, make files, and any data files that are needed
by your test cases. It should not include .o files, .so files, executable
files, etc. If your tar file is larger than 500kb (half a megabyte), you will
not be allowed to submit it. If you follow these instructions, your tar file
will probably be much smaller than 500kb. If it is bigger than 500kb, you need
to delete some files and recreate the tar file.
After you have created your tar file, click on the following link to go to the
project submission web page:
Chess
Submission Page
After you provide your CS account login name and password and the name of your
tar file, this page will upload your tar file to our server.
After submitting your tar file, in order to receive credit you must also pass
off your project with a TA. When you pass off, you will be asked to download
your tar file from our server using the the project retrieval page, which is
located at the following link:
Chess
Retrieval Page
After downloading your tar file, you will be asked to:
-
un-tar your tar file
-
demonstrate that your make file supports all of the required functions
-
demonstrate that your program works (this includes showing that your heap size
is zero at the end of main)
If the TA finds problems with your program, you will need to fix your program,
submit a new tar file containing your modified program, and then pass it off
again with the TA.
Your project must be completely functional before the deadline in order to
receive full credit. This project is due on the last day of class, so there is
no possibility of turning it in after the deadline. However, partial credit
will be available to those who do not finish by the deadline.
Test Data
The following files contain saved games that you can use to test your program.
Miscellaneous Notes
Ken Rodham