├── .gitignore ├── program.json ├── inputs └── tictactoe.in ├── README.md ├── src └── main.leo └── run.sh /.gitignore: -------------------------------------------------------------------------------- 1 | .env 2 | *.avm 3 | *.prover 4 | *.verifier 5 | outputs/ 6 | -------------------------------------------------------------------------------- /program.json: -------------------------------------------------------------------------------- 1 | { 2 | "program": "tictactoe.aleo", 3 | "version": "0.0.0", 4 | "description": "", 5 | "license": "MIT" 6 | } 7 | -------------------------------------------------------------------------------- /inputs/tictactoe.in: -------------------------------------------------------------------------------- 1 | // The `new` function does not take any inputs. 2 | [new] 3 | 4 | // Inputs for the `make_move` function. 5 | // - `player` : A u8 representing the player making the move. 1 for player 1, 2 for player 2. 6 | // - `row` : A u8 representing the row to make the move in. 7 | // - `column` : A u8 representing the column to make the move in. 8 | // - `board` : A representation of the board state. 9 | [make_move] 10 | player: u8 = 1u8; 11 | row: u8 = 1u8; 12 | col: u8 = 1u8; 13 | board: Board = Board { 14 | r1: Row { c1: 0u8, c2: 0u8, c3: 0u8 }, 15 | r2: Row { c1: 0u8, c2: 0u8, c3: 0u8 }, 16 | r3: Row { c1: 0u8, c2: 0u8, c3: 0u8 }, 17 | }; 18 | 19 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | [//]: # (workshop/tictactoe) 4 | 5 | A standard game of Tic-Tac-Toe in Leo. 6 | 7 | ⭕ ❕ ⭕ ❕ ❌ 8 | 9 | ➖ ➕ ➖ ➕ ➖ 10 | 11 | ⭕ ❕ ⁣❌ ❕ ⭕ 12 | 13 | ➖ ➕ ➖ ➕ ➖ 14 | 15 | ❌ ❕ ❌ ❕ ⭕ 16 | 17 | ## Representing State 18 | Leo allows users to define composite data types with the `struct` keyword. 19 | The game board is represented by a struct called `Board`, which contains three `Row`s. 20 | An alternative representation would be to use an array, however, these are not yet supported in Leo. 21 | 22 | ## Language Features 23 | - `struct` declarations 24 | - conditional statements 25 | - early termination. Leo allows users to return from a function early using the `return` keyword. 26 | 27 | ## Running the Program 28 | 29 | Leo provides users with a command line interface for compiling and running Leo programs. 30 | Users may either specify input values via the command line or provide an input file in `inputs/`. 31 | 32 | ### Providing inputs via the command line. 33 | 1. Run 34 | ```bash 35 | leo run ... 36 | ``` 37 | See `./run.sh` for an example. 38 | 39 | 40 | ### Using an input file. 41 | 1. Modify `inputs/tictactoe.in` with the desired inputs. 42 | 2. Run 43 | ```bash 44 | leo run 45 | ``` 46 | 47 | ## Executing the Program 48 | ```bash 49 | leo execute ... 50 | ``` 51 | 52 | ## Playing the Game 53 | 54 | ### 1. Create a new game board 55 | ```bash 56 | leo run new 57 | ``` 58 | | | | | 59 | |---|---|---| 60 | | 0 | 0 | 0 | 61 | | 0 | 0 | 0 | 62 | | 0 | 0 | 0 | 63 | 64 | ### 2. Player 1 makes a move 65 | ```bash 66 | leo run make_move 1u8 1u8 1u8 "{ r1: { c1: 0u8, c2: 0u8, c3: 0u8 }, r2: { c1: 0u8, c2: 0u8, c3: 0u8 }, r3: { c1: 0u8, c2: 0u8, c3: 0u8 } }" 67 | ``` 68 | | | | | 69 | |---|---|---| 70 | | 1 | 0 | 0 | 71 | | 0 | 0 | 0 | 72 | | 0 | 0 | 0 | 73 | 74 | ### 3. Player 2 makes a move 75 | ```bash 76 | leo run make_move 2u8 2u8 2u8 "{ r1: { c1: 1u8, c2: 0u8, c3: 0u8 }, r2: { c1: 0u8, c2: 0u8, c3: 0u8 }, r3: { c1: 0u8, c2: 0u8, c3: 0u8 } }" 77 | ``` 78 | | | | | 79 | |---|---|---| 80 | | 1 | 0 | 0 | 81 | | 0 | 2 | 0 | 82 | | 0 | 0 | 0 | 83 | -------------------------------------------------------------------------------- /src/main.leo: -------------------------------------------------------------------------------- 1 | program tictactoe.aleo { 2 | // A row in a tic tac toe board. 3 | // - `c1` : The first entry in the row. 4 | // - `c2` : The second entry in the row. 5 | // - `c3` : The third entry in the row. 6 | // A valid entry is either 0, 1, or 2, where 0 is empty, 1 corresponds to player 1, and 2 corresponds to player 2. 7 | // Any other values are invalid. 8 | struct Row { 9 | c1: u8, 10 | c2: u8, 11 | c3: u8 12 | } 13 | 14 | // A tic tac toe board. 15 | // - `r1` : The first row in the board. 16 | // - `r2` : The second row in the board. 17 | // - `r3` : The third row in the board. 18 | struct Board { 19 | r1: Row, 20 | r2: Row, 21 | r3: Row, 22 | } 23 | 24 | // Returns an empty board. 25 | transition new() -> Board { 26 | return Board { 27 | r1: Row { c1: 0u8, c2: 0u8, c3: 0u8 }, 28 | r2: Row { c1: 0u8, c2: 0u8, c3: 0u8 }, 29 | r3: Row { c1: 0u8, c2: 0u8, c3: 0u8 }, 30 | }; 31 | } 32 | 33 | // Returns `true` if there exists a row, column, or diagonal with all entries occupied by the same player. 34 | // - `b` : A tic tac toe board. 35 | // - `p` : A number corresponding to a player. 36 | function check_for_win(b: Board, p: u8) -> bool { 37 | return 38 | (b.r1.c1 == p && b.r1.c2 == p && b.r1.c3 == p) || // row 1 39 | (b.r2.c1 == p && b.r2.c2 == p && b.r2.c3 == p) || // row 2 40 | (b.r3.c1 == p && b.r3.c3 == p && b.r3.c3 == p) || // row 3 41 | (b.r1.c1 == p && b.r2.c1 == p && b.r3.c1 == p) || // column 1 42 | (b.r1.c2 == p && b.r2.c3 == p && b.r3.c2 == p) || // column 2 43 | (b.r1.c3 == p && b.r2.c3 == p && b.r3.c3 == p) || // column 3 44 | (b.r1.c1 == p && b.r2.c2 == p && b.r3.c3 == p) || // diagonal 45 | (b.r1.c3 == p && b.r2.c2 == p && b.r3.c1 == p); // other diagonal 46 | } 47 | 48 | // Returns an updated tic tac toe board with a move made by a player. 49 | // Returns a `u8` corresponding to the player who won the game, or 0 if no one has won yet. 50 | // - `player` : A number corresponding to a player. 51 | // - `row` : The row of the move. 52 | // - `col` : The column of the move. 53 | // - `board` : A tic tac toe board. 54 | // Assumes that `player` is either 1 or 2. 55 | // Assumes that `row` and `col` are valid indices into the board. 56 | // If an entry is already occupied, the move is invalid and the board is returned unchanged. 57 | transition make_move(player: u8, row: u8, col: u8, board: Board) -> (Board, u8) { 58 | // Check that inputs are valid. 59 | assert(player == 1u8 || player == 2u8); 60 | assert(1u8 <= row && row <= 3u8); 61 | assert(1u8 <= col && col <= 3u8); 62 | 63 | // Unpack the entries in the board into variables. 64 | let r1c1: u8 = board.r1.c1; 65 | let r1c2: u8 = board.r1.c2; 66 | let r1c3: u8 = board.r1.c3; 67 | let r2c1: u8 = board.r2.c1; 68 | let r2c2: u8 = board.r2.c2; 69 | let r2c3: u8 = board.r2.c3; 70 | let r3c1: u8 = board.r3.c1; 71 | let r3c2: u8 = board.r3.c2; 72 | let r3c3: u8 = board.r3.c3; 73 | 74 | // Update the appropriate entry with the given move. 75 | if row == 1u8 && col == 1u8 && r1c1 == 0u8 { 76 | r1c1 = player; 77 | } else if row == 1u8 && col == 2u8 && r1c2 == 0u8 { 78 | r1c2 = player; 79 | } else if row == 1u8 && col == 3u8 && r1c3 == 0u8 { 80 | r1c3 = player; 81 | } else if row == 2u8 && col == 1u8 && r2c1 == 0u8 { 82 | r2c1 = player; 83 | } else if row == 2u8 && col == 2u8 && r2c2 == 0u8 { 84 | r2c2 = player; 85 | } else if row == 2u8 && col == 3u8 && r2c3 == 0u8 { 86 | r2c3 = player; 87 | } else if row == 3u8 && col == 1u8 && r3c1 == 0u8 { 88 | r3c1 = player; 89 | } else if row == 3u8 && col == 2u8 && r3c2 == 0u8 { 90 | r3c2 = player; 91 | } else if row == 3u8 && col == 3u8 && r3c3 == 0u8 { 92 | r3c3 = player; 93 | } 94 | 95 | // Construct the updated game board. 96 | let updated: Board = Board { 97 | r1: Row { c1: r1c1, c2: r1c2, c3: r1c3 }, 98 | r2: Row { c1: r2c1, c2: r2c2, c3: r2c3 }, 99 | r3: Row { c1: r3c1, c2: r3c2, c3: r3c3 }, 100 | }; 101 | 102 | // Check if the game is over. 103 | if check_for_win(updated, 1u8) { 104 | return (updated, 1u8); 105 | } else if check_for_win(updated, 2u8) { 106 | return (updated, 2u8); 107 | } else { 108 | return (updated, 0u8); 109 | } 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # First check that Leo is installed. 3 | if ! command -v leo &> /dev/null 4 | then 5 | echo "leo is not installed." 6 | exit 7 | fi 8 | # Create a new game. 9 | echo " 10 | ############################################################################### 11 | ######## ######## 12 | ######## STEP 0: Creating a new game of Tic-Tac-Toe ######## 13 | ######## ######## 14 | ######## | | | | ######## 15 | ######## | | | | ######## 16 | ######## | | | | ######## 17 | ######## ######## 18 | ############################################################################### 19 | " 20 | leo run new || exit 21 | 22 | # Have the Player 1 make a move. 23 | echo " 24 | ############################################################################### 25 | ######## ######## 26 | ######## STEP 1: Player 1 makes the 1st move. ######## 27 | ######## ######## 28 | ######## | x | | | ######## 29 | ######## | | | | ######## 30 | ######## | | | | ######## 31 | ######## ######## 32 | ############################################################################### 33 | " 34 | leo run make_move 1u8 1u8 1u8 "{ r1: { c1: 0u8, c2: 0u8, c3: 0u8 }, r2: { c1: 0u8, c2: 0u8, c3: 0u8 }, r3: { c1: 0u8, c2: 0u8, c3: 0u8 } }" || exit 35 | 36 | # Have the Player 2 make a move. 37 | echo " 38 | ############################################################################### 39 | ######## ######## 40 | ######## STEP 2: Player 2 makes the 2nd move. ######## 41 | ######## ######## 42 | ######## | x | | | ######## 43 | ######## | | o | | ######## 44 | ######## | | | | ######## 45 | ######## ######## 46 | ############################################################################### 47 | " 48 | leo run make_move 2u8 2u8 2u8 "{ r1: { c1: 1u8, c2: 0u8, c3: 0u8 }, r2: { c1: 0u8, c2: 0u8, c3: 0u8 }, r3: { c1: 0u8, c2: 0u8, c3: 0u8 } }" || exit 49 | 50 | # Have the Player 1 make a move. 51 | echo " 52 | ############################################################################### 53 | ######## ######## 54 | ######## STEP 3: Player 1 makes the 3rd move. ######## 55 | ######## ######## 56 | ######## | x | | | ######## 57 | ######## | | o | | ######## 58 | ######## | x | | | ######## 59 | ######## ######## 60 | ############################################################################### 61 | " 62 | leo run make_move 1u8 3u8 1u8 "{ r1: { c1: 1u8, c2: 0u8, c3: 0u8 }, r2: { c1: 0u8, c2: 2u8, c3: 0u8 }, r3: { c1: 0u8, c2: 0u8, c3: 0u8 } }" || exit 63 | 64 | # Have the Player 2 make a move. 65 | echo " 66 | ############################################################################### 67 | ######## ######## 68 | ######## STEP 4: Player 2 makes the 4th move. ######## 69 | ######## ######## 70 | ######## | x | | | ######## 71 | ######## | o | o | | ######## 72 | ######## | x | | | ######## 73 | ######## ######## 74 | ############################################################################### 75 | " 76 | leo run make_move 2u8 2u8 1u8 "{ r1: { c1: 1u8, c2: 0u8, c3: 0u8 }, r2: { c1: 0u8, c2: 2u8, c3: 0u8 }, r3: { c1: 1u8, c2: 0u8, c3: 0u8 } }" || exit 77 | 78 | # Have the Player 1 make a move. 79 | echo " 80 | ############################################################################### 81 | ######## ######## 82 | ######## STEP 5: Player 1 makes the 5th move. ######## 83 | ######## ######## 84 | ######## | x | | | ######## 85 | ######## | o | o | x | ######## 86 | ######## | x | | | ######## 87 | ######## ######## 88 | ############################################################################### 89 | " 90 | leo run make_move 1u8 2u8 3u8 "{ r1: { c1: 1u8, c2: 0u8, c3: 0u8 }, r2: { c1: 2u8, c2: 2u8, c3: 0u8 }, r3: { c1: 1u8, c2: 0u8, c3: 0u8 } }" || exit 91 | 92 | # Have the Player 2 make a move. 93 | echo " 94 | ############################################################################### 95 | ######## ######## 96 | ######## STEP 6: Player 2 makes the 6th move. ######## 97 | ######## ######## 98 | ######## | x | o | | ######## 99 | ######## | o | o | x | ######## 100 | ######## | x | | | ######## 101 | ######## ######## 102 | ############################################################################### 103 | " 104 | leo run make_move 2u8 1u8 2u8 "{ r1: { c1: 1u8, c2: 0u8, c3: 0u8 }, r2: { c1: 2u8, c2: 2u8, c3: 1u8 }, r3: { c1: 1u8, c2: 0u8, c3: 0u8 } }" || exit 105 | 106 | # Have the Player 1 make a move. 107 | echo " 108 | ############################################################################### 109 | ######## ######## 110 | ######## STEP 7: Player 1 makes the 7th move. ######## 111 | ######## ######## 112 | ######## | x | o | | ######## 113 | ######## | o | o | x | ######## 114 | ######## | x | x | | ######## 115 | ######## ######## 116 | ############################################################################### 117 | " 118 | leo run make_move 1u8 3u8 2u8 "{ r1: { c1: 1u8, c2: 2u8, c3: 0u8 }, r2: { c1: 2u8, c2: 2u8, c3: 1u8 }, r3: { c1: 1u8, c2: 0u8, c3: 0u8 } }" || exit 119 | 120 | # Have the Player 2 make a move. 121 | echo " 122 | ############################################################################### 123 | ######## ######## 124 | ######## STEP 8: Player 2 makes the 8th move. ######## 125 | ######## ######## 126 | ######## | x | o | | ######## 127 | ######## | o | o | x | ######## 128 | ######## | x | x | o | ######## 129 | ######## ######## 130 | ############################################################################### 131 | " 132 | leo run make_move 2u8 3u8 3u8 "{ r1: { c1: 1u8, c2: 2u8, c3: 0u8 }, r2: { c1: 2u8, c2: 2u8, c3: 1u8 }, r3: { c1: 1u8, c2: 1u8, c3: 0u8 } }" || exit 133 | 134 | echo " 135 | ############################################################################### 136 | ######## ######## 137 | ######## STEP 9: Player 1 makes the 9th move. ######## 138 | ######## ######## 139 | ######## | x | o | x | ######## 140 | ######## | o | o | x | ######## 141 | ######## | x | x | o | ######## 142 | ######## ######## 143 | ############################################################################### 144 | " 145 | leo run make_move 1u8 1u8 3u8 "{ r1: { c1: 1u8, c2: 2u8, c3: 0u8 }, r2: { c1: 2u8, c2: 2u8, c3: 1u8 }, r3: { c1: 1u8, c2: 1u8, c3: 2u8 } }" || exit 146 | 147 | echo " 148 | ############################################################################### 149 | ######## ######## 150 | ######## Game Complete! Players 1 & 2 Tied ######## 151 | ######## ######## 152 | ######## | x | o | x | ######## 153 | ######## | o | o | x | ######## 154 | ######## | x | x | o | ######## 155 | ######## ######## 156 | ############################################################################### 157 | " 158 | --------------------------------------------------------------------------------