Commençons par explorer notre contrat pour le jeu TicTacToe :
Python
# TicTacToe - Exemple à titre d'illustration uniquement.
import smartpy as sp
@sp.module
def main() :
class TicTacToe(sp.Contract) :
def __init__(self) :
self.data.nbMoves = 0
self.data.winner = 0
self.data.draw = False
self.data.deck = {
0 : {0: 0, 1: 0, 2: 0},
1 : {0: 0, 1: 0, 2: 0},
2 : {0: 0, 1: 0, 2: 0},
}
self.data.nextPlayer = 1
@sp.entrypoint
def play(self, params) :
assert self.data.winner == 0 and not self.data.draw
assert params.i >= 0 et params.i < 3
assert params.j >= 0 et params.j < 3
assert params.move == self.data.nextPlayer
assert self.data.deck[params.i][params.j] == 0
self.data.deck[params.i][params.j] = params.move
self.data.nbMoves += 1
self.data.nextPlayer = 3 - self.data.nextPlayer
self.data.winner = self.checkLine(
sp.record(winner=self.data.winner, line=self.data.deck[params.i])
)
self.data.winner = self.checkLine(
sp.record(
winner=self.data.winner,
line={
0: self.data.deck[0][params.j],
1: self.data.deck[1][params.j],
2: self.data.deck[2][params.j],
},
)
)
self.data.winner = self.checkLine(
sp.record(
winner=self.data.winner,
line={
0: self.data.deck[0][0],
1: self.data.deck[1][1],
2: self.data.deck[2][2],
},
)
)
self.data.winner = self.checkLine(
sp.record(
winner=self.data.winner,
line={
0: self.data.deck[0][2],
1: self.data.deck[1][1],
2: self.data.deck[2][0],
},
)
)
if self.data.nbMoves == 9 and self.data.winner == 0 :
self.data.draw = True
@sp.private()
def checkLine(self, winner, line) :
winner_ = winner
if line[0] != 0 et ligne[0] == ligne[1] et ligne[0] == ligne[2] :
gagnant_ = ligne[0]
return winner_
# Ajouter une fonction de réinitialisation du jeu
@sp.entrypoint
def confirm_and_reset(self) :
assert self.data.winner != 0 or self.data.draw
self.__init__()
# Tests
if "templates" not in __name__:
@sp.add_test(name="TicTacToe")
def test() :
scenario = sp.test_scenario(main)
scénario.h1("Tic-Tac-Toe")
# définir un contrat
c1 = main.TicTacToe()
# montrer sa représentation
scenario.h2("A séquence d'interactions avec un gagnant")
scenario += c1
scenario.h2("Message exécution")
scénario.h3("A premier coup au centre")
c1.play(i=1, j=1, move=1)
scenario.h3("A mouvement interdit")
c1.play(i=1, j=1, move=2).run(valid=False)
scénario.h3("A deuxième coup")
c1.play(i=1, j=2, move=2)
scenario.h3("Other coups")
c1.play(i=2, j=1, move=1)
c1.play(i=2, j=2, move=2)
scenario.verify(c1.data.winner == 0)
c1.play(i=0, j=1, move=1)
scenario.verify(c1.data.winner == 1)
scenario.p("Player1 a gagné")
c1.play(i=0, j=0, move=2).run(valid=False)
c2 = main.TicTacToe()
scenario.h2("A séquence d'interactions avec un dessin")
scenario += c2
scenario.h2("Message exécution")
scénario.h3("A premier coup au centre")
c2.play(i=1, j=1, move=1)
scenario.h3("A mouvement interdit")
c2.play(i=1, j=1, move=2).run(valid=False)
scénario.h3("A deuxième mouvement")
c2.play(i=1, j=2, move=2)
scenario.h3("Other moves")
c2.play(i=2, j=1, move=1)
c2.play(i=2, j=2, move=2)
c2.play(i=0, j=0, move=1)
c2.play(i=0, j=1, move=2)
c2.play(i=0, j=2, move=1)
c2.play(i=2, j=0, move=2)
c2.play(i=1, j=0, move=1)
# Ajouter des tests pour la réinitialisation du jeu
scenario.h2("Testing game reset")
scenario.p("Winner ou tirage au sort confirmé, réinitialisation de la partie")
c1.confirm_and_reset()
scenario.verify(c1.data.nbMoves == 0)
scenario.verify(c1.data.winner == 0)
scenario.verify(not c1.data.draw)
c2.confirm_and_reset()
scenario.verify(c2.data.nbMoves == 0)
scenario.verify(c2.data.winner == 0)
scenario.verify(not c2.data.draw)
Le contrat pour notre jeu TicTacToe sur Tezos est écrit dans le langage SmartPy. Il se compose de deux parties principales : l'état du contrat et la logique du jeu.
L'état du contrat est initialisé dans la fonction**init
. Il comprend
nbMoves
: Il s'agit d'un compteur pour le nombre de mouvements effectués dans le jeu. Il commence à zéro.gagnant
: Cette fonction permet de connaître le gagnant de la partie. Initialement, il est égal à zéro, ce qui indique qu'il n'y a pas de gagnant.draw
: Il s'agit d'un drapeau indiquant si la partie s'est terminée par un match nul. Dans un premier temps, c'est faux.jeu
: Il s'agit d'une grille 3x3 représentant le plateau de TicTacToe. Tous les emplacements du tableau sont initialement vides, représentés par des zéros.nextPlayer
: Il indique à qui revient le tour de jouer. Le jeu commence avec le joueur 1, il est donc initialement fixé à 1.La logique du jeu est encapsulée dans la fonction play
. Il effectue plusieurs vérifications pour s'assurer que le mouvement est valide :
nextPlayer
.nombre de coups
, passe au joueur suivant
et vérifie si le coup a abouti à une victoire ou à un match nul.La condition de victoire est vérifiée sur la ligne et la colonne du dernier coup, ainsi que sur les deux diagonales.
Si toutes les cases du plateau sont occupées et qu'aucun joueur n'a gagné (c'est-à-dire que nbMouvements
est égal à 9 et que le gagnant
est toujours 0), la partie est déclarée nulle.
La fonction checkLine
est utilisée pour vérifier si un joueur a gagné. Il vérifie si toutes les places d'une ligne (qui peut être une ligne, une colonne ou une diagonale) sont occupées par le même joueur. Si c'est le cas, ce joueur est déclaré vainqueur.
Les interactions avec le contrat sont représentées par des transactions. Lorsqu'un joueur effectue un mouvement en appelant la fonction play
, il génère une transaction. Cette transaction est enregistrée et peut être vue dans le panneau de droite de l'IDE SmartPy :
Un mouvement non réussi ou non valide génère également une transaction, mais avec une indication d'erreur :
Le premier coup de notre jeu de TicTacToe est relativement simple puisque le plateau de jeu est vide. Cependant, les choses deviennent plus intéressantes avec le deuxième mouvement et les mouvements suivants. Ces mouvements permettent non seulement d'ajouter des pièces au plateau de jeu, mais aussi d'invoquer la logique du jeu pour vérifier s'il y a des gagnants potentiels.
Après le premier coup, la valeur nextPlayer
passe au joueur 2. Maintenant, la fonction play
valide le coup du joueur 2. Des vérifications similaires sont effectuées pour s'assurer que le déplacement est valide, c'est-à-dire que le point de grille sélectionné se trouve à l'intérieur des limites et qu'il est vide.
Lorsque chaque joueur effectue un mouvement, l'état du jeu évolue. Le nbMoves
augmente, le nextPlayer
bascule et la pioche
est mise à jour. En outre, après chaque coup, le contrat vérifie s'il y a un gagnant ou s'il s'agit d'un tirage au sort.
Par exemple, après que le premier joueur a joué un coup au centre du plateau à i=1, j=1,
le deuxième joueur peut jouer à un autre endroit, disons i=1, j=2
. Ces deux mouvements seront validés et exécutés avec succès, et les transactions correspondantes seront générées.
Les mouvements suivants se déroulent de la même manière. Chaque joueur joue à tour de rôle, en choisissant un emplacement vide sur le plateau. Après chaque coup, le contrat vérifie s'il existe des conditions de victoire. Si un joueur remplit une ligne, une colonne ou une diagonale entière avec son symbole, le jeu se termine et ce joueur est déclaré vainqueur. La variable " gagnant"
de l'état du contrat sera mise à jour en conséquence.
Il est important de noter qu'une fois qu'un joueur a gagné, aucun autre coup n'est valable. Toute tentative d'effectuer un mouvement après la fin du jeu sera considérée comme non valide et la transaction correspondante échouera.
Dans certains jeux, il est possible qu'aucun joueur n'atteigne la condition gagnante, même si le plateau de jeu est entièrement rempli. Il en résulte un tirage au sort. Le contrat a été conçu pour gérer cette situation également.
Si toutes les cases du plateau sont occupées(nbMouvements
égal à 9) et qu'aucun joueur n'a gagné(le gagnant
reste 0), la partie est déclarée nulle. Le drapeau de match nul
dans l'état du contrat est mis à True, ce qui indique que la partie s'est terminée par un match nul. Une fois de plus, aucun autre mouvement n'est valable après ce point. Toute tentative d'action après un tirage au sort échoue également.
La deuxième partie du scénario de test du contrat TicTacToe illustre ce scénario de dessin. Il simule une série de mouvements qui aboutissent à un match nul et vérifie que le contrat le gère correctement.
Commençons par explorer notre contrat pour le jeu TicTacToe :
Python
# TicTacToe - Exemple à titre d'illustration uniquement.
import smartpy as sp
@sp.module
def main() :
class TicTacToe(sp.Contract) :
def __init__(self) :
self.data.nbMoves = 0
self.data.winner = 0
self.data.draw = False
self.data.deck = {
0 : {0: 0, 1: 0, 2: 0},
1 : {0: 0, 1: 0, 2: 0},
2 : {0: 0, 1: 0, 2: 0},
}
self.data.nextPlayer = 1
@sp.entrypoint
def play(self, params) :
assert self.data.winner == 0 and not self.data.draw
assert params.i >= 0 et params.i < 3
assert params.j >= 0 et params.j < 3
assert params.move == self.data.nextPlayer
assert self.data.deck[params.i][params.j] == 0
self.data.deck[params.i][params.j] = params.move
self.data.nbMoves += 1
self.data.nextPlayer = 3 - self.data.nextPlayer
self.data.winner = self.checkLine(
sp.record(winner=self.data.winner, line=self.data.deck[params.i])
)
self.data.winner = self.checkLine(
sp.record(
winner=self.data.winner,
line={
0: self.data.deck[0][params.j],
1: self.data.deck[1][params.j],
2: self.data.deck[2][params.j],
},
)
)
self.data.winner = self.checkLine(
sp.record(
winner=self.data.winner,
line={
0: self.data.deck[0][0],
1: self.data.deck[1][1],
2: self.data.deck[2][2],
},
)
)
self.data.winner = self.checkLine(
sp.record(
winner=self.data.winner,
line={
0: self.data.deck[0][2],
1: self.data.deck[1][1],
2: self.data.deck[2][0],
},
)
)
if self.data.nbMoves == 9 and self.data.winner == 0 :
self.data.draw = True
@sp.private()
def checkLine(self, winner, line) :
winner_ = winner
if line[0] != 0 et ligne[0] == ligne[1] et ligne[0] == ligne[2] :
gagnant_ = ligne[0]
return winner_
# Ajouter une fonction de réinitialisation du jeu
@sp.entrypoint
def confirm_and_reset(self) :
assert self.data.winner != 0 or self.data.draw
self.__init__()
# Tests
if "templates" not in __name__:
@sp.add_test(name="TicTacToe")
def test() :
scenario = sp.test_scenario(main)
scénario.h1("Tic-Tac-Toe")
# définir un contrat
c1 = main.TicTacToe()
# montrer sa représentation
scenario.h2("A séquence d'interactions avec un gagnant")
scenario += c1
scenario.h2("Message exécution")
scénario.h3("A premier coup au centre")
c1.play(i=1, j=1, move=1)
scenario.h3("A mouvement interdit")
c1.play(i=1, j=1, move=2).run(valid=False)
scénario.h3("A deuxième coup")
c1.play(i=1, j=2, move=2)
scenario.h3("Other coups")
c1.play(i=2, j=1, move=1)
c1.play(i=2, j=2, move=2)
scenario.verify(c1.data.winner == 0)
c1.play(i=0, j=1, move=1)
scenario.verify(c1.data.winner == 1)
scenario.p("Player1 a gagné")
c1.play(i=0, j=0, move=2).run(valid=False)
c2 = main.TicTacToe()
scenario.h2("A séquence d'interactions avec un dessin")
scenario += c2
scenario.h2("Message exécution")
scénario.h3("A premier coup au centre")
c2.play(i=1, j=1, move=1)
scenario.h3("A mouvement interdit")
c2.play(i=1, j=1, move=2).run(valid=False)
scénario.h3("A deuxième mouvement")
c2.play(i=1, j=2, move=2)
scenario.h3("Other moves")
c2.play(i=2, j=1, move=1)
c2.play(i=2, j=2, move=2)
c2.play(i=0, j=0, move=1)
c2.play(i=0, j=1, move=2)
c2.play(i=0, j=2, move=1)
c2.play(i=2, j=0, move=2)
c2.play(i=1, j=0, move=1)
# Ajouter des tests pour la réinitialisation du jeu
scenario.h2("Testing game reset")
scenario.p("Winner ou tirage au sort confirmé, réinitialisation de la partie")
c1.confirm_and_reset()
scenario.verify(c1.data.nbMoves == 0)
scenario.verify(c1.data.winner == 0)
scenario.verify(not c1.data.draw)
c2.confirm_and_reset()
scenario.verify(c2.data.nbMoves == 0)
scenario.verify(c2.data.winner == 0)
scenario.verify(not c2.data.draw)
Le contrat pour notre jeu TicTacToe sur Tezos est écrit dans le langage SmartPy. Il se compose de deux parties principales : l'état du contrat et la logique du jeu.
L'état du contrat est initialisé dans la fonction**init
. Il comprend
nbMoves
: Il s'agit d'un compteur pour le nombre de mouvements effectués dans le jeu. Il commence à zéro.gagnant
: Cette fonction permet de connaître le gagnant de la partie. Initialement, il est égal à zéro, ce qui indique qu'il n'y a pas de gagnant.draw
: Il s'agit d'un drapeau indiquant si la partie s'est terminée par un match nul. Dans un premier temps, c'est faux.jeu
: Il s'agit d'une grille 3x3 représentant le plateau de TicTacToe. Tous les emplacements du tableau sont initialement vides, représentés par des zéros.nextPlayer
: Il indique à qui revient le tour de jouer. Le jeu commence avec le joueur 1, il est donc initialement fixé à 1.La logique du jeu est encapsulée dans la fonction play
. Il effectue plusieurs vérifications pour s'assurer que le mouvement est valide :
nextPlayer
.nombre de coups
, passe au joueur suivant
et vérifie si le coup a abouti à une victoire ou à un match nul.La condition de victoire est vérifiée sur la ligne et la colonne du dernier coup, ainsi que sur les deux diagonales.
Si toutes les cases du plateau sont occupées et qu'aucun joueur n'a gagné (c'est-à-dire que nbMouvements
est égal à 9 et que le gagnant
est toujours 0), la partie est déclarée nulle.
La fonction checkLine
est utilisée pour vérifier si un joueur a gagné. Il vérifie si toutes les places d'une ligne (qui peut être une ligne, une colonne ou une diagonale) sont occupées par le même joueur. Si c'est le cas, ce joueur est déclaré vainqueur.
Les interactions avec le contrat sont représentées par des transactions. Lorsqu'un joueur effectue un mouvement en appelant la fonction play
, il génère une transaction. Cette transaction est enregistrée et peut être vue dans le panneau de droite de l'IDE SmartPy :
Un mouvement non réussi ou non valide génère également une transaction, mais avec une indication d'erreur :
Le premier coup de notre jeu de TicTacToe est relativement simple puisque le plateau de jeu est vide. Cependant, les choses deviennent plus intéressantes avec le deuxième mouvement et les mouvements suivants. Ces mouvements permettent non seulement d'ajouter des pièces au plateau de jeu, mais aussi d'invoquer la logique du jeu pour vérifier s'il y a des gagnants potentiels.
Après le premier coup, la valeur nextPlayer
passe au joueur 2. Maintenant, la fonction play
valide le coup du joueur 2. Des vérifications similaires sont effectuées pour s'assurer que le déplacement est valide, c'est-à-dire que le point de grille sélectionné se trouve à l'intérieur des limites et qu'il est vide.
Lorsque chaque joueur effectue un mouvement, l'état du jeu évolue. Le nbMoves
augmente, le nextPlayer
bascule et la pioche
est mise à jour. En outre, après chaque coup, le contrat vérifie s'il y a un gagnant ou s'il s'agit d'un tirage au sort.
Par exemple, après que le premier joueur a joué un coup au centre du plateau à i=1, j=1,
le deuxième joueur peut jouer à un autre endroit, disons i=1, j=2
. Ces deux mouvements seront validés et exécutés avec succès, et les transactions correspondantes seront générées.
Les mouvements suivants se déroulent de la même manière. Chaque joueur joue à tour de rôle, en choisissant un emplacement vide sur le plateau. Après chaque coup, le contrat vérifie s'il existe des conditions de victoire. Si un joueur remplit une ligne, une colonne ou une diagonale entière avec son symbole, le jeu se termine et ce joueur est déclaré vainqueur. La variable " gagnant"
de l'état du contrat sera mise à jour en conséquence.
Il est important de noter qu'une fois qu'un joueur a gagné, aucun autre coup n'est valable. Toute tentative d'effectuer un mouvement après la fin du jeu sera considérée comme non valide et la transaction correspondante échouera.
Dans certains jeux, il est possible qu'aucun joueur n'atteigne la condition gagnante, même si le plateau de jeu est entièrement rempli. Il en résulte un tirage au sort. Le contrat a été conçu pour gérer cette situation également.
Si toutes les cases du plateau sont occupées(nbMouvements
égal à 9) et qu'aucun joueur n'a gagné(le gagnant
reste 0), la partie est déclarée nulle. Le drapeau de match nul
dans l'état du contrat est mis à True, ce qui indique que la partie s'est terminée par un match nul. Une fois de plus, aucun autre mouvement n'est valable après ce point. Toute tentative d'action après un tirage au sort échoue également.
La deuxième partie du scénario de test du contrat TicTacToe illustre ce scénario de dessin. Il simule une série de mouvements qui aboutissent à un match nul et vérifie que le contrat le gère correctement.