Ludo Exercise 5
This page transcribes the first of the two Ludo exercises for the Programming 2 course in 2022.
For details, see Implementing a Ludo Game as a moldable development exercise.
In the upcoming exercises, we will implement Man, Don't Get Angry / Mensch ärgere Dich nicht / Ludo (see its Wikipedia article, a simple board game that can be played by up to four people. By applying the concepts that have been covered so far (for example, object-oriented design principles, unit testing, responsibility-driven design), we aim for a well-designed implementation of some basic features in this first exercise. In the second exercise, we will continue to add features until we have a fully functional game. Therefore, building a solid foundation in this exercise will pay off in the long run.
Man, Don't Get Angry / Mensch ärgere Dich nicht / Ludo is a board game that requires at least 2 players.
The board is rectangular with tiles (or squares; we use both terms interchangeably here) that represent paths along which a player has to walk. In a regular game each player would have four pieces/tokens, but in our case there will be only two per player. The goal of the player is to move all their pieces around the board and land at their home tiles. The first player who reaches the home tile with all pieces wins the game.
We use the following rules for our game. If something is unclear or missing, refer to the original rules stated on Wikipedia. However, we will simplify parts of the rules, so that the exercise does not become overwhelming.
The game has four players. For this exercise, you do not need to consider two or three player versions of the game. We will focus on only four player version game.
- Each player starts with two pieces (also called tokens) in one corner, not four as in the original.
- Players move their tokens clockwise along the board.
- Players take turns rolling the die.
- When rolling a six, a player must move a piece on the board onto his starting square (the next
* square). Then the player rolls the die again.
- If the player has rolled a six, but does not have any pieces left to put on the board, he can move any one of his pieces for six squares/tiles. Then he can roll the die again. In general: Every time a person rolls a six, he can roll the die again. If this additional roll is again a six, he places/moves pieces and rolls again, and so on.
- When rolling any other number, any one piece on the route can be moved. However, the die roll cannot be split up among pieces, for example, if the die rolls 5, the player can choose any piece to move for 5 squares. The player cannot move one piece for 2 squares and the other piece for 3 squares.
- When a player's piece lands on a piece of another player, the player's piece that was already there is placed back to their starting square. The players own pieces cannot be reset in such a way, so the move itself will not be executed. It is not possible to have more than one piece on a square/tile. Afterwards, it is the next players turn.
- When approaching the goal, denoted as
$ on the board, one has to roll the exact number required to get onto the target goal tile; otherwise, the player cannot move at all on that round. If one of the goal already occupied, you have to target the next available goal tile. The aim is to land on any free goal tile.
- Players that have multiple tokens in play can choose freely which one to move.
- Should a player's last piece be in front of the home, but he rolls a six, then the move cannot be made. the player cannot roll again, and his turn is ended.
- The player that first fills all his/her goal tiles, wins the game.
Note that you will not have to implement all rules in this exercise yet. However, you may want to keep them in mind when designing and implementing your game basics.
In order to pass this exercise, you need to do the tasks stated here. Note that exercise 6 will build on top of this one. You will have to implement the parts described here in any case.
Before you get started, make sure you understand the game by reading the description of the above-mentioned rules, and clearing up any questions that you might have. Once this is clear, you can start designing and implementing the game.
Task 1: Initialization
In the first task, we implement basic features of the game. In this stage, the game does not have to be playable yet. Instead, you will create the basic classes, properly distribute responsibilities, and test the game setup.
Implement the following.
- the game (bringing it all together, similar to the Snakes & Ladders
You can decide yourself what kinds of classes you will use. However, you need to have at least dedicated classes for board, game, players, tokens, and squares. Add additional classes if required. - Ability to:
- Initialize a new board that places four players in their respective corners, - place player tokens on specific squares, - move tokens along the route.
Note that the last point just means that you can do something like
player.move(token1, 3) (whichever way you choose to distribute the responsbilities), which moves the selected token of a player by 3 steps. You do not have to implement logic that checks, for example, whether the move is valid, whether it is a winning move, etc. It’s just about moving along the route in a
Make sure you follow the principles you have learned so far. You should document your code (e.g., class, method comments) and write tests, apply responsibility-driven design, and use design by contract where appropriate.
Task 2: Rendering the board
A board contains a large amount of information, and your task will be to represent it in a sensible way.
Again, you are free to represent the board however you want. Nevertheless, we provide an example board here that you can choose to use, but you are not obliged to. (In case the board is not displayed properly, check out the file
ludo_board.txt, which contains the same board.)
####--*#### #-$-# B1 A0 #-$-# ####-#-#### *--A-#--aB- -$$#####$$- -----#----* ####-#-#### #-$C# C1 D2 #-$-# ####*--####
In this board, the following symbols are used:
␣ (space): Drawing; these are non-functional and just serve to give a better idea and boundary of the board. The pieces are not supposed to occupy these.
-: Unoccupied square/tile.
*: Starting square of the closest player denotation. (Left is player A, Top is player B, Right is player C, and Bottom is player D)
$: A player's “home road”.
d: Player tokens, so player A's first token is
A, the second is
A2 in the corners (and same for B, C, D): Number of tokens still not on the board. For example,
A2 means that player A does not have any tokens on the board yet.
B1 means that player B has a single token on the board.
C0 means that player C has allhis pieces on the board.
In this iteration, your task is to implement and test a board renderer. To do that, create a class that can render a given board by generating a string representation. This can then be used in tests or printed using
methods (more information on this below).
You should write tests that ensure that your game correctly renders different game configurations, not only the initial state. For example, you should write a test that ensures that tokens are correctly rendered when on a specific tile/square.
Hint: Think about what “units” you are testing. For example, rendering tiles with different things occupying them can be done in isolation, you do not have to test the full board. If rendering individual tiles works, then you can use this in the main board renderer. You should also think about who is responsible for rendering what. Should a single
Renderer class take care of everything? Or should there be, for example, classes like
PlayerRenderer that can be composed?
In order to mark milestones, we will start using git's tag feature. Tags are used to mark important commits with a name, for example, with a version number. The feature is thoroughly documented on git-scm.com.
Use git to create a tag that marks the finished first stage. Here, we will use annotated tags, which you can create as follows.
git tag -a v1 -m "Ludo stage 1"
Task 3: Debugger
As you write your code and perform your magic, you will certainly run into situations where you don't understand your own magic. At that point, please use the debugger. Take screenshots and use them to explain how the debugger can help wizards in need to solve their problems. Create a markdown file named
debugger.md where you embed the images and use proper markdown syntax to format the document as you explain your magic spells that helped you unravel the mysteries of your previous work. The file must contain at least 3 problems that you fixed using the debugger.
Task 4: UML Diagram
Your last task of this exercise is to create a class diagram of the current state of your game. Include all relevant classes including their relations, variables and methods to give an overview of the project. The purpose of the class diagram is to give newcomers to the project a better idea of all the important parts of your game, so a good level of abstraction is key to not litter your diagram with unnecessary details (e.g. private helper methods and so on).
Additionally, the class diagram should help you to plan ahead and give you a better understanding of what and how you want to develop in the next two exercises to complete the game. Read through the Ludo rules and identify the potential remaining classes that you will likely need to implement and add them as well. Identifying their responsibilities now will ease up the process of adding the upcoming features.
Submit the class diagram as either an image or PDF within the exercise folder and name it
- You are free to design the game as you want, but you should follow the design principles that you learned so far. You can take a look at the Snakes and Ladders implementations we provided in exercise 4 to get an idea of how your class structures could look like.
- We added some classes (without implementations) in the template. You can use them, but if you want, you can also modify or change them (or change them into interfaces if necessary).
- You do not have to implement a fully functional game yet! In this exercise, we focus on initialization, rendering, and (very) basic player movement. You do not need to implement any additional game logic.
- Write proper documentation, such as JavaDoc class and method comments.
- Do not forget about design by contract.
- If you are struggling with the exercise, you are not alone. Get help on the ilias forum, during pool hours, or via assistant mailing list.
- Manage your time responsibly. Do not just start the day before the exercise is due.
Do not forget to mention your contributions for the exercise in the
The exercise is due on
Friday, 8 April, 12:00
. Do not forget the
v1 git tag.