Debugging and Assertion Statements

Objectives
  • Practice interpreting code and paying attention to program requirements.

  • Explore program debugging using Eclipse.

Getting Started

Create a new Java project called Debugging and import MineSweeper-starter.jar.

Your directory should look like this:

Debugging/
└── src
    ├── BoardModel.java
    ├── BoardSpace.java
    └── BoardController.java
Description

This week’s assignment involves very little coding on your part. Instead, you will be tasked with reading, understanding, and debugging an application.

The first part of debugging is truly understanding what the code is supposed to do. Start go here.

There are two distinct commands the player may enter to play the game: reveal and flag. These commands are entered at the displayed > prompt.

  • > r [x] [y] : reveals what is present in the board space located at (row x, column y). If this space contains a mine, the player loses. The player may win the game by revealing all board spaces that are not mines.

  • > f [x] [y] : flags a board space (row x, column y) as a possible mine. The player wins the game if they manage to flag all mines.

  • > q : quit the game.

  • > reset : start a new game.

Your Task

The provided implementation of minesweeper contains numerous bugs. Your job is to read and interpret the provided code documentation to understand what each method should accomplish.

Read about a general workflow on how to debug your program here.

This assignment does NOT involve writing a substantial amount of code. If you find yourself writing much more than a single if-statement here and there, something is wrong. Most of the required fixes are minor tweaks to the existing code.

Furthermore, you need only modify the code in BoardModel.java. There are no intentional bugs in BoardSpace.java and BoardController.java to worry about. BoardController is responsible for running the minesweeper game and interacting with the user. BoardSpace objects are used by the BoardModel to represent game spaces. You may encounter bugs in how BoardModel uses BoardSpace objects.

You should assume that the provided documentation is correct. There are no intentional bugs in the documentation.

Overview of the Program

The provided minesweeper game consists of three classes: BoardController, BoardModel, and BoardSpace.

  • BoardController handles all I/O and interaction with the player.

  • BoardModel represents the current state of the game. More specifically, BoardModel describes the rules of the game (win/loss conditions, move validity, etc.) and the state of the game in progress (revealed spaces, flag/mine locations, etc.).

  • Internally, the game board is represented as a two dimensional array of BoardSpace objects in (row, column) order. For example:

int row = 5;
int col = 2;

BoardSpace space = board[row][col];

Refers to BoardSpace stored in row 5, column 2. Recall that row 0, column 0 is the top left corner of the board. Each BoardSpace describes whether or not the space has been revealed (directly or indirectly), if the space contains a mine, if the space has been flagged, and the number of mines that are adjacent to the space. In general, a BoardSpace object is responsible for storing information related to how that particular space is view by the user over the course of the game.

Board spaces are initially not "visible" to the player. That is, the player does not know whether or not a space contains a mine until it has been revealed. This information is displayed once the player reveals a space either directly (via the reveal command) or indirectly (triggered exploration). The BoardModel is the intermediary for all interaction with BoardSpace objects. The BoardController has no knowledge of the details of the BoardSpace class.

BoardModel contains numerous instance variables that help it keep track of the game’s state. Aside from the previously discussed 2D board, BoardModel also keeps track of the unflagged mines (remainingMines), the number of mines that should be laid, whether or not the user has made their first move, and whether the game has been lost or won. BoardModel retains state of the user’s first move in order to improve the game’s playability. Mines are only laid after the player has made their first move. This prevents the player from picking a mine on their first move and immediately losing the game. We will discuss mine laying in more detail shortly.

Constructing BoardModels

Minesweeper games are created with respect to a difficulty setting. We allow three difficulty settings: beginner, intermediate, and expert. The details of these modes are shown in the table below:

Difficulty

number of rows

number of columns

number of mines

Beginner

8

8

10

Intermediate

16

16

40

Advanced

16

30

99

For the purposes of debugging we have provided a seed. This means that the same difficulty level and first action will lead to the same board every single time. This allows your to reproduce your errors as you are debugging the program.

The constructor must ensure other pieces of the game’s state are properly initialized. However, this task is delegated to the resetBoard() method. We will discuss this method soon.

Debugging the Constructor (Warm Up)

Your TA will talk to you about how to use the debugger and help you work through the bugs in the constructor:

The initial BoardModel(Difficulty level) constructor contains:

	public BoardModel(Difficulty level){
        int rows, cols;
        switch (level) {
            case BEGINNER:
                rows = cols = 8;
                numMines = numFlags = 10;
                break;

            case INTERMEDIATE:
                rows = cols = 16;
                numMines = numFlags = 40;
                break;

            case EXPERT:
            default:
                rows = 16;
                cols = 30;
                numMines = numFlags = 99;
                break;
        }

        BoardSpace newSpace = new BoardSpace();
        for (int r = 0; r < rows; r++) {
            for (int c = 0; c < cols; c++) {
                board[r][c] = newSpace;
            }
        }
        resetBoard();
        rdm = new Random();
    }

Try running the game on in each mode: beginner, intermediate, and expert. Once of the levels doesn’t work correctly. How come?

Once you are sure each board is being constructed properly. Try making a move, type r with the row and column that you want to make your first move with. Is this the behavior that you expected?

After debugging the constructor you should have the following code:

	public BoardModel(Difficulty level){
        int rows, cols;
        switch (level) {
            case BEGINNER:
                rows = cols = 8;
                numMines = numFlags = 10;
                break;

            case INTERMEDIATE:
                rows = cols = 16;
                numMines = numFlags = 40;
                break;

            case EXPERT:
            default:
                rows = 16;
                cols = 30;
                numMines = numFlags = 99;
                break;
        }
        board = new BoardSpace[rows][cols];

        for (int r = 0; r < rows; r++) {
            for (int c = 0; c < cols; c++) {
                board[r][c] = new BoardSpace();
            }
        }
        resetBoard();
        rdm = new Random();
    }

Running the program should now successfully run the BoardModel constructor but the program probably won’t run yet. The remainder of this lab page will point you to various buggy methods. Use the javadocs to understand the methods and follow the above workflow to help you fix the problems.

The Rest

There are 14 bugs total.

With each bug you find, take a moment to comment above the bug with:

  • What the problem was.

  • How you fixed it.

Your lab assignment is to fix bugs in the following methods:

  • resetBoard()

  • layMines(int row, int col)

  • isValidMove(int row, int col)

  • reveal(int row, int col)

  • explore(int row, int col)

  • flag(int row, int col)

  • unflag(int row, int col)

Submission

This lab is based on attendance. Good luck on your exam!