Creating the Ludo Board view

TL;DR

We implement a visualization of the board state, which will later also serve as a GUI for the game, as well as the basis for other views.

The Board view

Before we implement the game logic, it would be nice to have already a visualization of the Board state. We can lay out 40 squares on an 11x11 grid.

NB: As before we continue to experiment and prototype our ideas as Notebook snippets, while documenting our steps.

Here is a simple experiment showing how we can place squares on arbitrary locations on a board:

container := (BlElement new)
	size: 100 @ 100;
	background: Color blue.
container
	addChild:
		((BlElement new)
			background: Color yellow;
			size: 10 @ 10;
			relocate: 20 @ 30;
			when: BlClickEvent do: [ :event | 
				event currentTarget phlow spawnObject: 42 ]).
container asScalableElement
  

We start building the GtLudoBoardElement BlElement subclass: #GtLudoBoardElement instanceVariableNames: 'feedbackLabel game squares' classVariableNames: '' package: 'GToolkit-Demo-Ludo-UI' class.

We encode magic numbers such as the grid size and the default dimensions as constant methods, GtLudoBoardElement>>#gridSize gridSize ^ 400@400 and GtLudoBoardElement>>#dimensions dimensions "Number of squares per side" ^ 11 @ 11 .

We hard-code the positions of the first ten squares as GtLudoBoardElement>>#playerAPositions playerAPositions "The locations of the first ten squares starting from player A's start square." ^ {1 @ 5. 2 @ 5. 3 @ 5. 4 @ 5. 5 @ 5. 5 @ 4. 5 @ 3. 5 @ 2. 5 @ 1. 6 @ 1} , and then compute the other positions by rotation in GtLudoBoardElement>>#playPositions playPositions "Compute the standard positions of the 40 Ludo squares on an 11x11 board. The positions for player A are pre-computed. Those for the other players are obtained by rotation." | aPositions bPositions cPositions dPositions squarePositions | aPositions := self playerAPositions. bPositions := aPositions collect: [ :p | (12 - p y) @ p x ]. cPositions := aPositions collect: [ :p | 12 @ 12 - p ]. dPositions := bPositions collect: [ :p | 12 @ 12 - p ]. squarePositions := aPositions , bPositions , cPositions , dPositions. self assert: squarePositions size equals: self numberOfSquares. ^ squarePositions .

Here is the visualization of the earlier example:

GtLudoBoardElement for: GtLudoBoardExamples new boardWith2PlayingPlayers  
  

Adding start and goal positions

We also want to display the tokens that are in the start position, or have reached their goal.

We add slots for startSquares and goalSquares to the Board.

We add a kind slot to Squares so we know what kind a given square is.

We extend the BoardElement to display the start and goal squares, and we assign colors to them based on their kind.

Now we can programmatically move a token around the board.

example := GtLudoBoardExamples new boardWith2PlayingPlayers .
board := GtLudoBoardElement for: example 
  

Now by playing with the following snippet we can move the token A around the board:

position := 9.
example players first tokens first goToSquare: (example squares at: position)