Implement the classic game of Tic Tac Toe on the Lightpad Block.
Launch the BLOCKS CODE application and open the script called TicTacToe.littlefoot
. You can find the script in the littlefoot/scripts/Example Scripts
folder. If you don't have the BLOCKS CODE IDE installed on your system, please refer to the section Getting started with BLOCKS CODE for help.
Let's start by defining global variables to save the current state of the game. To define global variables in LittleFoot simply place your variables outside any function declaration and at the top of the file for convenience. We first have 9 variables for the state of each cell in the grid, a currentTurn
variable for the current player's turn and a winner
variable to determine which player is the winner.
The initialise() function in the littlefoot language is useful to initialise variables and the state of your script as the function is called once when the program is loaded onto the device. Here we set all the cells to 0, a number chosen to define the blank state of a cell, the current turn to player 1 and the winner to 0, again a number chosen to define the ongoing state of the game.
In the repaint() function, we first clear the display as usual and check if a winner has been selected. If not, this means the game is still ongoing and we proceed to draw a grid and signs if there are any. Otherwise we draw the winner screen.
In order to draw the default grid, we have created a helper function called drawGrid() which is called in the previously defined repaint() function. We first define a variable to the colour white and proceed to draw a rectangle if the cell is still unoccupied.
This is performed on each cell using the helper function drawRect() defined below which takes as argument a colour, the coordinates and the size of the rectangle.
Notice here we use the built-in fillRect() function with either a width or height of 1 to draw lines for the four sides of the rectangle because we don't want the rectangle to be filled.
Now let's see how we can draw the player signs if any of the cells are occupied. The drawSigns() function called in the repaint() loop checks every cell using the evaluate() helper function defined after. It passes the cell variables along with the coordinates in case we need to draw the signs.
The evaluate() function below checks if the cell variable has been switched to a player index of 1 or 2 in which case we need to draw the corresponding player sign. If the cell variable is still set to 0 this means that the cell is still blank and we keep the white default square.
To draw player 1's "X" sign, we first define the player colour and draw each point in the two diagonals as follows:
To draw player 2's "O" sign, we first define the player colour and draw the four sides like so:
In its current implementation state, our script won't receive any touch events and therefore the game will stay in the blank state with a white grid showing. Let's implement the touchStart() callback to receive player moves.
In the above function, we first convert the device coordinates into LED grid coordinates by multiplying both x and y variables by 7. Device coordinates are defined using the number of DNA connectors on the side of the device so for example in the case of a Lightpad Block, the device has a size of 2x2 and therefore the device coordinates will range from 0.0 to 2.0 on each x and y dimensions. Multiplying this range by 7 gives us the LED grid coordinates ranging from 0 to 14 inclusive.
Now using these grid coordinates, we use the getIndex()
helper function defined below to retrieve the cell index ranging from 0 to 8 from our 3x3 game grid.
When the index is retrieved we attempt to set a cell variable value only if the touched cell is unoccupied. If a value has been successfully set for the current player, the function returns true and the currentTurn
variable is switched to the other player.
We were able to implement the basic gameplay but we don't have a mechanism to select a winner yet. As a last step to the touchStart() callback, we check if a winner has been selected by calling respectively the xHasWon()
and oHasWon()
helper functions defined as follows:
These in turn call the hasWon()
function with the player number which checks all 8 possible combination of winning lines (3 horizontal, 3 vertical and 2 diagonal).
If a winner is selected the repaint() function will call the drawWinner()
function defined below and fill the screen with the appropriate winner's colour:
As a final step we can implement a simple way to reset the game back to the beginning by calling the initialise() function ourselves when the side button of the device is pressed. This is achieved by implementing the handleButtonDown() callback function like this:
In this example, we learnt how to recreate the classic game of Tic Tac Toe on the Lightpad Block.