まず、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 の右側のパネルに表示されます。
移動が失敗したり無効になったりした場合も、トランザクションが生成されますが、エラーが表示されます。
TicTacToeゲームの最初の動きは、ゲームボードが空であるため、比較的簡単です。 しかし、2手目以降の動きで物事はより面白くなります。 これらの動きは、ゲームボードに駒を追加するだけでなく、ゲームのロジックを呼び出して、潜在的な勝者をチェックします。
最初の移動の後、 nextPlayer
値はプレイヤー2に切り替わります。これで、この関数は play
プレイヤー 2 の動きを検証します。 同様のチェックが実行され、移動が有効であること、つまり、選択したグリッドスポットが境界内にあり、空であることを確認します。
各プレイヤーが移動すると、ゲームの状態が進化します。 が増加し nbMoves
、トグルし、 nextPlayer
更新されます deck
。 また、各移動の後、契約は勝者がいるか引き分けであるかを確認します。
たとえば、最初のプレイヤーが で i=1, j=1
ボードの中央に移動した後、2 番目のプレーヤーは別の場所、たとえば i=1, j=2
でプレイできます。 これらの移動は両方とも検証され、正常に実行され、対応するトランザクションが生成されます。
その後の動きも同様の方法で継続されます。 各プレイヤーは順番にプレイし、ボード上の空いている場所を選択します。 各移動の後、契約は勝利条件をチェックします。 プレイヤーが行、列、または対角線全体をシンボルで埋めると、ゲームは終了し、そのプレイヤーが勝者として宣言されます。 winner
コントラクトの状態の変数は、それに応じて更新されます。
プレイヤーが勝つと、それ以上の動きは有効ではないことに注意することが重要です。 ゲーム終了後に移動しようとすると、無効と見なされ、対応するトランザクションは失敗します。
一部のゲームでは、ゲームボード全体がいっぱいになった後でも、勝利条件を達成したプレイヤーがいない可能性があります。 この結果、引き分けとなります。 この契約は、この状況にも対処できるように設計されています。
ボード上のすべてのスポットが埋まり (9 に等しい)、どのプレイヤーも勝っていない (nbMoves
winner
0 のまま) 場合、ゲームは引き分けとして宣言されます。draw
コントラクトの状態のフラグは True に設定され、ゲームが引き分けに終わったことを示します。繰り返しになりますが、この時点以降はそれ以上の移動は有効ではありません。 引き分け後に移動しようとする試みも失敗します。
TicTacToe コントラクトのテスト シナリオの 2 番目の部分では、この描画シナリオを示します。 引き分けになる一連の動きをシミュレートし、コントラクトがそれを正しく処理することを検証します。
まず、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 の右側のパネルに表示されます。
移動が失敗したり無効になったりした場合も、トランザクションが生成されますが、エラーが表示されます。
TicTacToeゲームの最初の動きは、ゲームボードが空であるため、比較的簡単です。 しかし、2手目以降の動きで物事はより面白くなります。 これらの動きは、ゲームボードに駒を追加するだけでなく、ゲームのロジックを呼び出して、潜在的な勝者をチェックします。
最初の移動の後、 nextPlayer
値はプレイヤー2に切り替わります。これで、この関数は play
プレイヤー 2 の動きを検証します。 同様のチェックが実行され、移動が有効であること、つまり、選択したグリッドスポットが境界内にあり、空であることを確認します。
各プレイヤーが移動すると、ゲームの状態が進化します。 が増加し nbMoves
、トグルし、 nextPlayer
更新されます deck
。 また、各移動の後、契約は勝者がいるか引き分けであるかを確認します。
たとえば、最初のプレイヤーが で i=1, j=1
ボードの中央に移動した後、2 番目のプレーヤーは別の場所、たとえば i=1, j=2
でプレイできます。 これらの移動は両方とも検証され、正常に実行され、対応するトランザクションが生成されます。
その後の動きも同様の方法で継続されます。 各プレイヤーは順番にプレイし、ボード上の空いている場所を選択します。 各移動の後、契約は勝利条件をチェックします。 プレイヤーが行、列、または対角線全体をシンボルで埋めると、ゲームは終了し、そのプレイヤーが勝者として宣言されます。 winner
コントラクトの状態の変数は、それに応じて更新されます。
プレイヤーが勝つと、それ以上の動きは有効ではないことに注意することが重要です。 ゲーム終了後に移動しようとすると、無効と見なされ、対応するトランザクションは失敗します。
一部のゲームでは、ゲームボード全体がいっぱいになった後でも、勝利条件を達成したプレイヤーがいない可能性があります。 この結果、引き分けとなります。 この契約は、この状況にも対処できるように設計されています。
ボード上のすべてのスポットが埋まり (9 に等しい)、どのプレイヤーも勝っていない (nbMoves
winner
0 のまま) 場合、ゲームは引き分けとして宣言されます。draw
コントラクトの状態のフラグは True に設定され、ゲームが引き分けに終わったことを示します。繰り返しになりますが、この時点以降はそれ以上の移動は有効ではありません。 引き分け後に移動しようとする試みも失敗します。
TicTacToe コントラクトのテスト シナリオの 2 番目の部分では、この描画シナリオを示します。 引き分けになる一連の動きをシミュレートし、コントラクトがそれを正しく処理することを検証します。