Skip to main content

Overview

The Tic-Tac-Toe example demonstrates how to implement game logic in Leo using structs, conditional statements, and helper functions. This example showcases state representation, input validation, and win condition checking.
This example is located at .circleci/tictactoe/ in the Leo repository and is actively tested in CI.

Program Structure

Data Structures

Row Struct

Represents a single row in the game board:
Valid Values:
  • 0u8: Empty cell
  • 1u8: Player 1’s mark
  • 2u8: Player 2’s mark
Any value other than 0, 1, or 2 is invalid and will cause incorrect game logic.

Board Struct

Represents the complete game board:
Visual Representation:

Why Not Arrays?

Leo could represent the board as [[u8; 3]; 3], but this example uses structs to demonstrate:
  • Custom type definitions
  • Named field access
  • Struct initialization
  • Nested struct composition
Arrays would be more concise, but structs provide better readability for educational purposes.

Core Functions

Creating a New Game

Returns: An empty 3x3 board with all cells initialized to 0u8. Usage:
Output:

Making a Move

Parameters:
  • player: The player making the move (1 or 2)
  • row: The row (1, 2, or 3)
  • col: The column (1, 2, or 3)
  • board: The current game board
Returns:
  • Board: The updated game board
  • u8: Winner (1 or 2) or 0 if no winner yet
Key Features:

Input Validation

Ensures:
  • Player is either 1 or 2
  • Row is between 1 and 3
  • Column is between 1 and 3

Move Validation

Only updates the cell if:
  • The target cell matches the row/col parameters
  • The cell is empty (== 0u8)
If the cell is already occupied, the board is returned unchanged (the move is silently ignored).

Helper Functions

Checking for a Winner

Parameters:
  • b: The game board to check
  • p: The player to check for (1 or 2)
Returns: true if the player has won, false otherwise Win Conditions:
  • Three in a row (horizontally)
  • Three in a column (vertically)
  • Three in a diagonal
There’s a bug in the original code! Line 105 checks b.r3.c3 twice instead of b.r3.c2 for row 3. This is preserved from the actual source code.

Playing the Game

Step 1: Create a New Board

Output:

Step 2: Player 1 Makes a Move

Output:

Step 3: Player 2 Makes a Move

Output:

Continue Until Win

Keep making moves until one player wins:

Running the Demo

Use the Run Script

This script plays through a complete game.

Build the Program

View Generated Code

Key Language Features

Struct Initialization

Field Access

Conditional Logic

Early Return

Leo supports early returns from functions using the return keyword.

Helper Functions

Helper functions improve code organization and readability.

Improvements and Extensions

Add Draw Detection

Use Records for Private Games

This would allow private games where the board state is hidden.

Add Turn Validation

Store Games On-Chain

Testing

Create Test Inputs

Create inputs/tictactoe.in:

Run Tests

Token

More complex example with records and mappings

Lottery

Simpler example with randomness

Further Reading

Data Types

Learn more about structs and data types

Functions

Function documentation

Statements

Control flow guide

Built-in Types

Type reference