Tracking the state of the Ludo game play
TL;DR
We add various examples to test the progress of a game.
Tracking the state of the game play
The game should always report the state of the game play (Player X rolls the die; Play X moves token Y or Z; Player X has won).
For this, the game needs to know if the Die has been rolled since the last move or not. It therefore also needs to subscribe to rolls of the die.
We start to prepare examples to track the game state.
emptyGame <gtExample> | game | game := self gameClass new. self assert: game isOver not. self assert: game winner equals: 'No one'. self assert: game currentPlayer name equals: 'A'. self assert: game playerToRoll. self assert: game playerToMove not. ^ game
We add a slot needToRollDie
and update it after a move, and after a roll of the die, using the GtLudoGame>>#requireDieRoll
method.
(Browse the senders of
requireDieRoll
.)
We prepare several more examples.
Player A rolls a 6.
playerArolls6 <gtExample> | game | game := self emptyGame. game roll: 6. self assert: game currentPlayer name equals: 'A'. self assert: game playerToRoll not. self assert: game playerToMove. self assert: (game tokensToMove collect: #name) asSet equals: { 'A'. 'a' } asSet. ^ game
Player A enters its token A.
playerAentersTokenA "Setup for 2. Entering play when there is a token of the same player on the start square (ie after rolling a 6 twice)." <gtExample> | game | game := self playerArolls6. game moveTokenNamed: 'A'. self assert: (game positionOfTokenNamed: 'A') equals: 1. self assert: game currentPlayer name equals: 'A'. self assert: game playerToRoll. self assert: game playerToMove not. self assert: (game tokensToMove collect: #name) asSet equals: Set new. ^ game
Player A moves its token A.
playerAmovesTokenA <gtExample> | game | game := self playerAentersTokenA. game roll: 5. self assert: (game tokensToMove collect: #name) asSet equals: { 'A' } asSet. game moveTokenNamed: 'A'. self assert: (game positionOfTokenNamed: 'A') equals: 6. self assert: game currentPlayer name equals: 'B'. self assert: game playerToRoll. self assert: game playerToMove not. self assert: (game tokensToMove collect: #name) asSet equals: Set new. ^ game
And so on.
Different routes for each player
To compute the moves it is useful to have the differents routes for each of the player's tokens, since they start and end on different squares. We add a suitable test to the empty board game.
emptyBoard <gtExample> | board | board := GtLudoGame new. self assert: board players size equals: 4. self assert: board squares size equals: 40. self assert: board tokens size equals: 8. board tokens do: [ :token | self assert: token isInStartState ]. board squares do: [ :square | self assert: square isEmpty ]. board players do: [ :player | | route | route := board routeFor: player. self assert: route size equals: 42. self assert: route first kind equals: #initial. self assert: route last kind equals: #goal. self assert: route nextToLast kind equals: #goal ]. ^ board
We can also inspect the route for a given player. Here is the route for player B:
board := GtLudoBoardExamples new boardWith2PlayingPlayers. board routeFor: board players second
Now that we have implemented GtLudoGame>>#computeTargetFor:
and GtLudoGame>>#moveToken:
, we can actually play the game by clicking on the die and sending move:
messages.
GtLudoGameExamples new playerAmovesTokenA
Clicking to move a token
When we double-click on a square (element) we ask the square to announce to the game the interest in moving the token occupying that square (if there is one). Here we can click on either A or a.