3. New model โ
INFO
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
and apply_
.
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 โ
TIP
The model_wrap
function of model_wrap.py
returns the structure expected by the new_model
entrypoint.
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? โ
WARNING
You should never use blockchain operations instructions inside your lambda.
The complete list of instructions is available in the Michelson Reference. It includes:
AMOUNT
, BALANCE
, CONTRACT
, CREATE_CONTRACT
, IMPLICIT_ACCOUNT
, LEVEL
, NOW
, SELF
, SELF_ADDRESS
, SENDER
, SET_DELEGATE
, SOURCE
, TOTAL_VOTING_POWER
, TRANSFER_TOKENS
, VOTING_POWER
.
You should never accept a game with a model that contains one of these instructions. More explanations here
Model class โ
A model is a python class that defines the following attributes:
name
: A string with the name of the modelt_init_input
: SmartPy type of the parameter ofinit
t_game_state
: SmartPy type of the game statet_move_data
: SmartPy type of the parameter of a play movet_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 โ
model_wrap
from 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.
model_wrap
automatically
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 โ
The init
lambda takes one parameter of the type defined in t_init_input
.
It returns (by calling sp.result
) a game state of the type defined in t_game_state
.
apply_
lambda โ
The apply_
lambda takes 4 parameters:
move_data
of type t_move defined in t_move_datamove_nb
of type nat: the id of the current moveplayer
of type int: the id of the current playerstate
of type defined in t_game_state
It returns (by calling sp.result
) a pair of
new_state
of type defined in t_game_stateoutcome
(see outcomes)
INFO
The outcome returned by apply_
is surrounded by sp.bounded
because model_wrap.py
verifies that it is listed in self.t_outcome
.
Example โ
Example with the simplest model: transfer.py
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 โ
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 permissions โ
Models can have permissions to mint platform tokens. see tokens