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
- Implement the game loop in which the game will be running.
- Implement printing of the string representation of the game field.
- 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.).
- printing the text representation of the game field to the output using method
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 theX
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 theM
character. - To depict an unmarked tile (
CLOSED
) we can use the-
character.
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
- Java Tutorial aimed at regular expressions