In this lab, you will be working with existing code and adding to it. You are given working versions of all the classes that make up a simple version of the classic Windows game "Mine Sweeper"--all the classes, that is, except one. Your task is to complete the missing class so that the game works correctly. Note that no source code is available to you except for the class that you are to complete. Javadoc for all classes used in this lab is available in the project itself.

When you complete the lab assignment, you'll be able to play your own version of Mine Sweeper. This is our last lab, so have fun!

The Mine Sweeper game is played on a grid of cells, each of which potentially contains a mine. The objective of the game is to uncover all of the cells which do not contain mines and to place a flag on all of the cells which do contain mines.

Initially all of the cells on the board are covered and appear to be raised like those in the lower right corner of the above figure. Left clicking on a cell with the mouse will uncover a cell. If the uncovered cell contains a mine, the game is over. If the uncovered cell does not contain a mine, the cell will either become blank or will be filled with a number. The appearance of a number in an uncovered cell indicates the number of mines that are contained in adjacent cells. For example, in the figure above there is a mine in exactly one cell adjacent to each cell containing a 1. Similarly, there are exactly two mines adjacent to the cell in the center of the bottom row which contains a 2.

When a player determines that a cell contains a mine, the player can place a flag on that cell by right clicking the mouse on the cell. In the figure above a flag has been placed on one cell which is thought to contain a mine. Once a flag is placed on a cell, that cell cannot be uncovered unless the flag is first removed by right clicking on the cell again. This protects the player from accidentally uncovering a cell which is thought to contain a mine.

The game ends when the player either, loses by uncovering a mine or wins by placing a flag on all cells which contain a mine and uncovering all of the remaining cells. The difficulty of the game can be changed by selecting a different level of play from the "Level" menu. The higher the level of play, the larger the board becomes and the more mines it contains.

To begin this assignment, download the minesweeper.zip file and unzip it to create a project directory. If you open up the project in BlueJ, you can see the class diagram for the Mine Sweeper application. You can also access the Javadoc for all of the classes using the Tools->Project Documentation menu entry (remember to choose "Just Show", the Javadoc will open in your web browser)).

Your assignment for this lab is to complete the implementation of the Mine Sweeper game. To complete the implementation you will need to write the MineSweeperBoard class. You have a skeleton of this class to begin with, and only need to fill in the method bodies that are missing. This class is a subclass of MineSweeperBoardBase, an abstract base class that provides some of the capabilities needed to complete a solution.

The MineSweeperBoard class is responsible for keeping track of the contents of the Mine Sweeper board as the game is being played. Many of the details you will need to perform this implementation can be found in the Java Documentation for the MineSweeperBoard class. The following sections contain some additional information about the MineSweeperBoard class and give an outline for how to approach this lab.

Representing the Board

The most direct way to implement the MineSweeperBoard is to use a two dimensional array of integer values to represent the current state of the playing board. The integer value contained in each cell indicates the contents of the cell and whether or not it has been uncovered or has had a flag placed on it. The following table gives a list of the integer values that may appear in such an array (these constants are predefined in the abstract base class, so that they are immediately available in the methods you will be completing):

Cell ValueConstantMeaning
-1COVERED_CELL An array entry containing the value COVERED_CELL indicates an empty cell on the board that has not yet been uncovered by the player.
-2MINE An array entry containing the value MINE indicates a cell containing a mine which has neither been uncovered by the player nor has it had a flag placed on it.
-3FLAG An array entry containing the value FLAG indicates a cell that does not contain a mine, but which has had a flag (incorrectly) placed on it.
-4FLAGGED_MINE An array entry containing the value FLAGGED_MINE indicates a cell that does contain a mine and has had a flag (correctly) placed on it.
-5UNCOVERED_MINE An array entry containing the value UNCOVERED_MINE indicates a cell containing a mine which has been uncovered by the player.
0-8n/a An array entry containing a value between 0 and 8 indicates an empty cell which has been uncovered. The specific value between 0 and 8 indicates the number of mines which appear in the adjacent cells.

