3. New model
This step is optional. It is only needed if you want to define a new game with new rules. To get started, it may be easier to use one of the pre-defined example models.
A model is a piece of code that determine the rules of a game. They consist of two lambdas:
init takes a set of parameters and returns the initial state of the game.
apply_ takes a current state, a move, and a current state metadata. It returns a new state and, if the game is finished, an outcome. The outcome can be mapped to a settlement, using a list defined at game creation.
Push a new model on the platform
model_wrap function of
model_wrap.py returns the structure expected by the
Click me to view the code
import smartpy as sp gp = sp.io.import_template("state_channel_games/game_platform.py") Tictactoe = sp.io.import_template("state_channel_games/models/tictactoe.py").Tictactoe model_wrap = sp.io.import_template("state_channel_games/model_wrap.py").model_wrap @sp.add_test(name="New Model") def test(): sc = sp.test_scenario() player1 = sp.test_account("player1") platform_address = sp.address('KT1_ADDRESS_OF_THE_PLATFORM'), platform = gp.GamePlatform(admins = sp.set([player1.address]), self_addr = platform_address) sc += platform # New Model tictactoe = Tictactoe() model = sc.compute(model_wrap.model_wrap(tictactoe)) model_id = sc.compute(model_wrap.model_id(model)) platform.new_model(model).run(sender = player1.address)
Compute the model_id
The model_id is a
BLAKE2B hash of the parameters
model given to new_model.
import smartpy as sp model_wrap = sp.io.import_template("state_channel_games/model_wrap.py").model_wrap Tictactoe = sp.io.import_template("state_channel_games/models/tictactoe.py").Tictactoe tictactoe = Tictactoe() model = sc.compute(model_wrap.model_wrap(tictactoe)) model_id = sc.compute(model_wrap.model_id(model))
How to code the model?
You should never use blockchain operations instructions inside your lambda.
The complete list of instructions is available in the Michelson Reference. It includes:
You should never accept a game with a model that contains one of these instructions. More explanations here
A model is a python class that defines the following attributes:
name: A string with the name of the model
t_init_input: SmartPy type of the parameter of
t_game_state: SmartPy type of the game state
t_move_data: SmartPy type of the parameter of a play move
t_outcome: list of the model outcomes
And two methods:
apply_: How the game acts after a play move`
init: How the game is initialized
@sp.entrypoint def admin_new_model(self, metadata, model, permissions, rewards): # The metadata of the model. sp.set_type(metadata, sp.TMap(sp.TString, sp.TBytes)) # The model sp.set_type(model, sp.TBytes) # Model's permissions sp.set_type(permissions, sp.TMap(sp.TString, sp.TBytes)) # A list of transfers from the platform to reward the creators of the model. sp.set_type(rewards, sp.TList(sp.TRecord( amount=sp.TNat, to_=sp.TAddress, token_id=sp.TNat).layout(('to_', ('token_id', 'amount')))) )
class MyModel: def __init__(self): # Name of the model # Example: "Tictactoe" self.name = ... # Type of the unpacked `model_init` params # Example: sp.TUnit self.t_initial_config = ... # Type of the unpacked game state # Example: sp.TMap(sp.TInt, sp.TMap(sp.TInt, sp.TInt)) self.t_game_state = ... # Type of the unpacked `mode_data` # Example: sp.TRecord(i=sp.TInt, j=sp.TInt) self.t_move_data = # List of possible outcomes # Example: ["draw", "player_1_won", "player_2_won"] self.t_outcome = ... def model_init(self, params): """The lambda that will be called when instantiating a new game.""" sp.set_type(params, sp.TBytes) # The game params # The initial state computation and checks sp.result(sp.pack(...)) # The game's initial state def model_apply(self, apply_input): """The lambda that will be called every time someone is playing.""" sp.set_type(apply_input, sp.TRecord( move_data=sp.TBytes, # Move data given to the model move_nb=sp.TNat, # Incremental id of the move. (Managed by the platform.) player=sp.TNat, # Id of the current player. (Managed by the platform) state=sp.TBytes, # Current state of the game. (Last state returned by the model) )) # A new state computed from inputs. result = ... sp.result(sp.set_type_expr(result, sp.TPair( sp.TBytes, # New state of the game # Outcome: If `None`, the game continues. # Otherwise the game ends with the given outcome. sp.TOption(sp.TString), ) ))
model_wrap.py is a helper that takes an instance of your class and returns a record that you can give to the new_model entrypoint.
packs and unpacks your inputs and outputs. So the game platform only stores bytes.
The gameTester let you test your model without the wrapping process and channels complexity. :::
init lambda takes one parameter of the type defined in
It returns (by calling
sp.result) a game state of the type defined in
apply_ lambda takes 4 parameters:
move_dataof type t_move defined in t_move_data
move_nbof type nat: the id of the current move
playerof type int: the id of the current player
stateof type defined in t_game_state
It returns (by calling
sp.result) a pair of
new_stateof type defined in t_game_state
The outcome returned by
apply_ is surrounded by
model_wrap.py verifies that it is listed in
Example with the simplest model:
import smartpy as sp class Transfer: def __init__(self): self.name = "Transfer" self.t_init_input = sp.TUnit self.t_game_state = sp.TUnit self.t_move_data = sp.TUnit self.t_outcome = ["transferred"] def apply_(self, move_data, move_nb, player, state): sp.result( sp.pair( sp.unit, sp.some(sp.bounded("transferred")) ) ) def init(self, params): sp.result(sp.unit)
The rest is SmartPy code that you can learn and try on SmartPy.io.
We've build a lot of models that can be used as examples. Also, you can always contact us on Telegram
Game tester is a little platform that let you test your models in a simple environment. Examples of its usage can be found in the tictactoe template
Models can have permissions to mint platform tokens. see tokens