Program Design and Debugging

This lecture presents a sample program that implements a "Pirate Treasure" game using C-Style ADTs and many of the programming techniques we've seen in the course so far. We also cover several debugging strategies to track down bugs in the program.

Updated Winter 2025

1: Program Overview
1.1 Not Started

Here's an overview of where things are in the "Pirate Treasure" program with a few comments on overall program design. I go through things pretty quickly and without all the details, but the intent is primarily to orient you to what parts exist so that the debugging strategies below make more sense (don't worry if you're not quite sure about how everything works).


1.1 Exercise: Module Responsibilities

Based on the overview above (or taking a look through the code in the GitHub repository), which file is responsible for the following tasks? Write either "Game.cpp", "Game.hpp", "CommandUI.cpp", or "pirate.cpp" in each of the blanks.

Updating the number of treasures/traps that have been revealed after each move.

Reading input from the user to determine the next move.

Determining whether any neighboring cells are revealed if the user chose to reveal an empty cell.

Extracting the desired size of the game board from command-line arguments.

Providing function prototypes that define the public interface of the Game ADT.

Defining the main() function that starts the Pirate Treasure game.

Sample solution…

Function declaration in .h file

Function definition in .cpp file

Code inside the function's curly braces

Which input values are valid or invalid for the function

Comments inside the function to clarify tricky lines of code

RME comment before the function declaration in .h file



2: Scavenger Hunt
2.1 Not Started

In addition to writing new code from scratch, it's also valuable to practice reading through a new codebase, understanding the way it's organized, and figuring out how to change it.

For this section, first get your own copy of the code. It lives in a public repository at https://github.com/jamesjuett/pirate-treasure. From the terminal, you can create local clone of this repository in your EECS 280 folder. Run the commands indicated by the $ below (don't type/copy the $ itself).

$ cd ~/eecs280
$ pwd
/home/jjuett/eecs280
$ git clone https://github.com/jamesjuett/pirate-treasure.git
Cloning into 'pirate-treasure'...
remote: Enumerating objects: 157, done.
remote: Counting objects: 100% (157/157), done.
remote: Compressing objects: 100% (98/98), done.
remote: Total 157 (delta 94), reused 117 (delta 57), pack-reused 0 (from 0)
Receiving objects: 100% (157/157), 80.20 KiB | 1.15 MiB/s, done.
Resolving deltas: 100% (94/94), done.

(Note that some of your output may be different, e.g. your username in the home directory.)

This command will create a new folder called pirate-treasure. If you're using VS Code, you can open it by running:

code pirate-treasure

You're welcome to browse through the code as much as you like. The organization ends up similar to EECS 280 project 2 in many places, and there are some areas you might find helpful as examples. At a minimum, consider the exercise below.

2.1 Exercise: Scavenger Hunt

Consider the scenarios below. Please note that you don't actually need to implement and/or test anything in the code, just consider where these changes would need to be made.

In a well-designed program, there should often be a clear, specific place where you need to add or modify code to change a particular behavior. Let's say you wanted to modify the program so that a new game will never contain traps or treasures on the boundary of the game board. Which function(s) would you need to modify to implement this?

On the other hand, some changes might need to affect multiple parts of the program. Consider implementing a "lives" system where a player starts with e.g. 3 lives and it takes 3 traps revealed to end the game. In this case, the Game.hpp file would need to change as well - why is this (and why wouldn't it be necessary for the change above?


Sample solution…

Part 1: The first Game_init() function as well as the internal place_items() function would potentially need to change. Either place_items() could be modified to avoid the borders, or additional parameters could be added so that an acceptable region for placing the items could be specified when it was called by Game_init().

Part 2: In this case, the Game ADT would be responsible for keeping track of the number of lives, and the implementations of several functions in Game.cpp would need to change to initialize and update the lives, as well as to consider lives when determining if the game is over. The Game.hpp file would also need to contain changes to the Game struct definition to store the current number of lives and to add a public interface function so that other ADTs like CommandUI could check the current number of lives.



3: Debugging

Now, let's look at several debugging strategies applied to the "Pirate Treasure" program.

First, we'll take a look at running the overall pirate.exe program and Game_tests.exe unit tests. We encounter and track down a segmentation fault using a visual debugger.


Next, we'll take a look at some defensive programming techniques, including using assertions, to detect bugs earlier and make them easier to fix.


Finally, we'll get more information about what exactly the program is doing by adding breakpoints and using print statements so that we can figure out what is happening to cause the last few bugs.


You've reached the end of this lecture! Your work on any exercises will be saved if you re-open this page in the same web browser.

Participation Credit
Make sure to sign in to the page, complete each of the exercises, and double check the participation indicator at the top left of this page to ensure you've earned credit.