To help clarify the meaning of these values consider the following examples. When a new MineSweeperBoard is created it will contain only COVERED_CELLs (-1) and MINEs (-2). The MINEs will be placed randomly in the array. For example if the new array has 3 rows and 4 columns it might look as follows:


A newly created array with no cells
uncovered and mines at location (0,0) and (2,1).

If the player were to left click on the upper right hand cell of the board then the MineSweeperBoard class would change cell (0,3) of its array to a zero as shown below:


The player left-clicked on the cell
in the upper-right corner.

Cell (0,3) was changed to a zero reflecting the fact that the cell has been uncovered and that there are no mines adjacent to this cell. When the Mine Sweeper game sees a 0 in this location it will display a sunken blank icon in the upper-right corner.

If the player were now to left click in the center cell in the left-most column, the MineSweeperBoard would change cell (1,0) in its array to a two, indicating that there are two mines adjacent to that cell. When the Mine Sweeper game detects a 2 in this location it will display a sunken icon containing the number 2. The array would now appear as follows:


The player left-clicked on the cell
in the center of the left-most row.

If the player were now to right click on the cell in the lower-left corner of the board to place a flag on that cell, the MineSweeperBoard would change cell (2,0) of its array to FLAG. Recall that the value FLAG indicates that a flag has been (incorrectly) placed on a cell which does not contain a mine. The array would now appear as shown below:


The player right-clicked on the cell
in the lower-left corner.

If the player now right clicks on the cell in the upper-left corner of the board, the MineSweeperBoard would change cell (0,0) of its array to a FLAGGED_MINE. The value FLAGGED_MINE indicates that a flag has been (correctly) placed on a cell containing a mine. The array would now appear as shown below:


The player right-clicked on the cell
in the upper-left corner.

Imagine now that player, having decided that the cell in the lower-left corner of the board should not be flagged, right-clicks again on the lower-left corner cell. The MineSweeperBoard must now change cell (2,0) of its array back to an COVERED_CELL. Similarly, if the player were to decide to remove the flag from the upper-left corner, the MineSweeperBoard class would have to change cell (0,0) of its array back to a MINE. Finally, if after removing the flag from the upper-left corner of the board, the poor unsuspecting player left clicks that cell, the MineSweeperBoard will change cell (0,0) to a UNCOVERED_MINE, effectively causing the game to end.

As in our prior labs you must must work with a another student as a pair. Decide which of you will be the driver and who will be the navigator for Part A. Be sure to switch roles between the driver and navigator half way through the lab period. The driver should do all the typing/mousing. The driver should feel free to ask for advice or bounce ideas off the navigator, and the navigator should look out for errors in what the driver is typing. Work efficiently to complete this assignment in the allotted lab time.

