Давайте начнем с изучения нашего контракта на игру TicTacToe:
Python
# TicTacToe - Пример только для иллюстративных целей.
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 и params.i < 3
assert params.j >= 0 и 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 и line[0] == line[1] и line[0] == line[2]:
winner_ = line[0]
return winner_
# Добавить функцию сброса игры
@sp.entrypoint
def confirm_and_reset(self):
assert self.data.winner != 0 или self.data.draw
self.__init__()
# Тесты
if "templates" not in __name__:
@sp.add_test(name="TicTacToe")
def test():
scenario = sp.test_scenario(main)
scenario.h1("Tic-Tac-Toe")
# определите контракт
c1 = main.TicTacToe()
# покажите его представление
scenario.h2("A Последовательность взаимодействий с победителем")
scenario += c1
scenario.h2("Message выполнение")
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 второй ход")
c1.play(i=1, j=2, move=2)
scenario.h3("Другое moves")
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 выиграл")
c1.play(i=0, j=0, move=2).run(valid=False)
c2 = main.TicTacToe()
scenario.h2("A Последовательность взаимодействий с жеребьевкой")
scenario += c2
scenario.h2("Message выполнение")
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 второй ход")
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, 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)
# Добавьте тесты для перезагрузки игры
scenario.h2("Testing game reset")
scenario.p("Winner или ничья подтверждена, теперь сбрасываем игру")
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)
Контракт для нашей игры TicTacToe на Tezos написан на языке SmartPy. Он состоит из двух основных частей: состояние контракта и логика игры.
Состояние контракта инициализируется в функции**init
. Он включает в себя:
nbMoves
: Это счетчик количества ходов, сделанных в игре. Она начинается с нуля.winner (победитель
): Здесь ведется учет победителя игры. Первоначально он равен нулю, что означает отсутствие победителя.draw (ничья
): Это флаг, указывающий, закончилась ли игра вничью. Первоначально это Ложь.Колода
: Это сетка 3x3, представляющая собой доску TicTacToe. Все места на доске изначально пусты, представлены нулями.nextPlayer (следующий игрок
): Это указывает, чья очередь играть. Игра начинается с игроком 1, поэтому первоначально установлено значение 1.Логика игры заключена в функции play
. Он выполняет несколько проверок, чтобы убедиться в правильности хода:
nextPlayer
.nbMoves
, переключает следующего игрока (nextPlayer
) и проверяет, привел ли этот ход к победе или ничьей.Условие выигрыша проверяется по строке и колонке последнего хода, а также по двум диагоналям.
Если все места на доске заполнены и ни один игрок не выиграл (т.е. nbMoves
равно 9, а победитель
все еще 0), игра объявляется ничейной.
Функция checkLine
используется для проверки того, выиграл ли какой-либо игрок. Она проверяет, все ли места в линии (которая может быть строкой, колонкой или диагональю) заполнены одним и тем же игроком. Если да, то этот игрок объявляется победителем.
Взаимодействия с контрактом представляются в виде транзакций. Когда игрок делает ход, вызывая функцию play
, он генерирует транзакцию. Эта транзакция записывается в журнал и видна на правой панели SmartPy IDE:
Неудачное или недействительное перемещение также генерирует транзакцию, но с индикацией ошибки:
Первый ход в нашей игре TicTacToe относительно прост, поскольку игровое поле пусто. Однако все становится более интересным со вторым ходом и последующими ходами. Эти ходы не только добавляют фигуры на игровое поле, но и вызывают логику игры для проверки потенциальных победителей.
После первого хода значение nextPlayer
переключается на игрока 2. Теперь функция play
проверяет ход игрока 2. Аналогичные проверки выполняются для того, чтобы убедиться, что перемещение является действительным, т.е. выбранный участок сетки находится в пределах границ и не пуст.
По мере того, как каждый игрок делает ход, состояние игры изменяется. nbMoves
увеличивается, nextPlayer
переключается, и колода
обновляется. Кроме того, после каждого хода контракт проверяет, есть ли победитель или это ничья.
Например, после того, как первый игрок сделает ход в центре доски в точке i=1, j=1
, второй игрок может сыграть в другой точке, скажем, i=1, j=2
. Оба этих хода будут подтверждены и успешно выполнены, с генерированием соответствующих транзакций.
Последующие перемещения продолжаются аналогичным образом. Каждый игрок играет по очереди, выбирая свободное место на доске. После каждого хода контракт проверяет наличие выигрышного состояния. Если игрок заполняет своим символом всю строку, колонку или диагональ, игра заканчивается, и этот игрок объявляется победителем. Переменная winner
в состоянии контракта будет обновлена соответствующим образом.
Важно отметить, что как только игрок выиграл, никакие дальнейшие ходы не действительны. Любая попытка сделать ход после окончания игры будет считаться недействительной, и соответствующая операция будет провалена.
В некоторых играх возможно, что ни один игрок не достигнет выигрышного состояния даже после того, как будет заполнено все игровое поле. В результате получается ничья. Контракт был разработан таким образом, чтобы справиться и с этой ситуацией.
Если все места на доске заполнены(nbMoves
равно 9) и ни один игрок не выиграл(победитель
остается в 0), игра объявляется ничейной. Флаг ничьей
в состоянии контракта устанавливается в True, указывая на то, что игра закончилась вничью. И снова, после этого момента никакие дальнейшие ходы не действительны. Любые попытки сделать ход после ничьей также будут безуспешными.
Вторая часть тестового сценария контракта TicTacToe демонстрирует этот сценарий розыгрыша. Он моделирует серию ходов, приводящих к ничьей, и проверяет, правильно ли контракт ее обрабатывает.
Давайте начнем с изучения нашего контракта на игру TicTacToe:
Python
# TicTacToe - Пример только для иллюстративных целей.
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 и params.i < 3
assert params.j >= 0 и 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 и line[0] == line[1] и line[0] == line[2]:
winner_ = line[0]
return winner_
# Добавить функцию сброса игры
@sp.entrypoint
def confirm_and_reset(self):
assert self.data.winner != 0 или self.data.draw
self.__init__()
# Тесты
if "templates" not in __name__:
@sp.add_test(name="TicTacToe")
def test():
scenario = sp.test_scenario(main)
scenario.h1("Tic-Tac-Toe")
# определите контракт
c1 = main.TicTacToe()
# покажите его представление
scenario.h2("A Последовательность взаимодействий с победителем")
scenario += c1
scenario.h2("Message выполнение")
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 второй ход")
c1.play(i=1, j=2, move=2)
scenario.h3("Другое moves")
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 выиграл")
c1.play(i=0, j=0, move=2).run(valid=False)
c2 = main.TicTacToe()
scenario.h2("A Последовательность взаимодействий с жеребьевкой")
scenario += c2
scenario.h2("Message выполнение")
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 второй ход")
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, 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)
# Добавьте тесты для перезагрузки игры
scenario.h2("Testing game reset")
scenario.p("Winner или ничья подтверждена, теперь сбрасываем игру")
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)
Контракт для нашей игры TicTacToe на Tezos написан на языке SmartPy. Он состоит из двух основных частей: состояние контракта и логика игры.
Состояние контракта инициализируется в функции**init
. Он включает в себя:
nbMoves
: Это счетчик количества ходов, сделанных в игре. Она начинается с нуля.winner (победитель
): Здесь ведется учет победителя игры. Первоначально он равен нулю, что означает отсутствие победителя.draw (ничья
): Это флаг, указывающий, закончилась ли игра вничью. Первоначально это Ложь.Колода
: Это сетка 3x3, представляющая собой доску TicTacToe. Все места на доске изначально пусты, представлены нулями.nextPlayer (следующий игрок
): Это указывает, чья очередь играть. Игра начинается с игроком 1, поэтому первоначально установлено значение 1.Логика игры заключена в функции play
. Он выполняет несколько проверок, чтобы убедиться в правильности хода:
nextPlayer
.nbMoves
, переключает следующего игрока (nextPlayer
) и проверяет, привел ли этот ход к победе или ничьей.Условие выигрыша проверяется по строке и колонке последнего хода, а также по двум диагоналям.
Если все места на доске заполнены и ни один игрок не выиграл (т.е. nbMoves
равно 9, а победитель
все еще 0), игра объявляется ничейной.
Функция checkLine
используется для проверки того, выиграл ли какой-либо игрок. Она проверяет, все ли места в линии (которая может быть строкой, колонкой или диагональю) заполнены одним и тем же игроком. Если да, то этот игрок объявляется победителем.
Взаимодействия с контрактом представляются в виде транзакций. Когда игрок делает ход, вызывая функцию play
, он генерирует транзакцию. Эта транзакция записывается в журнал и видна на правой панели SmartPy IDE:
Неудачное или недействительное перемещение также генерирует транзакцию, но с индикацией ошибки:
Первый ход в нашей игре TicTacToe относительно прост, поскольку игровое поле пусто. Однако все становится более интересным со вторым ходом и последующими ходами. Эти ходы не только добавляют фигуры на игровое поле, но и вызывают логику игры для проверки потенциальных победителей.
После первого хода значение nextPlayer
переключается на игрока 2. Теперь функция play
проверяет ход игрока 2. Аналогичные проверки выполняются для того, чтобы убедиться, что перемещение является действительным, т.е. выбранный участок сетки находится в пределах границ и не пуст.
По мере того, как каждый игрок делает ход, состояние игры изменяется. nbMoves
увеличивается, nextPlayer
переключается, и колода
обновляется. Кроме того, после каждого хода контракт проверяет, есть ли победитель или это ничья.
Например, после того, как первый игрок сделает ход в центре доски в точке i=1, j=1
, второй игрок может сыграть в другой точке, скажем, i=1, j=2
. Оба этих хода будут подтверждены и успешно выполнены, с генерированием соответствующих транзакций.
Последующие перемещения продолжаются аналогичным образом. Каждый игрок играет по очереди, выбирая свободное место на доске. После каждого хода контракт проверяет наличие выигрышного состояния. Если игрок заполняет своим символом всю строку, колонку или диагональ, игра заканчивается, и этот игрок объявляется победителем. Переменная winner
в состоянии контракта будет обновлена соответствующим образом.
Важно отметить, что как только игрок выиграл, никакие дальнейшие ходы не действительны. Любая попытка сделать ход после окончания игры будет считаться недействительной, и соответствующая операция будет провалена.
В некоторых играх возможно, что ни один игрок не достигнет выигрышного состояния даже после того, как будет заполнено все игровое поле. В результате получается ничья. Контракт был разработан таким образом, чтобы справиться и с этой ситуацией.
Если все места на доске заполнены(nbMoves
равно 9) и ни один игрок не выиграл(победитель
остается в 0), игра объявляется ничейной. Флаг ничьей
в состоянии контракта устанавливается в True, указывая на то, что игра закончилась вничью. И снова, после этого момента никакие дальнейшие ходы не действительны. Любые попытки сделать ход после ничьей также будут безуспешными.
Вторая часть тестового сценария контракта TicTacToe демонстрирует этот сценарий розыгрыша. Он моделирует серию ходов, приводящих к ничьей, и проверяет, правильно ли контракт ее обрабатывает.