Bài học 3

Desarrollando un juego TicTacToe en Tezos

El mundo de los juegos blockchain está lleno de oportunidades para los desarrolladores. Proporciona una forma única e innovadora de integrar mecanismos descentralizados y transparentes en los juegos. Al desarrollar juegos en una cadena de bloques, podemos incorporar características como transacciones seguras y transparentes, propiedad de los activos del juego y más. En esta lección, entraremos en los juegos blockchain desarrollando un juego clásico de TicTacToe en la blockchain de Tezos. Nuestro objetivo con esta lección es comprender la dinámica de la lógica del juego y la gestión del estado en un juego basado en blockchain.

Comencemos explorando nuestro contrato para el juego TicTacToe:

Estructura del contrato

Python 
 # TicTacToe: ejemplo solo con fines ilustrativos.

importar smartpy como sp 


 @sp.module 
 def main(): 
 clase 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.entrypoint 
 def play(self, params): 
 afirmar self.data.winner == 0 y no self.data.draw 
 afirmar params.i >= 0 y parámetros.i < 3 
 afirmar params.j >= 0 y parámetros.j < 3 
 afirmar 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(ganador=self.data.ganador, línea=self.data.deck[params.i])
            ) 
 self.datos.ganador = self.checkLine(
                sp.record( 
 ganador=self.data.ganador,
                    línea={
                        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( 
 ganador=self.data.ganador,
                    línea={
                        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( 
 ganador=self.data.ganador,
                    línea ={
                        0: self.data.deck[0][2],
                        1: self.data.deck[1][1],
                        2: self.data.deck[2][0],
                    }, 
 ) 
 ) 
 si self.data.nbMoves == 9 y self.data.winner == 0: 
 self.data.draw = True 

 @sp.private() 
 def checkLine(self , ganador, línea): 
 ganador_ = ganador 
 si línea[0] != 0 y línea[0] == línea[1] y línea[0] == línea[2]: 
 ganador_ = línea[0] 
 return ganador_ 

 # Agregar una función de reinicio del juego 
 @sp.entrypoint 
 def confirm_and_reset(self): 
 afirmar self.data.winner! = 0 o self.data.draw 
 self.__init__()

# Pruebas 
 si las "plantillas" no están en __name__: 

 @sp.add_test(name="TicTacToe") 
 def test(): 
 escenario = sp.test_scenario(main)
        escenario.h1("Tic-Tac-Toe")
        # definir un contrato 
 c1 = main.TicTacToe() 

 # mostrar su representación 
 escenario.h2("A secuencia de interacciones con un ganador") 
 escenario += c1 
 escenario.h2("Mensaje ejecución") 
 escenario.h3("A primer movimiento en el centro") 
 c1.play(i=1, j=1, movimiento=1) 
 escenario.h3("A movimiento prohibido") 
 c1.play(i=1, j=1, move=2).run(valid=False)
        escenario.h3("A segundo movimiento") 
 c1.play(i=1, j=2, movimiento=2) 
 escenario.h3("Otro movimientos") 
 c1.play(i=2, j=1, movimiento=1) 
 c1.play(i=2, j=2, movimiento=2) 
 escenario.verify(c1.data.winner == 0 ) 
 c1.play(i=0, j=1, mover=1) 
 escenario.verify(c1.data.winner == 1) 
 escenario.p("Jugador1 ha ganado") 
 c1.play(i=0, j=0, move=2).run(valid=False)

        c2 = principal.TicTacToe() 
 escenario.h2("A secuencia de interacciones con un empate") 
 escenario += c2 
 escenario.h2("Mensaje ejecución") 
 escenario.h3("A primer movimiento en el centro") 
 c2.play(i=1, j=1, movimiento=1) 
 escenario.h3("A movimiento prohibido") 
 c2.play(i=1, j=1, move=2).run(valid=False)
        escenario.h3("A segundo movimiento") 
 c2.play(i=1, j=2, movimiento=2) 
 escenario.h3("Otro mueve") 
 c2.play(i=2, j=1, movimiento=1) 
 c2.play(i=2, j=2, movimiento=2) 
 c2.play(i=0, j=0, mover=1) 
 c2.play(i=0, j=1, mover=2) 
 c2.play(i=0, j=2, mover=1) 
 c2.play(i=2, j=0 , move=2) 
 c2.play(i=1, j=0, move=1) 

 # Agregar pruebas para reiniciar el juego 
 escenario.h2("Pruebas reinicio del juego") 
 escenario.p("Ganador o sorteo confirmado, ahora reiniciando el juego") 
 c1.confirm_and_reset() 
 escenario.verify(c1.data.nbMoves == 0) 
 escenario.verify(c1.data.winner == 0) 
 escenario.verify(no c1.datos.draw)

        c2.confirm_and_reset() 
 escenario.verify(c2.data.nbMoves == 0) 
 escenario.verify(c2.data.winner == 0) 
 escenario.verify(no c2.datos.draw)

El contrato de nuestro juego TicTacToe en Tezos está escrito en lenguaje SmartPy. Consta de dos partes principales: el estado del contrato y la lógica del juego.

Estado del contrato

El estado del contrato se inicializa en la función **init . Incluye:

  • nbMoves: Este es un contador del número de movimientos realizados en el juego. Comienza en cero.
  • winner: Esto realiza un seguimiento del ganador del juego. Inicialmente, es cero, lo que indica que no hay ganador.
  • draw: Esta es una bandera que indica si el juego ha terminado en empate. Inicialmente, es falso.
  • deck: Esta es una cuadrícula de 3x3 que representa el tablero TicTacToe. Todos los espacios del tablero están inicialmente vacíos y representados por ceros.
  • nextPlayer: Esto indica a quién le toca jugar. El juego comienza con el jugador 1, por lo que inicialmente está configurado en 1.

Lógica del juego

La lógica del juego está resumida en la función play . Realiza varias comprobaciones para garantizar un movimiento válido:

  • Comprueba que ningún jugador haya ganado todavía y que el juego no sea un empate.
  • Verifica que los índices para el punto de la cuadrícula elegido por el jugador estén dentro de los límites de la cuadrícula.
  • Se asegura de que el jugador que realiza el movimiento coincida con el nextPlayer.
  • Asegura que el lugar elegido en la cuadrícula esté vacío.
    Una vez que se realiza un movimiento, la lógica del juego incrementa los nbMoves, cambia el nextPlayer y verifica si el movimiento resultó en una victoria o un empate.

La condición de ganancia se verifica en la fila y columna del último movimiento, así como en las dos diagonales.

Si todos los espacios en el tablero están ocupados y ningún jugador ha ganado (es decir, nbMoves equivale a 9 y winner sigue siendo 0), el juego se declara empatado.

Comprobando una victoria

La función checkLine se utiliza para comprobar si algún jugador ha ganado. Comprueba si todos los espacios de una línea (que puede ser una fila, una columna o una diagonal) están ocupados por el mismo jugador. Si es así, ese jugador es declarado ganador.

Interactuar con el contrato

Las interacciones con el contrato se representan como transacciones. Cuando un jugador realiza un movimiento llamando a la función play , genera una transacción. Esta transacción se registra y se puede ver en el panel derecho del IDE de SmartPy:

Un movimiento fallido o no válido también generaría una transacción pero con una indicación de error:

El segundo movimiento y más allá

El primer movimiento en nuestro juego TicTacToe es relativamente sencillo ya que el tablero de juego está vacío. Sin embargo, las cosas se ponen más interesantes con el segundo movimiento y los siguientes. Estos movimientos no sólo añaden piezas al tablero de juego, sino que también invocan la lógica del juego para buscar posibles ganadores.

Después del primer movimiento, el valor nextPlayer cambia al jugador 2. Ahora, la función play valida el movimiento del jugador 2. Se realizan comprobaciones similares para garantizar que el movimiento sea válido, es decir, que el punto de la cuadrícula seleccionado esté dentro de los límites y esté vacío.

A medida que cada jugador realiza un movimiento, el estado del juego evoluciona. Los nbMoves aumentan, el nextPlayer cambia y el deck se actualiza. Además, después de cada movimiento, el contrato comprueba si hay un ganador o si hay empate.

Por ejemplo, después de que el primer jugador hace un movimiento en el centro del tablero en i=1, j=1, el segundo jugador puede jugar en un lugar diferente, digamos i=1, j=2. Ambos movimientos se validarían y ejecutarían con éxito, generándose las transacciones correspondientes.

Los otros movimientos y la progresión del juego

Los movimientos posteriores continúan de manera similar. Cada jugador se turna para jugar, eligiendo un lugar vacío en el tablero. Después de cada movimiento, el contrato comprueba si hay alguna condición ganadora. Si un jugador llena una fila, columna o diagonal completa con su símbolo, el juego termina y ese jugador es declarado ganador. La variable winner en el estado del contrato se actualizará en consecuencia.

Es importante tener en cuenta que una vez que un jugador ha ganado, no son válidos más movimientos. Cualquier intento de realizar un movimiento una vez finalizado el juego se considerará inválido y la transacción correspondiente fracasará.

El escenario del sorteo

En algunos juegos, es posible que ningún jugador logre una condición ganadora incluso después de que se haya llenado todo el tablero. Esto resulta en un empate. El contrato también ha sido diseñado para manejar esta situación.

Si se llenan todos los espacios del tablero (nbMoves equivale a 9) y ningún jugador ha ganado (winner sigue siendo 0), el juego se declara empatado. La bandera draw en el estado del contrato se establece en Verdadero, lo que indica que el juego terminó en empate. Una vez más, no hay más movimientos válidos después de este punto. Cualquier intento de hacer un movimiento después de un empate también fracasaría.

La segunda parte del escenario de prueba del contrato TicTacToe demuestra este escenario de dibujo. Simula una serie de movimientos que resultan en un empate y verifica que el contrato lo maneja correctamente.

Tuyên bố từ chối trách nhiệm
* Đầu tư tiền điện tử liên quan đến rủi ro đáng kể. Hãy tiến hành một cách thận trọng. Khóa học không nhằm mục đích tư vấn đầu tư.
* Khóa học được tạo bởi tác giả đã tham gia Gate Learn. Mọi ý kiến chia sẻ của tác giả không đại diện cho Gate Learn.
Danh mục
Bài học 3

Desarrollando un juego TicTacToe en Tezos

El mundo de los juegos blockchain está lleno de oportunidades para los desarrolladores. Proporciona una forma única e innovadora de integrar mecanismos descentralizados y transparentes en los juegos. Al desarrollar juegos en una cadena de bloques, podemos incorporar características como transacciones seguras y transparentes, propiedad de los activos del juego y más. En esta lección, entraremos en los juegos blockchain desarrollando un juego clásico de TicTacToe en la blockchain de Tezos. Nuestro objetivo con esta lección es comprender la dinámica de la lógica del juego y la gestión del estado en un juego basado en blockchain.

Comencemos explorando nuestro contrato para el juego TicTacToe:

Estructura del contrato

Python 
 # TicTacToe: ejemplo solo con fines ilustrativos.

importar smartpy como sp 


 @sp.module 
 def main(): 
 clase 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.entrypoint 
 def play(self, params): 
 afirmar self.data.winner == 0 y no self.data.draw 
 afirmar params.i >= 0 y parámetros.i < 3 
 afirmar params.j >= 0 y parámetros.j < 3 
 afirmar 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(ganador=self.data.ganador, línea=self.data.deck[params.i])
            ) 
 self.datos.ganador = self.checkLine(
                sp.record( 
 ganador=self.data.ganador,
                    línea={
                        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( 
 ganador=self.data.ganador,
                    línea={
                        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( 
 ganador=self.data.ganador,
                    línea ={
                        0: self.data.deck[0][2],
                        1: self.data.deck[1][1],
                        2: self.data.deck[2][0],
                    }, 
 ) 
 ) 
 si self.data.nbMoves == 9 y self.data.winner == 0: 
 self.data.draw = True 

 @sp.private() 
 def checkLine(self , ganador, línea): 
 ganador_ = ganador 
 si línea[0] != 0 y línea[0] == línea[1] y línea[0] == línea[2]: 
 ganador_ = línea[0] 
 return ganador_ 

 # Agregar una función de reinicio del juego 
 @sp.entrypoint 
 def confirm_and_reset(self): 
 afirmar self.data.winner! = 0 o self.data.draw 
 self.__init__()

# Pruebas 
 si las "plantillas" no están en __name__: 

 @sp.add_test(name="TicTacToe") 
 def test(): 
 escenario = sp.test_scenario(main)
        escenario.h1("Tic-Tac-Toe")
        # definir un contrato 
 c1 = main.TicTacToe() 

 # mostrar su representación 
 escenario.h2("A secuencia de interacciones con un ganador") 
 escenario += c1 
 escenario.h2("Mensaje ejecución") 
 escenario.h3("A primer movimiento en el centro") 
 c1.play(i=1, j=1, movimiento=1) 
 escenario.h3("A movimiento prohibido") 
 c1.play(i=1, j=1, move=2).run(valid=False)
        escenario.h3("A segundo movimiento") 
 c1.play(i=1, j=2, movimiento=2) 
 escenario.h3("Otro movimientos") 
 c1.play(i=2, j=1, movimiento=1) 
 c1.play(i=2, j=2, movimiento=2) 
 escenario.verify(c1.data.winner == 0 ) 
 c1.play(i=0, j=1, mover=1) 
 escenario.verify(c1.data.winner == 1) 
 escenario.p("Jugador1 ha ganado") 
 c1.play(i=0, j=0, move=2).run(valid=False)

        c2 = principal.TicTacToe() 
 escenario.h2("A secuencia de interacciones con un empate") 
 escenario += c2 
 escenario.h2("Mensaje ejecución") 
 escenario.h3("A primer movimiento en el centro") 
 c2.play(i=1, j=1, movimiento=1) 
 escenario.h3("A movimiento prohibido") 
 c2.play(i=1, j=1, move=2).run(valid=False)
        escenario.h3("A segundo movimiento") 
 c2.play(i=1, j=2, movimiento=2) 
 escenario.h3("Otro mueve") 
 c2.play(i=2, j=1, movimiento=1) 
 c2.play(i=2, j=2, movimiento=2) 
 c2.play(i=0, j=0, mover=1) 
 c2.play(i=0, j=1, mover=2) 
 c2.play(i=0, j=2, mover=1) 
 c2.play(i=2, j=0 , move=2) 
 c2.play(i=1, j=0, move=1) 

 # Agregar pruebas para reiniciar el juego 
 escenario.h2("Pruebas reinicio del juego") 
 escenario.p("Ganador o sorteo confirmado, ahora reiniciando el juego") 
 c1.confirm_and_reset() 
 escenario.verify(c1.data.nbMoves == 0) 
 escenario.verify(c1.data.winner == 0) 
 escenario.verify(no c1.datos.draw)

        c2.confirm_and_reset() 
 escenario.verify(c2.data.nbMoves == 0) 
 escenario.verify(c2.data.winner == 0) 
 escenario.verify(no c2.datos.draw)

El contrato de nuestro juego TicTacToe en Tezos está escrito en lenguaje SmartPy. Consta de dos partes principales: el estado del contrato y la lógica del juego.

Estado del contrato

El estado del contrato se inicializa en la función **init . Incluye:

  • nbMoves: Este es un contador del número de movimientos realizados en el juego. Comienza en cero.
  • winner: Esto realiza un seguimiento del ganador del juego. Inicialmente, es cero, lo que indica que no hay ganador.
  • draw: Esta es una bandera que indica si el juego ha terminado en empate. Inicialmente, es falso.
  • deck: Esta es una cuadrícula de 3x3 que representa el tablero TicTacToe. Todos los espacios del tablero están inicialmente vacíos y representados por ceros.
  • nextPlayer: Esto indica a quién le toca jugar. El juego comienza con el jugador 1, por lo que inicialmente está configurado en 1.

Lógica del juego

La lógica del juego está resumida en la función play . Realiza varias comprobaciones para garantizar un movimiento válido:

  • Comprueba que ningún jugador haya ganado todavía y que el juego no sea un empate.
  • Verifica que los índices para el punto de la cuadrícula elegido por el jugador estén dentro de los límites de la cuadrícula.
  • Se asegura de que el jugador que realiza el movimiento coincida con el nextPlayer.
  • Asegura que el lugar elegido en la cuadrícula esté vacío.
    Una vez que se realiza un movimiento, la lógica del juego incrementa los nbMoves, cambia el nextPlayer y verifica si el movimiento resultó en una victoria o un empate.

La condición de ganancia se verifica en la fila y columna del último movimiento, así como en las dos diagonales.

Si todos los espacios en el tablero están ocupados y ningún jugador ha ganado (es decir, nbMoves equivale a 9 y winner sigue siendo 0), el juego se declara empatado.

Comprobando una victoria

La función checkLine se utiliza para comprobar si algún jugador ha ganado. Comprueba si todos los espacios de una línea (que puede ser una fila, una columna o una diagonal) están ocupados por el mismo jugador. Si es así, ese jugador es declarado ganador.

Interactuar con el contrato

Las interacciones con el contrato se representan como transacciones. Cuando un jugador realiza un movimiento llamando a la función play , genera una transacción. Esta transacción se registra y se puede ver en el panel derecho del IDE de SmartPy:

Un movimiento fallido o no válido también generaría una transacción pero con una indicación de error:

El segundo movimiento y más allá

El primer movimiento en nuestro juego TicTacToe es relativamente sencillo ya que el tablero de juego está vacío. Sin embargo, las cosas se ponen más interesantes con el segundo movimiento y los siguientes. Estos movimientos no sólo añaden piezas al tablero de juego, sino que también invocan la lógica del juego para buscar posibles ganadores.

Después del primer movimiento, el valor nextPlayer cambia al jugador 2. Ahora, la función play valida el movimiento del jugador 2. Se realizan comprobaciones similares para garantizar que el movimiento sea válido, es decir, que el punto de la cuadrícula seleccionado esté dentro de los límites y esté vacío.

A medida que cada jugador realiza un movimiento, el estado del juego evoluciona. Los nbMoves aumentan, el nextPlayer cambia y el deck se actualiza. Además, después de cada movimiento, el contrato comprueba si hay un ganador o si hay empate.

Por ejemplo, después de que el primer jugador hace un movimiento en el centro del tablero en i=1, j=1, el segundo jugador puede jugar en un lugar diferente, digamos i=1, j=2. Ambos movimientos se validarían y ejecutarían con éxito, generándose las transacciones correspondientes.

Los otros movimientos y la progresión del juego

Los movimientos posteriores continúan de manera similar. Cada jugador se turna para jugar, eligiendo un lugar vacío en el tablero. Después de cada movimiento, el contrato comprueba si hay alguna condición ganadora. Si un jugador llena una fila, columna o diagonal completa con su símbolo, el juego termina y ese jugador es declarado ganador. La variable winner en el estado del contrato se actualizará en consecuencia.

Es importante tener en cuenta que una vez que un jugador ha ganado, no son válidos más movimientos. Cualquier intento de realizar un movimiento una vez finalizado el juego se considerará inválido y la transacción correspondiente fracasará.

El escenario del sorteo

En algunos juegos, es posible que ningún jugador logre una condición ganadora incluso después de que se haya llenado todo el tablero. Esto resulta en un empate. El contrato también ha sido diseñado para manejar esta situación.

Si se llenan todos los espacios del tablero (nbMoves equivale a 9) y ningún jugador ha ganado (winner sigue siendo 0), el juego se declara empatado. La bandera draw en el estado del contrato se establece en Verdadero, lo que indica que el juego terminó en empate. Una vez más, no hay más movimientos válidos después de este punto. Cualquier intento de hacer un movimiento después de un empate también fracasaría.

La segunda parte del escenario de prueba del contrato TicTacToe demuestra este escenario de dibujo. Simula una serie de movimientos que resultan en un empate y verifica que el contrato lo maneja correctamente.

Tuyên bố từ chối trách nhiệm
* Đầu tư tiền điện tử liên quan đến rủi ro đáng kể. Hãy tiến hành một cách thận trọng. Khóa học không nhằm mục đích tư vấn đầu tư.
* Khóa học được tạo bởi tác giả đã tham gia Gate Learn. Mọi ý kiến chia sẻ của tác giả không đại diện cho Gate Learn.