├── .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 | [//]: # (
)
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 |
--------------------------------------------------------------------------------