Task 2: Beesweeper

_images/2-beelove.png

Your task is to implement the game Beesweeper in two styles: On a rectangular playing field, and on a “honeycombed” playing field.

The minimum requirement for passing the functional grading of this task: It must be possible to reveal fields and to win and lose the game on a small playing field.

Use the given template and add all missing functionality.

Two additional requirements:

  1. If JavaDoc is present in any unimplemented method of the given template (marked with UnsupportedOperationException), the implementation of the method must fulfill that JavaDoc.

  2. The run-time performance of your implementation will be considered in the grading of this task.

Beesweeper Rules

Beesweeper is a single-player game. Given a field of arbitrary size and a certain amount of hidden bees, the player has to clear the full field without hitting any bees. To find out which fields hide a bee, the player reveals fields without bees on them. Revealed fields tell the player how many bees are located in direct adjacency to that field (a number between 0 and 8). To remember the potential location of bees, the player can mark fields with flowers.

Winning condition

The player wins if all fields but the ones with bees on it are cleared, or if all bees are correctly marked with flowers. The player loses if she reveals a field that contains a bee.

Game Setup

The game starts on a playing field with a given number of hidden bees, a given shape (rectangular or honeycombed), and a given size. All cells on the playing field are cloaked at first. This means it is not visible whether there’s a bee or a number below a field. The user has as many flowers available as there are bees hidden on the playing field. For example, if there are 20 bees in the game, the user has 20 flowers.

Game Play

One turn after another, the player has three options:

  1. The player can reveal a cell. If the cell hid a bee, the game is immediately lost. If the cell did not hide a bee, the number of bees directly adjacent to the cell is displayed (a number between 0 and 8). This gives the user hints on where bees may hide.

  2. The player can mark a cell with a flower, to indicate that there is a bee under it. The player loses one flower and a cell marked with a flower can not be revealed without unmarking the cell first. Marking cells helps to not reveal a bee by mistake.

  3. The player can unmark a cell to get a flower back. Afterwards, the cell can be marked again, or be revealed.

If the last flower is used to correctly mark the last bee, the player wins the game. Otherwise, the game continues until all non-bee cells are revealed.

Beesweeper Shell

Our implementation of beesweeper uses a command-line shell for interaction.

There’s an input prompt “MW > ” that waits for user input. Upon pressing ENTER, the given input is processed.

