Skip to content

Latest commit

 

History

History
204 lines (157 loc) · 7.71 KB

File metadata and controls

204 lines (157 loc) · 7.71 KB

Tic Tac Toe

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 |   |   

Chia Concepts and Design Patterns

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  |
    +---------------------+

singleton-tic-tac-toe

Pre-commit Environment and Store State

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 or o) 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
)

creating-coin

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.

create-singleton

Code

Helpers Code

Notebooks

Each notebooks show how each puzzle work.

  1. tic tac toe
  2. terminate game
  3. tic tac toe coin
  4. tic tac toe coin - blockchain simulator
  5. singleton tic tac toe