Introducing rules to the Ludo Board Game
TL;DR
Now that we have a low-level interface for managing the game state, we start to incrementally introduce the game rules.
Caveat:
Recall that originally we introduced separate GtBoard
and GtGame
classes, where the former managed the game state while the latter implemented the rules of the game. These were later unified into a single GtLudoGame
class. In the text below, we still refer at times to the Game
and the Board
as separate entities, though they are now a single class.
The Board Game
The game offers the high-level interface to the board, and interprets the rules.
It knows which player's turn it is, knows what moves are possible, knows what happens on a move, and knows when the game is over.
A Move consists of (1) the Die being rolled, (2) the current player selecting a token to move.
We can encapsulate a Move as a Die value plus a Token name.
A Move may or may not be valid.
Rules:
If a 6 is rolled, and the player has a token in the start state, it must be put into play. Otherwise a token in play may be moved.
A token that is put into play moves to the start square.
After a 6, the same player can roll again (stays the current player).
If the landing square is occupied, then
(1) if the token belongs to the same player, the token lands on the next square
(2) otherwise if it belongs to another player, that token is sent back to the start position
Let's start with a Game as a holder for a Board.
At first, the board was a slot holding an instance of Board. Later we made the Game a subclass of Board, pushed down or merged all the methods, and eliminated the Board class and the redundant slot.
We add forwarding views for the Board, players and squares.
We keep track of the current player in a rotating collection in GtLudoGame>>#currentPlayer
.
For testing purposes, it is easier if we can explicitly set the value of the Die rolled.
game roll: 6
Now we can start to script some moves.
game := GtLudoGame new.
game roll: 6. game moveTokenNamed: 'A'.
We start to implement the various game rules in the GtLudoGame>>#moveToken:
method. Note that the logic is split into two parts — computing the target square to land on, and deciding what happens when a token lands on that square.
This is by far the most complex method in the whole package, excluding examples.
classes := GtLudoGame package classes removeAll: (GtLudoGame package classTagNamed: 'Examples') classes; yourself. ((classes flatCollect: #methods) asOrderedCollection sort: [ :a :b | a linesOfCode > b linesOfCode ]) copyFrom: 1 to: 10