The shell has to understand the following user inputs:

  • ‘NEWREC X Y B’ starts a new game on a rectangular playing field with ‘X’ columns, ‘Y’ rows, and ‘B’ bees hidden, and prints the new playing field. Example:

      MW > NEWREC 3 4 2
          A B C
        1 * * *
        2 * * *
        3 * * *
        4 * * *
      Flowers left: 2
      MW >
    
    
    For invalid input (numbers <= 0 or too many bees), the following error message is displayed:
    ``Error! Invalid input``.
    
  • ‘PRINT’ prints the current playing field with the corresponding fields revealed or unrevealed, and the current number of flowers left. This command only works if a game is currently running. Cloaked cells are displayed as ‘*’, numbers are displayed by the corresponding number, bees are displayed as ‘B’, and flowers are displayed as ‘F’. The coordinates of each row and column are displayed on the left/on the top. On the left, there’s space for 3-digit numbers. (i.e., for 1, the shell displays ⎵⎵1). Each column is separated by a single space from neighboring columns. Example:

    MW > PRINT
        A B C D
      1 * 0 * *
      2 * F 2 F
      3 * F 5 2
      4 * F F 0
    Flowers left: 2
    MW >
    

    If no game is actively running (i.e., no game started yet or the last game was lost), the following error message is displayed: Error! No active game running.

  • ‘REVEAL C R’ reveals the cell at column ‘C’ and row ‘R’. If the cell is a number, the number is revealed. If the cell is a bee, the game is over. In either case, the playing field is printed to the user in the same format as provided by ‘PRINT’. If the game is lost, the message Sorry, you lose. is displayed to the user afterwards. If the last cell is revealed and not a bee, the game is won. In this case, message Congratulations, you win! is displayed after printing the field. Example:

    MW > REVEAL A 1
        A B C
      1 3 * *
      2 * * *
      3 * * *
    Flowers left: 3
    MW > REVEAL B 1
        A B C
      1 3 B *
      2 * * *
      3 * * *
    Flowers left: 2
    Sorry, you lose.
    MW >
    
  • ‘MARK C R’ marks the cell at column ‘C’ and row ‘R’ and prints the playing field afterwards. If the cell can not be marked because it already is marked or revealed, the following error message is displayed: Error! Not possible.. If the last flower is used to mark the last unrevealed cell on the playing field, the game is won. In this case, message Congratulations, you win! is displayed after printing the field. Example:

    MW > PRINT
        A B C
      1 * 2 1
      2 2 F 1
      3 1 1 1
    Flowers left: 1
    MW > MARK B 1
    Error! Not possible.
    MW > MARK A 1
        A B C
      1 F 2 1
      2 2 F 1
      3 1 1 1
    Flowers left: 0
    Congratulations, you win!
    MW >
    
  • ‘UNMARK C R’ unmarks the cell at column ‘C’ and row ‘R’ and prints the playing field afterwards. If the cells can not be unmarked because it is not marked, the following error message is displayed: Error! Not possible.. Example:

    MW > PRINT
        A B C
      1 F * *
      2 * * *
      3 * * *
    Flowers left: 2
    MW > UNMARK A 1
        A B C
      1 * * *
      2 * * *
      3 * * *
    Flowers left: 3
    MW > UNMARK A 1
    Error! Not possible.
    MW >
    
  • ‘NEWCOMB Y B’ starts a new game on a honeycombed playing field with ‘Y’ rows, and ‘B’ bees hidden, and prints the new playing field. The playing field should be a regular hexagon (each ‘*’ is one unit). If it is not possible to build a regular hexagon with Y rows, the following message should be displayed: Error! Honeycomb with these dimensions not possible.. If it is not possible to fit B bees into the hexagon, the following message should be displayed: Error! Not enough fields for bees. Example:

    MW > NEWCOMB 1 1
    Error! Honeycomb with these dimensions not possible.
    MW > NEWCOMB 3 3
        A B C D
      1   * *
      2 * * * *
      3   * *
    Flowers left: 3
    MW > NEWCOMB 5 2
        A B C D E F G
      1     * * *
      2   * * * * *
      3 * * * * * * *
      4   * * * * *
      5     * * *
    Flowers left: 2
    MW >
    
  • ‘QUIT’ ends the game and exits the program immediately (without any further output).

For unknown commands, the following error message is displayed: Error! Invalid command.. For all invalid arguments not mentioned in the commands above (for example too few arguments), the following error message is displayed: Error! Invalid arguments: EXPLANATION where ‘EXPLANATION’ is the placeholder for an explanation of the issue.

Implementation Tips

  • Build the program incrementally. Start with the minimum requirements of the project: Commands ‘NEWREC’, ‘PRINT’ and ‘REVEAL’.

    Once you have tested that these commands work reliably and when you are happy with your code, continue with the commands that build on that: ‘MARK’ and ‘UNMARK’.

    Finally, implement command ‘NEWCOMB’ and any other missing commands.

    When implementing the first set of commands, keep in mind that the playing field will have to adapt to other shapes than a rectangle (here: a hexagon).

  • Do not implement for speed, but for understandability! Make the code easy to understand and work reliably. Introduce classes to hold your data in an understandable way and try to mimic the game’s world with your classes.

  • Only care about performance bottlenecks as a last step. Regarding speed, we only care about asymptotic performance issues, i.e., unfitting data structures and nested loops that could be avoided.

General Requirements

  • You can modify the behavior of any method of the template, and add public methods if necessary.

  • BUT: Do not modify any public method signatures or interfaces. You are not allowed to add method parameters to existing public methods.

  • The output and return values of implemented methods must exactly match the output described here. Otherwise, tests will fail.

  • Documentation of the source code is part of the exercise and will be graded. The Google Java Style Guide must be fulfilled.

  • The asymptotic run-time performance of the implementation is part of the exercise and will be graded.

  • Your solution must be anonymous. Your name may not appear in the solution.

  • Your solution may not contain compiled data (no build directory or .class files). Please check the content of your ZIP file before uploading.

Helpful Resources

While reading JavaDoc, you may encounter the following types that could be confusing:

  • Stream is an advanced data structure similar to lists. It can be consumed only once and has lots of methods for transformation and filtering. Often uses method references and other advanced topics. You can turn any Stream into an immutable List like this:

    Stream<Integer> numberStream = // .. snip ..;
    List<Integer> numberList = numberStream.collect(Collectors.toList());
    

bee Good luck!