第3课

Développer un jeu de TicTacToe sur Tezos

Le monde de la blockchain est riche en opportunités pour les développeurs. Il offre un moyen unique et innovant d'intégrer des mécanismes décentralisés et transparents dans les jeux. En développant des jeux sur une blockchain, nous pouvons intégrer des fonctionnalités telles que des transactions sécurisées et transparentes, la propriété des actifs du jeu, et plus encore. Dans cette leçon, nous allons nous lancer dans le jeu sur blockchain en développant un jeu classique de TicTacToe sur la blockchain Tezos. L'objectif de cette leçon est de comprendre la dynamique de la logique de jeu et de la gestion des états dans un jeu basé sur la blockchain.

Commençons par explorer notre contrat pour le jeu TicTacToe :

Structure du contrat

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.

État du contrat

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.
  • Le 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.

Logique du jeu

La logique du jeu est encapsulée dans la fonction play. Il effectue plusieurs vérifications pour s'assurer que le mouvement est valide :

  • Il vérifie qu'aucun joueur n'a encore gagné et que la partie n'est pas nulle.
  • Il vérifie que les indices du point de grille choisi par le joueur se trouvent à l'intérieur des limites de la grille.
  • Il s'assure que le joueur qui effectue le déplacement correspond au nextPlayer.
  • Il s'assure que l'emplacement choisi sur la grille est vide.
    Une fois qu'un coup est joué, la logique du jeu incrémente le 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.

Vérification de la victoire

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.

Interagir avec le contrat

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 deuxième mouvement et au-delà

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 autres mouvements et la progression du jeu

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.

Le scénario du tirage au sort

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.

免责声明
* 投资有风险,入市须谨慎。本课程不作为投资理财建议。
* 本课程由入驻Gate Learn的作者创作,观点仅代表作者本人,绝不代表Gate Learn赞同其观点或证实其描述。
目录
第3课

Développer un jeu de TicTacToe sur Tezos

Le monde de la blockchain est riche en opportunités pour les développeurs. Il offre un moyen unique et innovant d'intégrer des mécanismes décentralisés et transparents dans les jeux. En développant des jeux sur une blockchain, nous pouvons intégrer des fonctionnalités telles que des transactions sécurisées et transparentes, la propriété des actifs du jeu, et plus encore. Dans cette leçon, nous allons nous lancer dans le jeu sur blockchain en développant un jeu classique de TicTacToe sur la blockchain Tezos. L'objectif de cette leçon est de comprendre la dynamique de la logique de jeu et de la gestion des états dans un jeu basé sur la blockchain.

Commençons par explorer notre contrat pour le jeu TicTacToe :

Structure du contrat

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.

État du contrat

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.
  • Le 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.

Logique du jeu

La logique du jeu est encapsulée dans la fonction play. Il effectue plusieurs vérifications pour s'assurer que le mouvement est valide :

  • Il vérifie qu'aucun joueur n'a encore gagné et que la partie n'est pas nulle.
  • Il vérifie que les indices du point de grille choisi par le joueur se trouvent à l'intérieur des limites de la grille.
  • Il s'assure que le joueur qui effectue le déplacement correspond au nextPlayer.
  • Il s'assure que l'emplacement choisi sur la grille est vide.
    Une fois qu'un coup est joué, la logique du jeu incrémente le 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.

Vérification de la victoire

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.

Interagir avec le contrat

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 deuxième mouvement et au-delà

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 autres mouvements et la progression du jeu

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.

Le scénario du tirage au sort

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.

免责声明
* 投资有风险,入市须谨慎。本课程不作为投资理财建议。
* 本课程由入驻Gate Learn的作者创作,观点仅代表作者本人,绝不代表Gate Learn赞同其观点或证实其描述。