In this example, we show how to implement a simple Tic Tac Toe game in a coin set model with Chialisp on Chia Blockchain.
x | o | x x | o | x
---+---+--- ---+---+---
| o | x => | o | x
---+---+--- ---+---+---
| | x | |
Like the counter example, this example demonstrates the following Chia concepts and design patterns:
Outer and Inner Puzzle is a very powerful design pattern as it promotes good software engineering practices such as separation of concerns, composition, and unit testings.
For example, singleton top layer puzzle only concerns about maintaining singleton rules while the tic tac toe coin puzzle doesn't need to know if it's wrapped inside the singleton top layer or not.
The tic tac toe puzzle doesn't need to know if it's stand alone puzzle or if it's wrapped inside any puzzle.
We inject different terminate game puzzle to control how tic tac toe coin output the conditions. For example, the tic tac toe coin that will be wrapped inside the singleton top layer puzzle require
CREATE_COIN 0x... -113
to melt the singleton coin.
This is also similar to Dependency injection design pattern.
+---------------------+
| singleton top layer |
|-+-------------------+
| | tic tac toe coin |
| |-+-----------------+
| | | tic tac toe |
| | | terminate game |
+---------------------+
2. Currying
Currying allows us to customize the puzzle to be reused in different siutation.
Since Chialisp is a pure functional programming language, it only relies on input for its environment.
Current board and next player (
x
oro
) are curried in as a current state and playing the game only requires position.
; BOARD : current tic tac toe board state (curried)
; V : x or o to be played (curried)
; pos : position to be played
(mod (BOARD V pos)
(include tic-tac-toe.clib)
(defun play (new_board V)
(list
(check-board new_board V)
new_board
)
)
; 1. get new board
; 2. return the play result and new board
(play (get-new-board BOARD V pos) V)
)
We can also curry the curried puzzle to create a next puzzle and calculate its puzzle hash.
(create-new-coin
; puzzle_hash
(sha256tree
(curry
MOD
(list
MOD
TERMINATE_PUZZLE
(list PLAYER_ONE_PK PLAYER_ONE_HASH)
(list PLAYER_TWO_PK PLAYER_TWO_HASH)
(curry
tic_tac_toe_puzzle
(list
next_board
next_player
)
)
AMOUNT
)
)
)
AMOUNT
)
From the curried puzzle (
puzzle_reveal
is available on blockchain once the coin is spent), we could extract the curried values representing state that we want.
(defun-inline get-player-from-curried-tic-tac-toe-puzzle (curried_puzzle)
(r (f (r (f (r (r (f (r (r curried_puzzle)))))))))
)
def get_curried_puzzle_from_curried_coin_puzzle(curried_coin_puzzle):
return curried_coin_puzzle.at("rrfrrfrrfrrfrrfrfr")
def get_board_from_curried_puzzle(curried_puzzle):
board_from_puzzle = curried_puzzle.at("rrfrfr").as_atom_list()
board_from_puzzle = list(
map(lambda b: int.from_bytes(b, "little"), board_from_puzzle)
)
return board_from_puzzle
def get_player_from_curried_puzzle(curried_puzzle):
player = curried_puzzle.at("rrfrrfrfr").as_int()
return chr(player)
4. Aggregated Signature (AGG_SIG_ME
)
To create a two player game, we want two players to spend their standard coins to create one tic tac toe coin.
Both coins have to be spent at the same time, so we put them in one spend bundle.
Each player can provide his/her signature to allow their coins to be spent, and we can aggregate them into the spend bundle.
coin_message = (
std_hash(int_to_bytes(position))
+ tic_tac_toe_coin.name()
+ DEFAULT_CONSTANTS.AGG_SIG_ME_ADDITIONAL_DATA
)
# sign with sk
signature: G2Element = AugSchemeMPL.sign(
sk,
coin_message
)
coin_spend = CoinSpend(
tic_tac_toe_coin,
curried_coin_puzzle,
Program.to([position]) # position
)
# aggregate alice and bob's signatures
agg_sig = AugSchemeMPL.aggregate([alice_signature, bob_signature])
spend_bundle = SpendBundle(
[alice_coin_spend, bob_coin_spend], # coin spends
agg_sig # aggregated signature
)
6. Singleton
Singleton is another important design pattern allowing coin set model to implement a coin and puzzle with unique identifier (launcher id).
The unique id allows us to access the on-going game (stored in coin).
The singleton puzzle guarantees that there is only one valid coin representing the individual game.
Each notebooks show how each puzzle work.