Project 0: Checkers Game Engine - Fall 2025

There are no late submission folders for Project 0. You must turn it in on-time to receive credit.

Due: Tuesday Sep 9, before 9:00 pm

Objectives

  • Review the procedures to access the GL servers and to compile programs on GL.
  • Review C++ memory management (allocating and deallocating memory dynamically).
  • Use Valgrind to check for memory leaks.
  • To practice writing unit tests.
  • To practice working in a Linux environment.
  • To practice analyzing and understanding a project requirements.

Introduction

In this project, you will complete a C++ class. Furthermore, you will write a tester class and a test program and use Valgrind to check that your program is free of memory leaks. Finally, you will submit your project files on GL. If you have submitted programs on GL using shared directories (instead of the submit command), then the submission steps should be familiar.

In this project we develop the core part of an app. The app will be used by two players to play checkers. This software module along with a proper user interface can provide the complete game experience.

The Checkers class enforces the rules for a checkers game and stores the state of a game. You are assigned the task to implement the Checkers class. An object of the Checkers class contains a digital checkers board. The class stores the state of the game in a 2D array of the type CELL. The following figure presents multiple visualizations of an initial checkers game. The examples show the state of the game in a terminal, one may notice that depending on the terminal the cell colors can be different. For example, on a terminal with black background color the white cells of the checkers board are rendered in black. In this presentation the row and column numbers are provided to facilitate the debugging. The word WD represents White Disk and the word BD represents Black Disk. For the details of all definitions please refer to the provided template source files.

The following figure represents the main data structure in this project. It is a 2d structure.

Assignment

Step 1: Create your working directory

Create a directory in your GL account to contain your project files. For example, cs341/proj0.

Step 2: Copy the project files

You can right-click on the file links on this page and save-as in your computer. Then, transfer the files to your GL account using SFTP.

For this project, you are provided with the skeleton .h and .cpp files, a sample driver, and the output of driver program:

  • checkers.h - The interface for the Checkers class.
  • checkers.cpp - The skeleton for the class implementation.
  • driver.cpp - The sample driver/test program.
  • driver.pdf - The output of sample driver/test program.

Step 3: Complete the Checkers class

You need to implement the class according to the requirements. For the requirements please refer to the Specifications, The Rules, and Additional Requirements sections on this page.

Step 4: Test your code

You need to test your implementation properly and adequately. For a description of testing please refer to the Testing section on this page. Moreover, a sample test function has been provided in the file driver.cpp for your reference.

Step 5: Check for memory leaks

Run your test program using Valgrind. For example, assuming you have compiled mytest.cpp, producing the executable mytest.out, run the command

   valgrind mytest.out 

If there are no memory leaks, the end of the output should be similar to the following:

   ==8613== 
            ==8613== HEAP SUMMARY:
            ==8613==     in use at exit: 0 bytes in 0 blocks
            ==8613==   total heap usage: 14 allocs, 14 frees, 73,888 bytes allocated
            ==8613== 
            ==8613== All heap blocks were freed -- no leaks are possible
            ==8613== 
            ==8613== For lists of detected and suppressed errors, rerun with: -s
            ==8613== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
          

The important parts are “in use at exit: 0 bytes” and “no leaks are possible.” The last line is also important as memory errors can lead to leaks.

Step 6: Link your shared directory

Please take this step as soon as you receive the notification indicating the shared submission folders are ready. Leaving this step to the last minute can prevent you from submitting your work on time. Please note:
  * No other method of submission will be accepted due to such a problem.
  * No late submission will be accepted due to such a problem.

Follow the instructions on the Project Submission page to make a symbolic link to the shared directory in your home directory.

Step 7: Submit your files

See the “What to Submit” section, below.

The Rules

The following rules are part of the project requirements.

  • The min number of rows on the board is 8.
  • The min number of columns on the board is 8.
  • The number of columns is always an even number.
  • There are two players. They play in turn.
  • The board can be of any square size. It is similar to a chessboard with the cells in two different colors, e.g. black and white.
  • The number of disks for every player is (number of columns / 2 * 3). For example if the number of columns is 8, every player has 12 disks.
  • The disks are arranged on the board in a way that every player has an empty cell at the right-most corner.
  • The black player starts the game.
  • Players move their disks in turn. A disk can move only diagonally, forward and one location if there is an empty cell.
  • A disk can jump diagonally two locations if there is an empty cell and it can jump over an opponent disk. In this case, the opponent disk will be captured meaning the opponent loses that disk. The lost disk will be removed from the board.
  • If a disk can reach to the border side of the opponent the disk becomes a king, it is represented with BK or WK. A king can move diagonally forward or backward.

Specifications

You must implement the following functions. These functions are the public interface of the project. The public interface will be used to test your project. You can use private helper functions in your design of this project. They won't be called directly for testing.

Checkers::Checkers()
This is the default constructor. It creates an empty object. An empty object does not hold any memory. The constructor must initialize all member variables.
Checkers::Checkers(int rows, int columns)
This is the constructor. It initializes all member variables and it allocates required memory if necessary. If the user passes invalid parameters such a a negative size the constructor creates an empty object.
Checkers::~Checkers()
This is the destructor and it deallocates the memory.
void Checkers::clear()
This function deallocates all memory and reinitializes all member variables to default values. It clears the current object to an empty object.
bool Checkers::initBoard()
This function initializes the game board to its checkers form. Dumping the object after calling this function will render a checker board without any disks. If the board initialization is successful the function returns true. The following figure presents the results of calling this function.

bool Checkers::initGame()
This function places the disks on the board. It also initializes the required member variables. Dumping the object after calling this function will render a checker board with all disks on their initial locations. If the game initialization is successful the function returns true. The following figure presents the results of calling this function. Notes:
  • This function will be called after initBoard(). It augments the game initialization process.
  • The board can be of any square size. Only the three rows are initialized by disks for every player.
  • The player with black disks starts the game.

