Vamos começar por explorar o nosso contrato para o jogo TicTactoe:
Python
# TicTacToe - Exemplo apenas para fins ilustrativos.
importar de forma inteligente como sp
@sp .módulo
def principal ():
classe TicTacToe (SP.Contract):
def __init__(self):
Self.data.nbMoves = 0
self.data.winner = 0
self.data.draw = Falso
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 .ponto de entrada
def play (self, parâmetros):
assert self.data.winner == 0 e não self.data.draw
afirmar params.i >= 0 e param.i <3
afirmar params.j >= 0 e params.j <3
assert params.move == Self.Data.NextPlayer
afirmar 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 (vencedor=self.data.winner, line=self.data.deck [params.i])
)
self.data.winner = Self.Checkline (
sp.registro (
winner=self.data.winner,
linha ={
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.registro (
winner=self.data.winner,
linha ={
0: self.data.deck[0][0],
1: self.data.deck[1][1],
2: self.data.deck[2][2],
},
)
)
self.data.winner = Self.Checkline (
sp.registro (
winner=self.data.winner,
linha ={
0: self.data.deck[0][2],
1: self.data.deck[1][1],
2: self.data.deck[2][0],
},
)
)
se self.data.nbmove == 9 e self.data.winner == 0:
self.data.draw = Verdadeiro
@sp .privado ()
def CheckLine (auto, vencedor, linha):
vencedor_ = vencedor
se linha [0]! = 0 e linha [0] == linha [1] e linha [0] == linha [2]:
vencedor_ = linha [0]
retorno ganhador_
# Adicionar uma função de redefinição de jogo
@sp .ponto de entrada
def confirmar_e_reset (self):
afirme self.data.winner! = 0 ou self.data.draw
eu mesmo.__init__()
# Testes
se " os modelos " não estiverem em __name__:
@sp .add_test (nome = TicTacToe) " "
teste def ():
cenário = sp.test_scenario (principal)
cenário.h1 (Tic-Tac-Toe) " "
# definir um contrato
c1 = main.TicTactoe ()
# mostrar a sua representação
cenário.h2 (A " sequência de interações com um vencedor")
cenário += c1
scenario.h2 (Mensagem) " execução")
cenário.h3 (A " primeiro passo no centro")
c1.play (i=1, j=1, movimento=1)
cenário.h3 (A " movimento proibido")
c1.play (i=1, j=1, move=2) .run (válido = falso)
cenário.h3 (A " segunda jogada")
c1.play (i=1, j=2, movimento=2)
scenario.h3 (Outro " movimentos")
c1.play (i=2, j=1, movimento=1)
c1.play (i=2, j=2, movimento=2)
cenário.verify (c1.data.winner == 0)
c1.play (i=0, j=1, movimento=1)
cenário.verify (c1.data.winner == 1)
scenario.p (Jogador1 " ganhou")
c1.play (i=0, j=0, move=2) .run (válido = falso)
c2 = main.TicTactoe ()
cenário.h2 (A " sequência de interações com um empate")
cenário += c2
scenario.h2 (Mensagem) " execução")
cenário.h3 (A " primeiro passo no centro")
c2.play (i=1, j=1, movimento=1)
cenário.h3 (A " movimento proibido")
c2.play (i=1, j=1, move=2) .run (válido = falso)
cenário.h3 (A " segunda jogada")
c2.play (i=1, j=2, movimento=2)
scenario.h3 (Outro " movimentos")
c2.play (i=2, j=1, movimento=1)
c2.play (i=2, j=2, movimento=2)
c2.play (i=0, j=0, movimento=1)
c2.play (i=0, j=1, movimento=2)
c2.play (i=0, j=2, movimento=1)
c2.play (i=2, j=0, movimento=2)
c2.play (i=1, j=0, movimento=1)
# Adicionar testes para o reset do jogo
scenario.h2 (Testes " redefinição do jogo")
scenario.p (Vencedor " ou sorteio confirmado, agora reiniciando o jogo")
c1.confirm_e_reset ()
scenário.verify (C1.data.nbMoves == 0)
cenário.verify (c1.data.winner == 0)
scenario.verify (não c1.data.draw)
c2.confirm_e_reset ()
scenário.verify (c2.data.nbMoves == 0)
cenário.verify (c2.data.winner == 0)
scenario.verify (não c2.data.draw)
O contrato para o nosso jogo TicTactoe no Tezos está escrito na linguagem SmartPy. Consiste em duas partes principais: o estado do contrato e a lógica do jogo.
O estado do contrato é inicializado na função **init
. Inclui:
NBMoves
: Este é um contador para o número de movimentos feitos no jogo. Começa no zero.vencedor
: Isto mantém o registo do vencedor do jogo. Inicialmente, é zero, indicando nenhum vencedor.empate
: Esta é uma bandeira que indica se o jogo terminou num empate. Inicialmente, é falso.deck
: Esta é uma grelha 3x3 que representa a placa TicTactoe. Todos os pontos no quadro estão inicialmente vazios, representados por zeros.NextPlayer
: Isso indica de quem é a vez de jogar. O jogo começa com o jogador 1, por isso é inicialmente definido como 1.A lógica do jogo está encapsulada na função de jogo
. Realiza várias verificações para garantir uma jogada válida:
NextPlayer
.NBMoves
, muda o NextPlayer
e verifica se a jogada resultou numa vitória ou num empate.A condição de vitória é verificada ao longo da linha e coluna do último movimento, bem como nas duas diagonais.
Se todas as vagas no tabuleiro estiverem preenchidas e nenhum jogador tiver ganho (ou seja, NBMoves
é igual a 9 e o vencedor
ainda é 0), o jogo é declarado empate.
A função CheckLine
é utilizada para verificar se algum jogador ganhou. Verifica se todos os pontos numa linha (que pode ser uma linha, uma coluna ou uma diagonal) são preenchidos pelo mesmo jogador. Se sim, esse jogador é declarado o vencedor.
As interações com o contrato são representadas como transações. Quando um jogador faz um movimento chamando a função play
, gera uma transação. Esta transação é registada e pode ser vista no painel direito do IDE SmartPy:
Uma movimentação malsucedida ou inválida também geraria uma transação mas com uma indicação de erro:
A primeira jogada no nosso jogo TicTactoe é relativamente simples, uma vez que o tabuleiro de jogo está vazio. No entanto, as coisas ficam mais interessantes com o segundo movimento e movimentos subsequentes. Estes movimentos não só adicionam peças ao tabuleiro de jogo mas também invocam a lógica do jogo para verificar possíveis vencedores.
Após o primeiro movimento, o valor do NextPlayer
muda para o jogador 2. Agora, a função play
valida a jogada do jogador 2. Verificações semelhantes são realizadas para garantir que a movimentação é válida, ou seja, o ponto da grade selecionado está dentro dos limites e está vazio.
À medida que cada jogador faz um movimento, o estado do jogo evolui. O NBMoves
aumenta, o NextPlayer
muda e o baralho
é atualizado. Além disso, após cada jogada, o contrato verifica se há um vencedor ou se é um empate.
Por exemplo, depois de o primeiro jogador fazer uma jogada no centro do tabuleiro em i=1, j=1,
o segundo jogador pode jogar num ponto diferente, digamos i=1, j=2.
Ambos os movimentos seriam validados e executados com sucesso, com as transações correspondentes a serem geradas.
Os movimentos subsequentes continuam de forma semelhante. Cada jogador reveza-se para jogar, escolhendo um lugar vazio no tabuleiro. Após cada movimento, o contrato verifica qualquer condição vencedora. Se um jogador preencher uma linha inteira, coluna ou diagonal com o seu símbolo, o jogo termina e esse jogador é declarado o vencedor. A variável vencedora
no estado do contrato seria atualizada em conformidade.
É importante notar que uma vez que um jogador tenha ganho, nenhum outro movimento é válido. Qualquer tentativa de fazer uma jogada após o jogo ter terminado seria considerada inválida e a transação correspondente falharia.
Em alguns jogos, é possível que nenhum jogador atinja uma condição de vitória mesmo depois de todo o tabuleiro de jogo estar cheio. Isso resulta num empate. O contrato também foi concebido para lidar com esta situação.
Se todas as vagas no tabuleiro estiverem preenchidas (NBMoves
é igual a 9) e nenhum jogador ganhou (o vencedor
permanece 0), o jogo é declarado empate. A bandeira de sorteio
no estado do contrato está definida como Verdadeiro, indicando que o jogo terminou num empate. Mais uma vez, nenhum outro movimento é válido após este ponto. Qualquer tentativa de fazer um movimento depois de um empate também falharia.
A segunda parte do cenário de teste do contrato TicTacToe demonstra este cenário de desenho. Simula uma série de movimentos que resultam num empate e verifica se o contrato lida com isso corretamente.
Vamos começar por explorar o nosso contrato para o jogo TicTactoe:
Python
# TicTacToe - Exemplo apenas para fins ilustrativos.
importar de forma inteligente como sp
@sp .módulo
def principal ():
classe TicTacToe (SP.Contract):
def __init__(self):
Self.data.nbMoves = 0
self.data.winner = 0
self.data.draw = Falso
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 .ponto de entrada
def play (self, parâmetros):
assert self.data.winner == 0 e não self.data.draw
afirmar params.i >= 0 e param.i <3
afirmar params.j >= 0 e params.j <3
assert params.move == Self.Data.NextPlayer
afirmar 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 (vencedor=self.data.winner, line=self.data.deck [params.i])
)
self.data.winner = Self.Checkline (
sp.registro (
winner=self.data.winner,
linha ={
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.registro (
winner=self.data.winner,
linha ={
0: self.data.deck[0][0],
1: self.data.deck[1][1],
2: self.data.deck[2][2],
},
)
)
self.data.winner = Self.Checkline (
sp.registro (
winner=self.data.winner,
linha ={
0: self.data.deck[0][2],
1: self.data.deck[1][1],
2: self.data.deck[2][0],
},
)
)
se self.data.nbmove == 9 e self.data.winner == 0:
self.data.draw = Verdadeiro
@sp .privado ()
def CheckLine (auto, vencedor, linha):
vencedor_ = vencedor
se linha [0]! = 0 e linha [0] == linha [1] e linha [0] == linha [2]:
vencedor_ = linha [0]
retorno ganhador_
# Adicionar uma função de redefinição de jogo
@sp .ponto de entrada
def confirmar_e_reset (self):
afirme self.data.winner! = 0 ou self.data.draw
eu mesmo.__init__()
# Testes
se " os modelos " não estiverem em __name__:
@sp .add_test (nome = TicTacToe) " "
teste def ():
cenário = sp.test_scenario (principal)
cenário.h1 (Tic-Tac-Toe) " "
# definir um contrato
c1 = main.TicTactoe ()
# mostrar a sua representação
cenário.h2 (A " sequência de interações com um vencedor")
cenário += c1
scenario.h2 (Mensagem) " execução")
cenário.h3 (A " primeiro passo no centro")
c1.play (i=1, j=1, movimento=1)
cenário.h3 (A " movimento proibido")
c1.play (i=1, j=1, move=2) .run (válido = falso)
cenário.h3 (A " segunda jogada")
c1.play (i=1, j=2, movimento=2)
scenario.h3 (Outro " movimentos")
c1.play (i=2, j=1, movimento=1)
c1.play (i=2, j=2, movimento=2)
cenário.verify (c1.data.winner == 0)
c1.play (i=0, j=1, movimento=1)
cenário.verify (c1.data.winner == 1)
scenario.p (Jogador1 " ganhou")
c1.play (i=0, j=0, move=2) .run (válido = falso)
c2 = main.TicTactoe ()
cenário.h2 (A " sequência de interações com um empate")
cenário += c2
scenario.h2 (Mensagem) " execução")
cenário.h3 (A " primeiro passo no centro")
c2.play (i=1, j=1, movimento=1)
cenário.h3 (A " movimento proibido")
c2.play (i=1, j=1, move=2) .run (válido = falso)
cenário.h3 (A " segunda jogada")
c2.play (i=1, j=2, movimento=2)
scenario.h3 (Outro " movimentos")
c2.play (i=2, j=1, movimento=1)
c2.play (i=2, j=2, movimento=2)
c2.play (i=0, j=0, movimento=1)
c2.play (i=0, j=1, movimento=2)
c2.play (i=0, j=2, movimento=1)
c2.play (i=2, j=0, movimento=2)
c2.play (i=1, j=0, movimento=1)
# Adicionar testes para o reset do jogo
scenario.h2 (Testes " redefinição do jogo")
scenario.p (Vencedor " ou sorteio confirmado, agora reiniciando o jogo")
c1.confirm_e_reset ()
scenário.verify (C1.data.nbMoves == 0)
cenário.verify (c1.data.winner == 0)
scenario.verify (não c1.data.draw)
c2.confirm_e_reset ()
scenário.verify (c2.data.nbMoves == 0)
cenário.verify (c2.data.winner == 0)
scenario.verify (não c2.data.draw)
O contrato para o nosso jogo TicTactoe no Tezos está escrito na linguagem SmartPy. Consiste em duas partes principais: o estado do contrato e a lógica do jogo.
O estado do contrato é inicializado na função **init
. Inclui:
NBMoves
: Este é um contador para o número de movimentos feitos no jogo. Começa no zero.vencedor
: Isto mantém o registo do vencedor do jogo. Inicialmente, é zero, indicando nenhum vencedor.empate
: Esta é uma bandeira que indica se o jogo terminou num empate. Inicialmente, é falso.deck
: Esta é uma grelha 3x3 que representa a placa TicTactoe. Todos os pontos no quadro estão inicialmente vazios, representados por zeros.NextPlayer
: Isso indica de quem é a vez de jogar. O jogo começa com o jogador 1, por isso é inicialmente definido como 1.A lógica do jogo está encapsulada na função de jogo
. Realiza várias verificações para garantir uma jogada válida:
NextPlayer
.NBMoves
, muda o NextPlayer
e verifica se a jogada resultou numa vitória ou num empate.A condição de vitória é verificada ao longo da linha e coluna do último movimento, bem como nas duas diagonais.
Se todas as vagas no tabuleiro estiverem preenchidas e nenhum jogador tiver ganho (ou seja, NBMoves
é igual a 9 e o vencedor
ainda é 0), o jogo é declarado empate.
A função CheckLine
é utilizada para verificar se algum jogador ganhou. Verifica se todos os pontos numa linha (que pode ser uma linha, uma coluna ou uma diagonal) são preenchidos pelo mesmo jogador. Se sim, esse jogador é declarado o vencedor.
As interações com o contrato são representadas como transações. Quando um jogador faz um movimento chamando a função play
, gera uma transação. Esta transação é registada e pode ser vista no painel direito do IDE SmartPy:
Uma movimentação malsucedida ou inválida também geraria uma transação mas com uma indicação de erro:
A primeira jogada no nosso jogo TicTactoe é relativamente simples, uma vez que o tabuleiro de jogo está vazio. No entanto, as coisas ficam mais interessantes com o segundo movimento e movimentos subsequentes. Estes movimentos não só adicionam peças ao tabuleiro de jogo mas também invocam a lógica do jogo para verificar possíveis vencedores.
Após o primeiro movimento, o valor do NextPlayer
muda para o jogador 2. Agora, a função play
valida a jogada do jogador 2. Verificações semelhantes são realizadas para garantir que a movimentação é válida, ou seja, o ponto da grade selecionado está dentro dos limites e está vazio.
À medida que cada jogador faz um movimento, o estado do jogo evolui. O NBMoves
aumenta, o NextPlayer
muda e o baralho
é atualizado. Além disso, após cada jogada, o contrato verifica se há um vencedor ou se é um empate.
Por exemplo, depois de o primeiro jogador fazer uma jogada no centro do tabuleiro em i=1, j=1,
o segundo jogador pode jogar num ponto diferente, digamos i=1, j=2.
Ambos os movimentos seriam validados e executados com sucesso, com as transações correspondentes a serem geradas.
Os movimentos subsequentes continuam de forma semelhante. Cada jogador reveza-se para jogar, escolhendo um lugar vazio no tabuleiro. Após cada movimento, o contrato verifica qualquer condição vencedora. Se um jogador preencher uma linha inteira, coluna ou diagonal com o seu símbolo, o jogo termina e esse jogador é declarado o vencedor. A variável vencedora
no estado do contrato seria atualizada em conformidade.
É importante notar que uma vez que um jogador tenha ganho, nenhum outro movimento é válido. Qualquer tentativa de fazer uma jogada após o jogo ter terminado seria considerada inválida e a transação correspondente falharia.
Em alguns jogos, é possível que nenhum jogador atinja uma condição de vitória mesmo depois de todo o tabuleiro de jogo estar cheio. Isso resulta num empate. O contrato também foi concebido para lidar com esta situação.
Se todas as vagas no tabuleiro estiverem preenchidas (NBMoves
é igual a 9) e nenhum jogador ganhou (o vencedor
permanece 0), o jogo é declarado empate. A bandeira de sorteio
no estado do contrato está definida como Verdadeiro, indicando que o jogo terminou num empate. Mais uma vez, nenhum outro movimento é válido após este ponto. Qualquer tentativa de fazer um movimento depois de um empate também falharia.
A segunda parte do cenário de teste do contrato TicTacToe demonstra este cenário de desenho. Simula uma série de movimentos que resultam num empate e verifica se o contrato lida com isso corretamente.