Lição 3

TezosでTicTacToeゲームを開発する

ブロックチェーンゲームの世界は、開発者にとってチャンスに満ちています。 分散型で透明性の高いメカニズムをゲームに統合するためのユニークで革新的な方法を提供します。 ブロックチェーン上でゲームを開発することで、安全で透明性の高い取引、ゲーム内資産の所有権などの機能を組み込むことができます。 このレッスンでは、Tezosブロックチェーン上でTicTacToeの古典的なゲームを開発することで、ブロックチェーンゲームに足を踏み入れます。 このレッスンの目的は、ブロックチェーンベースのゲームにおけるゲームロジックと状態管理のダイナミクスを理解することです。

まず、TicTacToeゲームの契約を調べてみましょう。

契約構造

ニシキヘビ
#TicTacToe - 例示のみを目的としています。SmartPy を SP としてインポートする

@sp.モジュール
デフmain():
    class TicTacToe(sp.契約):
        デフ __init__(セルフ):
            self.data.nbMoves = 0
            self.data.winner = 0
            self.data.draw = 偽
            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.エントリポイント
        def play(self, params):
            self.data.draw ではなく self.data.winner == 0 をアサートします。
            params.iをアサートします >= 0 と params.i < 3
            assert params.j >= 0 と params.j < 3
            params.move == self.data.nextPlayerをアサートします
            self.data.deck [params.i] [params.j]をアサートします == 0
            self.data.deck[params.i][params.j] = params.move
            self.data.nb移動 += 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],
                    },
                )
            )
            self.data.nbMoves == 9 かつ self.data.winner == 0 の場合:
                self.data.draw = 真

@sp.private()
        デフcheckLine(自己、勝者、行):
            winner_ = 勝者
            line[0] != 0 かつ line[0] == line[1] かつ line[0] == line[2] の場合:
                winner_ = line[0]
            winner_戻る

# ゲームリセット機能を追加
        @sp.エントリポイント
        def confirm_and_reset(self):
            assert self.data.winner != 0 または self.data.draw
            自己。__init__()# テスト
「テンプレート」が __name__にない場合:

@sp.add_test(名前="TicTacToe")
    def test()を使用します。
        シナリオ = sp.test_scenario(main)        scenario.h1("三目並べ")        # コントラクトの定義
        C1 = メイン。TicTacToe()関数

