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:

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:

        R        
                   
        K        
               
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.
B            
                   
        P        
        K        
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.
Q            
                   
        K        
    R        
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:

  1. 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.

  2. For each class in your design, document the following:

    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.

  3. DETAILED description of the top-level algoirthms that implement each of the use cases below:

    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: 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: 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:

  1. un-tar your tar file
  2. demonstrate that your make file supports all of the required functions
  3. 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