Procedure

  1. Complete the MineSweeperBoard constructor

    1. Open the Mine Sweeper project if you have not already, and then open the MineSweeperBoard in an edit window.

    2. Decide what field(s) you want to use to store the state of the board. Add them to the class--you can always add more later if you need to.

    3. Complete the body of the constructor. Note that there are two protected methods provided by the base class that help with clearing the board and placing mines.

  2. Complete the simple accessor methods

    1. Accessor methods are typically simple and straightforward to write. Complete the body of the getCell() method.

    2. Complete the body of the getColumns() method.

    3. Complete the body of the getRows() method.

  3. Complete the simple mutator method

    1. Complete the body of the setCell() method. Note that this method is protected, and is intended only for use by the pre-written methods in the base class.

  4. Write a test class

    1. Try compiling your class. You'll get some errors because some of the methods you have not yet written are expected to return values, but they contain no return statements.

    2. You can repair such an error by inserting an appropriate return statement that just returns a dummy value (like null or zero). Fix all such errors so you can compile your code.

    3. Now create a test class for your code.

    4. Decide on a simple test fixture--maybe a test board that is 4-by-4 cells or so.

    5. Brainstorm a couple of simple test cases that exercise the methods you've written so far. Note that the base class gives you two useful functions for writing test cases as well:

              // board is declared as part of the test fixture, and
      	// is initialized to be 4x4
              board.loadBoardState( new String[]{ "    ",
                                                  "OOOO",
                                                  "O++O",
                                                  "OOOO" } );
              board.setCell( 2, 1, MineSweeperBoardBase.FLAGGED_MINE );
              board.printBoard( new PrintWriter( System.out ) );
      

      This segment of code uses loadBoardState() to fill the board with specific contents for testing purposes. It also uses printBoard() to print the current state of the board out to the terminal window. Of course, you can also turn this into a real test case:

          public void assertBoard( String[] expected, MineSweeperBoard theBoard )
          {
              MineSweeperBoard expectedBoard =
      	    new MineSweeperBoard( expected.length, expected[0].length(), 0 );
              expectedBoard.loadBoardState( expected );
              assertEquals( expectedBoard, theBoard );
          }
      
          public void testSetCell()
          {
              // board is declared as part of the test fixture, and
      	// is initialized to be 4x4
              board.loadBoardState( new String[]{ "    ",
                                                  "OOOO",
                                                  "O++O",
                                                  "OOOO" } );
              board.setCell( 2, 1, MineSweeperBoardBase.FLAGGED_MINE );
              assertBoard( new String[]{ "    ",
                          	           "OOOO",
                                         "OM+O",
                                         "OOOO" },
      		     board );
          }
      
    6. At this point, you can try out your board "live". Right-click on the MineSweeper class and execute its main() method. Click OK to use the default argument values. It doesn't really work yet, since you haven't implemented all the methods, but as you add more, it will get "closer and closer" to a playable game.

  5. Implement flagCell()

    1. Add test cases for flagCell(). Read its documentation comments carefully in your source file for details about how it should operate. Compile and run your test cases.

    2. Implement the flagCell() method.

    3. Recompile, and re-run test cases. Repeat until all errors are resolved.

  6. Implement uncoverCell()

    1. Add test cases for uncoverCell(). Read its documentation comments carefully in your source file for details about how it should operate. Compile and run your test cases.

    2. Implement the uncoverCell() method.

    3. Recompile, and re-run test cases. Repeat until all errors are resolved.

If you reach this point before the lab is half over, it is time to switch roles. Otherwise, you should have already switched.

Procedure

  1. Implement revealBoard()

    1. Add a test case for revealBoard(). Read its documentation comments carefully in your source file for details about how it should operate. Compile and run your test case.

    2. Implement the revealBoard() method.

    3. Recompile, and re-run test cases. Repeat until all errors are resolved.

  2. Implement numAdjMines()

    1. Add test cases for numAdjMines(). Read its documentation comments carefully in your source file for details about how it should operate. Pay attention to boundary conditions. Compile and run your test cases.

    2. Implement the numAdjMines() method.

    3. Recompile, and re-run test cases. Repeat until all errors are resolved.

  3. Implement gameLost()

    1. Add test cases for gameLost(). Read its documentation comments carefully in your source file for details about how it should operate. Compile and run your test cases.

    2. Implement the gameLost() method.

    3. Recompile, and re-run test cases. Repeat until all errors are resolved.

  4. Implement gameWon()

    1. Add test cases for gameWon(). Read its documentation comments carefully in your source file for details about how it should operate. Compile and run your test cases.

    2. Implement the gameWon() method.

    3. Recompile, and re-run test cases. Repeat until all errors are resolved.

  5. Submit your solution

    1. On BlueJ's main menu, select Tools->Submit... from the main menu. Click on "Browse...", open the CS 1705 category, and select "Lab 14" (there is only one submission link this week). Click "OK". Click "Submit". Read the response you receive, and click on any link it provides for more information about your submission.

    2. Fix any errors, warnings, or suggestions that are indicated in the analysis of your submission.

In the BlueJ class window, (not on the object bench), right-click on the MineSweeper class and select its main() method to execute it, (do NOT instantiate a MineSweeper object). Click OK to use the default argument values. Play your game, and enjoy!