4. week

Task 3 - Creating simple console interface

Motivation

When programming games or other software systems it is very important to understand how the user will use the application, how will he interact with it. In case of games it is definitely important to identify phases of the game cycle, actions that can be initiated by the player, and effects which these actions may have on the game. You will focus on these key tasks during implementation of console user interface.

In case of tiled games, to implement console user interface it is required to implement the following three methods:

  • play(Field field) - game loop which will combine printing the text representation of the game field to the output and dialogue with the user,
  • show() - serves for printing the text representation of game field, called after each game "move",
  • handleInput() - processes user-entered input and executes corresponding action on the game field.

Objectives

  1. Implement the game loop in which the game will be running.
  2. Implement printing of the string representation of the game field.
  3. Implement handling of the user input and communication of the game with the user.

Instructions

Step 1

Task 1.1

Implement method with the functionality of game loop, e.g. play(Field field), in class that represents console user interface, e.g. ConsoleUI.

This method should perform the following actions:

  • initialisation of private variable field which will be used as an internal model of the game,
  • in loop:
    • printing the text representation of the game field to the output using method show(),
    • reading and processing user-entered input by using method handleInput(),
    • reaction on eventual changes of the game state (FAILED, SOLVED, etc.).

Comment

When implementing the functionality, split the source code into suitable private methods to improve readability of the code.

An example of implementation of the method play for game Minesweeper:

public void play(Field field) {
    this.field = field;
    do {
        show();
        handleInput();
    } while(field.getState() == GameState.PLAYING);

    show();

    if(field.getState() == GameState.SOLVED) {
        System.out.println("Solved!");
    } else if(field.getState() == GameState.FAILED){
        System.out.println("Failed!");
    }
}

Step 2

To display the game field on the standard output, the following requirements can be identified for the Minesweeper game:

  • Lines are denoted by uppercase letters in ascending order (A, B, ..., I).
  • Columns are denoted by numbers (0, 1, ... , 8).
  • To depict an uncovered tile (OPEN) of type mine (Mine) we can use the X character.
  • To depict a tile in state OPEN of type help (Clue), we use a number representing the tile value.
  • To depict a marked tile (MARKED) we can use the M character.
  • To depict an unmarked tile (CLOSED) we can use the - character.

Fig. 1

In case of tiled games, we recommend proceeding similarly, i.e. to define the way the game field is represented (a two-dimensional array in a matrix, one-dimensional array printed horizontally or vertically, for card games the card layout according to players' positions or other game rules). The next step is to code individual tiles (or cards) by letters or special characters similarly to the Minesweeper game: M, -, and numbers for clues.

The data for displaying individual tiles can be retrieved from the game logic (in our example it's the instance of class Field).

Task 2.1

Implement printing out the game field in method void show() in class ConsoleUI.

Comment

To print formatted output (e.g. when displaying the line and column legends), you can use the System.out.printf(...) method, which can format the output to a predefined number of characters, e.g.: System.out.printf("%3d", 4) prints the number 4 with the width of 3 characters. Lookup the method in Javadoc for more info.

Comment

To get the text representation of instances of individual classes (e.g. Mine and Clue), override the standard method toString() in those classes. For example:

public class Mine {
    @Override
    public String toString() {
        return "X";
    }
}

Step 3

Task 3.1

Implement the method handleInput() in class ConsoleUI that serves for processing the user input.

In game Minesweeper the method handleInput() performs the following actions:

  • Prints the request for entering the input, also showing the pattern of expected input format: X – end the game, MA1 – mark tile in row A and column 1, OB4 – open tile in row B and column 4.
  • Loads the input from the user (nextLine()).
  • Verifies the correctness of the input string using conditions and regular expressions.
  • In case of user-entered input in an incorrect format, asks the user to enter the input again.
  • Performs corresponding operation (marking a tile, opening a tile, ending the program) according to identified user action.

Comment

To define the input pattern using a regular expression, create new instance of class Pattern (e.g.. static method Pattern.compile("O([A-I])([0-8])") for the input in format OA9 to open a tile). To check whether the user-entered input is consistent with the pattern, use object of class Matcher. Object of this class can be obtained using the Matcher matcher(CharSequence input) method of the Pattern instance. To verify the input, use methods boolean matches() and String group(int group) defined in class Matcher.

Step 4

Task 4.1

Upload (commit and push) your implementation into your repository on GitLab. You can update the project as you gradually work on it. Before the next exercise, make sure you uploaded your latest work into your repository. Also, prepare questions that you would like to discuss on the next exercise.

Additional Tasks

Task A.1

To enhance usability of the game, accept the user input both in uppercase and lowercase (e.g. in game Minesweeper it will mean both oa9 and OA9).

Task A.2

Implement the support for starting a new game after winning or losing:

Congratulations, you won!
Do you wish to start a new game (Y/N)? _

Resources

  1. Java Tutorial aimed at regular expressions