#その表現を表示
        scenario.h2("A 勝者とのやり取りのシーケンス")
        シナリオ += C1
        scenario.h2("メッセージ 実行")
        scenario.h3("A 中央で最初の動き」)
        c1.play(i = 1、j = 1、move = 1)
        scenario.h3("A 禁じられた動き」)
        c1.play(i = 1、j = 1、move = 2).run(valid = False)        scenario.h3("A 2手目」)
        c1.play(i=1, j=2, 移動=2)
        scenario.h3("その他 moves")です。
        c1.play(i = 2、j = 1、move = 1)
        c1.play(i = 2、j = 2、move = 2)
        シナリオ.ベリファイ(c1.data.winner == 0)
        c1.play(i = 0、j = 1、move = 1)
        scenario.verify(c1.data.winner == 1)
        scenario.p("Player1 勝った」)
        c1.play(i = 0、j = 0、move = 2).run(valid = False)        C2 = メイン。TicTacToe()関数
        scenario.h2("A ドローとの相互作用のシーケンス」)
        シナリオ += C2
        scenario.h2("メッセージ 実行")
        scenario.h3("A 中央で最初の動き」)
        c2.play(i = 1、j = 1、move = 1)
        scenario.h3("A 禁じられた動き」)
        c2.play(i = 1、j = 1、move = 2).run(valid = False)        scenario.h3("A 2手目」)
        c2.play(i = 1、j = 2、move = 2)
        scenario.h3("その他 moves")です。
        c2.play(i = 2、j = 1、move = 1)
        c2.play(i = 2、j = 2、move = 2)
        c2.play(i = 0、j = 0、移動= 1)
        c2.play(i = 0、j = 1、移動= 2)
        c2.play(i = 0、j = 2、move = 1)
        c2.play(i = 2、j = 0、移動= 2)
        c2.play(i = 1、j = 0、移動= 1)

# ゲームリセットのテストを追加
        scenario.h2("テスト中 ゲームリセット」)
        scenario.p("勝者 または引き分けが確認され、ゲームがリセットされます」)
        c1.confirm_and_reset()
        scenario.verify(c1.data.nbMoves == 0)
        シナリオ.ベリファイ(c1.data.winner == 0)
        scenario.verify( c1.data.drawなど)        c2.confirm_and_reset()
        scenario.verify(c2.data.nbMoves == 0)
        シナリオ.ベリファイ(c2.data.winner == 0)
        scenario.verify( c2.data.drawなど)

TezosのTicTacToeゲームの契約は、SmartPy言語で書かれています。 これは、コントラクトの状態とゲームのロジックの 2 つの主要な部分で構成されています。

契約の状態

コントラクトの状態は、** init 関数で初期化されます。これには以下が含まれます。

  • nbMoves:これは、ゲームで行われた動きの数のカウンターです。 ゼロから始まります。
  • winner:これは、ゲームの勝者を追跡します。 最初は 0 で、勝者がいないことを示します。
  • draw:これは、ゲームが引き分けで終了したかどうかを示すフラグです。 最初は False です。
  • deck:これは、TicTacToeボードを表す3x3グリッドです。 ボード上のすべてのスポットは、最初は空で、ゼロで表されます。
  • nextPlayer:これは、誰の番がプレイするかを示します。 ゲームはプレイヤー 1 から開始されるため、最初は 1 に設定されています。

ゲームロジック

ゲームロジックは関数に play カプセル化されています。 有効な移動を確認するために、いくつかのチェックを実行します。

  • まだ勝っていないプレイヤーと、ゲームが引き分けではないことを確認します。
  • プレイヤーが選択したグリッドスポットのインデックスがグリッドの境界内にあることを確認します。
  • これは、移動 nextPlayerを行うプレーヤーが と一致することを確認します。
  • これにより、グリッド上の選択したスポットが空になります。
    移動が行われると、ゲームロジックは、 nbMovesをインクリメントし、 を切り替え nextPlayer、移動が勝利または引き分けのどちらになったかをチェックします。

勝利条件は、直近の動手の行と列、および2つの対角線でチェックされます。

ボード上のすべてのスポットが埋まり、どのプレイヤーも勝っていない場合(つまり、9に等しく、 nbMoves winner まだ0の場合)、ゲームは引き分けとして宣言されます。

勝利の確認

この checkLine 関数は、プレイヤーが勝ったかどうかを確認するために使用されます。 これは、行内のすべてのスポット(行、列、または対角線)が同じプレーヤーによって埋められているかどうかをチェックします。 もしそうなら、そのプレイヤーが勝者として宣言されます。

契約との対話

コントラクトとの対話は、トランザクションとして表されます。 プレイヤーが関数を呼び出し play て移動すると、トランザクションが生成されます。 このトランザクションはログに記録され、SmartPy IDE の右側のパネルに表示されます。

移動が失敗したり無効になったりした場合も、トランザクションが生成されますが、エラーが表示されます。

第2の一歩とその先へ

TicTacToeゲームの最初の動きは、ゲームボードが空であるため、比較的簡単です。 しかし、2手目以降の動きで物事はより面白くなります。 これらの動きは、ゲームボードに駒を追加するだけでなく、ゲームのロジックを呼び出して、潜在的な勝者をチェックします。

最初の移動の後、 nextPlayer 値はプレイヤー2に切り替わります。これで、この関数は play プレイヤー 2 の動きを検証します。 同様のチェックが実行され、移動が有効であること、つまり、選択したグリッドスポットが境界内にあり、空であることを確認します。

各プレイヤーが移動すると、ゲームの状態が進化します。 が増加し nbMoves 、トグルし、 nextPlayer 更新されます deck 。 また、各移動の後、契約は勝者がいるか引き分けであるかを確認します。

たとえば、最初のプレイヤーが で i=1, j=1ボードの中央に移動した後、2 番目のプレーヤーは別の場所、たとえば i=1, j=2でプレイできます。 これらの移動は両方とも検証され、正常に実行され、対応するトランザクションが生成されます。

その他の動きとゲームの進行

その後の動きも同様の方法で継続されます。 各プレイヤーは順番にプレイし、ボード上の空いている場所を選択します。 各移動の後、契約は勝利条件をチェックします。 プレイヤーが行、列、または対角線全体をシンボルで埋めると、ゲームは終了し、そのプレイヤーが勝者として宣言されます。 winnerコントラクトの状態の変数は、それに応じて更新されます。

プレイヤーが勝つと、それ以上の動きは有効ではないことに注意することが重要です。 ゲーム終了後に移動しようとすると、無効と見なされ、対応するトランザクションは失敗します。

描画シナリオ

一部のゲームでは、ゲームボード全体がいっぱいになった後でも、勝利条件を達成したプレイヤーがいない可能性があります。 この結果、引き分けとなります。 この契約は、この状況にも対処できるように設計されています。

ボード上のすべてのスポットが埋まり (9 に等しい)、どのプレイヤーも勝っていない (nbMoveswinner0 のまま) 場合、ゲームは引き分けとして宣言されます。drawコントラクトの状態のフラグは True に設定され、ゲームが引き分けに終わったことを示します。繰り返しになりますが、この時点以降はそれ以上の移動は有効ではありません。 引き分け後に移動しようとする試みも失敗します。

TicTacToe コントラクトのテスト シナリオの 2 番目の部分では、この描画シナリオを示します。 引き分けになる一連の動きをシミュレートし、コントラクトがそれを正しく処理することを検証します。

Exclusão de responsabilidade
* O investimento em criptomoedas envolve riscos significativos. Prossiga com cuidado. O curso não pretende ser um conselho de investimento.
* O curso é criado pelo autor que se juntou ao Gate Learn. Qualquer opinião partilhada pelo autor não representa o Gate Learn.
Catálogo
Lição 3

TezosでTicTacToeゲームを開発する

ブロックチェーンゲームの世界は、開発者にとってチャンスに満ちています。 分散型で透明性の高いメカニズムをゲームに統合するためのユニークで革新的な方法を提供します。 ブロックチェーン上でゲームを開発することで、安全で透明性の高い取引、ゲーム内資産の所有権などの機能を組み込むことができます。 このレッスンでは、Tezosブロックチェーン上でTicTacToeの古典的なゲームを開発することで、ブロックチェーンゲームに足を踏み入れます。 このレッスンの目的は、ブロックチェーンベースのゲームにおけるゲームロジックと状態管理のダイナミクスを理解することです。

まず、TicTacToeゲームの契約を調べてみましょう。

契約構造

ニシキヘビ
#TicTacToe - 例示のみを目的としています。SmartPy を SP としてインポートする

@sp.モジュール
デフmain():
    class TicTacToe(sp.契約):
        デフ __init__(セルフ):
            self.data.nbMoves = 0
            self.data.winner = 0
            self.data.draw = 偽
            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.エントリポイント
        def play(self, params):
            self.data.draw ではなく self.data.winner == 0 をアサートします。
            params.iをアサートします >= 0 と params.i < 3
            assert params.j >= 0 と params.j < 3
            params.move == self.data.nextPlayerをアサートします
            self.data.deck [params.i] [params.j]をアサートします == 0
            self.data.deck[params.i][params.j] = params.move
            self.data.nb移動 += 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],
                    },
                )
            )
            self.data.nbMoves == 9 かつ self.data.winner == 0 の場合:
                self.data.draw = 真

@sp.private()
        デフcheckLine(自己、勝者、行):
            winner_ = 勝者
            line[0] != 0 かつ line[0] == line[1] かつ line[0] == line[2] の場合:
                winner_ = line[0]
            winner_戻る

# ゲームリセット機能を追加
        @sp.エントリポイント
        def confirm_and_reset(self):
            assert self.data.winner != 0 または self.data.draw
            自己。__init__()# テスト
「テンプレート」が __name__にない場合:

@sp.add_test(名前="TicTacToe")
    def test()を使用します。
        シナリオ = sp.test_scenario(main)        scenario.h1("三目並べ")        # コントラクトの定義
        C1 = メイン。TicTacToe()関数

#その表現を表示
        scenario.h2("A 勝者とのやり取りのシーケンス")
        シナリオ += C1
        scenario.h2("メッセージ 実行")
        scenario.h3("A 中央で最初の動き」)
        c1.play(i = 1、j = 1、move = 1)
        scenario.h3("A 禁じられた動き」)
        c1.play(i = 1、j = 1、move = 2).run(valid = False)        scenario.h3("A 2手目」)
        c1.play(i=1, j=2, 移動=2)
        scenario.h3("その他 moves")です。
        c1.play(i = 2、j = 1、move = 1)
        c1.play(i = 2、j = 2、move = 2)
        シナリオ.ベリファイ(c1.data.winner == 0)
        c1.play(i = 0、j = 1、move = 1)
        scenario.verify(c1.data.winner == 1)
        scenario.p("Player1 勝った」)
        c1.play(i = 0、j = 0、move = 2).run(valid = False)        C2 = メイン。TicTacToe()関数
        scenario.h2("A ドローとの相互作用のシーケンス」)
        シナリオ += C2
        scenario.h2("メッセージ 実行")
        scenario.h3("A 中央で最初の動き」)
        c2.play(i = 1、j = 1、move = 1)
        scenario.h3("A 禁じられた動き」)
        c2.play(i = 1、j = 1、move = 2).run(valid = False)        scenario.h3("A 2手目」)
        c2.play(i = 1、j = 2、move = 2)
        scenario.h3("その他 moves")です。
        c2.play(i = 2、j = 1、move = 1)
        c2.play(i = 2、j = 2、move = 2)
        c2.play(i = 0、j = 0、移動= 1)
        c2.play(i = 0、j = 1、移動= 2)
        c2.play(i = 0、j = 2、move = 1)
        c2.play(i = 2、j = 0、移動= 2)
        c2.play(i = 1、j = 0、移動= 1)

# ゲームリセットのテストを追加
        scenario.h2("テスト中 ゲームリセット」)
        scenario.p("勝者 または引き分けが確認され、ゲームがリセットされます」)
        c1.confirm_and_reset()
        scenario.verify(c1.data.nbMoves == 0)
        シナリオ.ベリファイ(c1.data.winner == 0)
        scenario.verify( c1.data.drawなど)        c2.confirm_and_reset()
        scenario.verify(c2.data.nbMoves == 0)
        シナリオ.ベリファイ(c2.data.winner == 0)
        scenario.verify( c2.data.drawなど)

TezosのTicTacToeゲームの契約は、SmartPy言語で書かれています。 これは、コントラクトの状態とゲームのロジックの 2 つの主要な部分で構成されています。

契約の状態

コントラクトの状態は、** init 関数で初期化されます。これには以下が含まれます。

  • nbMoves:これは、ゲームで行われた動きの数のカウンターです。 ゼロから始まります。
  • winner:これは、ゲームの勝者を追跡します。 最初は 0 で、勝者がいないことを示します。
  • draw:これは、ゲームが引き分けで終了したかどうかを示すフラグです。 最初は False です。
  • deck:これは、TicTacToeボードを表す3x3グリッドです。 ボード上のすべてのスポットは、最初は空で、ゼロで表されます。
  • nextPlayer:これは、誰の番がプレイするかを示します。 ゲームはプレイヤー 1 から開始されるため、最初は 1 に設定されています。

ゲームロジック

ゲームロジックは関数に play カプセル化されています。 有効な移動を確認するために、いくつかのチェックを実行します。

  • まだ勝っていないプレイヤーと、ゲームが引き分けではないことを確認します。
  • プレイヤーが選択したグリッドスポットのインデックスがグリッドの境界内にあることを確認します。
  • これは、移動 nextPlayerを行うプレーヤーが と一致することを確認します。
  • これにより、グリッド上の選択したスポットが空になります。
    移動が行われると、ゲームロジックは、 nbMovesをインクリメントし、 を切り替え nextPlayer、移動が勝利または引き分けのどちらになったかをチェックします。

勝利条件は、直近の動手の行と列、および2つの対角線でチェックされます。

ボード上のすべてのスポットが埋まり、どのプレイヤーも勝っていない場合(つまり、9に等しく、 nbMoves winner まだ0の場合)、ゲームは引き分けとして宣言されます。

勝利の確認

この checkLine 関数は、プレイヤーが勝ったかどうかを確認するために使用されます。 これは、行内のすべてのスポット(行、列、または対角線)が同じプレーヤーによって埋められているかどうかをチェックします。 もしそうなら、そのプレイヤーが勝者として宣言されます。

契約との対話

コントラクトとの対話は、トランザクションとして表されます。 プレイヤーが関数を呼び出し play て移動すると、トランザクションが生成されます。 このトランザクションはログに記録され、SmartPy IDE の右側のパネルに表示されます。

移動が失敗したり無効になったりした場合も、トランザクションが生成されますが、エラーが表示されます。

第2の一歩とその先へ

TicTacToeゲームの最初の動きは、ゲームボードが空であるため、比較的簡単です。 しかし、2手目以降の動きで物事はより面白くなります。 これらの動きは、ゲームボードに駒を追加するだけでなく、ゲームのロジックを呼び出して、潜在的な勝者をチェックします。

最初の移動の後、 nextPlayer 値はプレイヤー2に切り替わります。これで、この関数は play プレイヤー 2 の動きを検証します。 同様のチェックが実行され、移動が有効であること、つまり、選択したグリッドスポットが境界内にあり、空であることを確認します。

各プレイヤーが移動すると、ゲームの状態が進化します。 が増加し nbMoves 、トグルし、 nextPlayer 更新されます deck 。 また、各移動の後、契約は勝者がいるか引き分けであるかを確認します。

たとえば、最初のプレイヤーが で i=1, j=1ボードの中央に移動した後、2 番目のプレーヤーは別の場所、たとえば i=1, j=2でプレイできます。 これらの移動は両方とも検証され、正常に実行され、対応するトランザクションが生成されます。

その他の動きとゲームの進行

その後の動きも同様の方法で継続されます。 各プレイヤーは順番にプレイし、ボード上の空いている場所を選択します。 各移動の後、契約は勝利条件をチェックします。 プレイヤーが行、列、または対角線全体をシンボルで埋めると、ゲームは終了し、そのプレイヤーが勝者として宣言されます。 winnerコントラクトの状態の変数は、それに応じて更新されます。

プレイヤーが勝つと、それ以上の動きは有効ではないことに注意することが重要です。 ゲーム終了後に移動しようとすると、無効と見なされ、対応するトランザクションは失敗します。

描画シナリオ

一部のゲームでは、ゲームボード全体がいっぱいになった後でも、勝利条件を達成したプレイヤーがいない可能性があります。 この結果、引き分けとなります。 この契約は、この状況にも対処できるように設計されています。

ボード上のすべてのスポットが埋まり (9 に等しい)、どのプレイヤーも勝っていない (nbMoveswinner0 のまま) 場合、ゲームは引き分けとして宣言されます。drawコントラクトの状態のフラグは True に設定され、ゲームが引き分けに終わったことを示します。繰り返しになりますが、この時点以降はそれ以上の移動は有効ではありません。 引き分け後に移動しようとする試みも失敗します。

TicTacToe コントラクトのテスト シナリオの 2 番目の部分では、この描画シナリオを示します。 引き分けになる一連の動きをシミュレートし、コントラクトがそれを正しく処理することを検証します。

Exclusão de responsabilidade
* O investimento em criptomoedas envolve riscos significativos. Prossiga com cuidado. O curso não pretende ser um conselho de investimento.
* O curso é criado pelo autor que se juntou ao Gate Learn. Qualquer opinião partilhada pelo autor não representa o Gate Learn.