bool Checkers::play(pair<int,int> origin, pair<int,int> destination)
This function receives an origin cell and a destination cell. It performs the move if all required conditions are satisfied for the requested move. If a move is completed successfully, the function returns true otherwise it returns false. The origin and destination cells are passed to this function in the form of pairs of row index and column index numbers. You might want to introduce one or more helper functions to facilitate the implementation of this function.
bool Checkers::setGameState(CELL game[], int n, PLAYER player)
This function rececives an array of CELLs and re-state the game using the provided values in the array. Using this function we can modify the state of the game. The variable n is the size of the array, and the variable player will be the current player after changing the state of the game. The size of array is equal to the number of cells, i.e. #columns x #rows. The array carries a value for a corresponding cell on the board if we want to modify that cell. The array carries an empty string for a corresponding cell if there is no intention to change that cell. For an example of a call to this function, refer to the provided sample driver program. This function may also need to modify the required class member variables based on the new information in the array. If the state of game is modified the function returns true. If there are errors in the provided state this function does not modify the state of the object. For example, the user might try to add more disks for a player than the maximum number of possible disks.
void Checkers::reportLostDisks()
This function prints the number i=of lost disks for every player at the time that is called. The following presents a sample output of this function.

void Checkers::dumpGame()
This function renders the board (the game state) on the terminal at the time that it is called. The implementation of this function is provided. You do not need to modify this function. This function is for debugging purposes. Do not call this function in the test program that you'll submit.

Additional Requirements

  • The class declaration (Checkers) in checkers.cpp may not be modified in any way. No additional libraries may be used.
  • You must use nullptr to set pointers to a default value. Do not use NULL or zero or any other value for this purpose.
  • You are not allowed to use STL template containers in your project implementation.
  • You are allowed to use STL template containers in your test functions.
  • The class functions must be written in checkers.cpp; in particular, they must not be written “in-line.”
  • Private helper functions may be added, but must be declared in the private section of the Checkers class. There is a comment indicating where private helper function declarations should be written.
  • You should read through the coding standards for this course.

Testing

Important, points will be deducted for violating the following list:

  • The sample driver.cpp file will not be accepted as a test file.
  • The name of the test file must be mytest.cpp.
  • The mytest.cpp file contains the Tester class, and the main function.
  • The test cases must be implemented in the Tester class, and must be called in the main function.
  • Every test function returns true or false to indicate the pass or fail.
  • A dump() function is provided for debugging purposes, visual inspections will not be accepted as test cases.

You must write and submit a test program along with the implementation of your project. To test your project class, you implement your test functions in the Tester class. The Tester class resides in your test file. You name your test file mytest.cpp. It is strongly recommended that you read the testing guidelines before writing test cases. A sample test program including Tester class, and sample test functions are provided in driver.cpp. You add your Tester class, test functions and test cases to mytest.cpp. You must write a separate function for every test case.

Any program should be adequately tested. Adequate testing includes test functions for normal cases, edge cases and error cases if any applies. The following list presents some examples for this project:

  • Trying to create a Checkers object with 6 rows and 6 columns is an error case.
  • Trying to create a Checkers object with 8 rows and 8 columns is an edge case.
  • Trying to create a Checkers object with 10 rows and 10 columns is a normal case.

The following presents a non-exhaustive list of tests for this project. Please note, you need to test your work adequately.

  • Test whether the constructor works correctly for an error case, e.g. it creates an empty object if the user tries to create an object with -5 rows and -10 columns.
  • Test whether the constructor works correctly for an normal case, e.g. it creates memory and initilizes all member variables to the proper values, if the user tries to create an object with 10 rows and 10 columns.
  • Test whether initBoard() is working correctly for an error case, e.g. if it is called on an empty object, the object will stay an empty object after the call.
  • Test whether initBoard() is working correctly for an edge case, e.g. the cells in m_game are initialized to the correct value, if the object has an 8x8 board.
  • Test whether initGame() is working correctly for an error case, e.g. if it is called on an empty object, the object will stay an empty object after the call.
  • Test whether initGame() is working correctly for a normal case, e.g. the cells in m_game are initialized to the correct value, if the object has a 10x10 board. Moreover, each player has the proper number of disks.
  • Test whether setGameState(...) is working correctly, e.g. after calling the function the board cells are initialized to the correct values and the class member variables have the correct values.
  • Test whether play(...) is working correctly for an error case, e.g. it is the white turn, but the requested move is for a black disk. In such a case there should not be any change to the object and the play(...) function must return false. Please note, there are multiple possible error cases based on the requirements.
  • Test whether play(...) is working correctly for a normal case, e.g. a valid single move is requested and the object is modified correctly after calling the play(...) function. In such a case the function must return true.
  • Test whether play(...) is working correctly for a normal case, e.g. a valid jump over opponent is requested and the object is modified correctly after calling the play(...) function. In such a case the function must return true.

The following test function is provided to you in driver.cpp in the Tester class as a sample test function. We recommend that you study the implementation of this function.

bool Tester::testCaptureSuccess(Checkers & checkers)
This function tests whether the play function works correctly in performing a jump and capturing an opponent disk.

What to Submit

You must submit the following files to the proj0 submit directory:

  • checkers.h
  • checkers.cpp
  • mytest.cpp (Note: This file contains the declaration and implementation of your Tester class as well as all your test cases.)

If you followed the instructions in the Project Submission page to set up your directories, you can submit your code using the following command:

   cp checkers.h checkers.cpp mytest.cpp ~/cs341proj/proj0/

Grading Rubric

For details of grading rubric please refer to Project Grading Policy