Programación de un juego de Tic Tac Toe

La programación de juegos de computadora puede ser el trabajo técnicamente más desafiante (y posiblemente el mejor pagado) que puede tener un programador. Los juegos de nivel superior requieren lo mejor tanto de los programadores como de las computadoras..

Visual Basic 6 ahora se ha pasado por alto como una plataforma para la programación de juegos. (Nunca fue realmente uno. Incluso en los "buenos viejos tiempos", los programadores serios nunca usarían un lenguaje de alto nivel como VB 6 porque simplemente no se podía obtener el rendimiento de vanguardia que la mayoría de los juegos requieren). El sencillo juego "Tic Tac Toe" es una gran introducción a la programación que es un poco más avanzada que "Hello World".

Esta es una gran introducción a muchos de los conceptos fundamentales de la programación, ya que combina técnicas que incluyen:

  • El uso de matrices. Los marcadores X y O se guardan en matrices separadas y las matrices completas se pasan entre funciones para realizar un seguimiento del progreso del juego..
  • Uso de gráficos de nivel VB 6: VB 6 no ofrece una gran capacidad gráfica, pero el juego es una buena introducción a lo que está disponible. Gran parte del resto de esta serie es una exploración de cómo GDI +, la próxima generación de gráficos de Microsoft, reemplaza a los gráficos de nivel VB 6.
  • Uso de cálculos matemáticos para el control del programa: el programa usa módulos inteligentes (Mod) y cálculos de división de enteros usando las matrices de marcadores de dos juegos para determinar cuándo se ha producido una "victoria" de tres elementos.

La clase de programación en este artículo es quizás un poco más allá del nivel inicial, pero debería ser buena para los programadores "intermedios". Pero comencemos en un nivel elemental para ilustrar algunos de los conceptos y comenzar con su carrera de programación de juegos de Visual Basic. Incluso los estudiantes más avanzados que eso pueden encontrar que es un poco difícil obtener los objetos en la forma correcta.

Cómo jugar Tic Tac Toe

Si nunca has jugado al Tic Tac Toe, estas son las reglas. Dos jugadores se alternan colocando Xs y Os en el campo de juego 3 x 3.

Antes de que comience el juego, ambos jugadores deben acordar quién irá primero y quién marcará sus movimientos con qué símbolo. Después del primer movimiento, los jugadores colocan alternativamente sus marcas en cualquier celda vacía. El objetivo del juego es ser el primer jugador con tres marcas en una línea horizontal, diagonal o vertical. Si no hay celdas vacías y ninguno de los jugadores tiene una combinación ganadora, el juego es un empate.

Iniciando el programa

Antes de comenzar cualquier codificación real, siempre es una buena idea cambiar los nombres de los componentes que use. Una vez que comience a codificar, Visual Basic usará el nombre automáticamente, por lo que desea que sea el nombre correcto. Usaremos el nombre del formulario frmTicTacToe y también cambiaremos el título a "Acerca de Tic Tac Toe".

Con el formulario establecido, use el control de caja de herramientas de línea para dibujar una cuadrícula de 3 x 3. Haga clic en la herramienta de línea, luego dibuje una línea donde lo desee. Tendrá que crear cuatro líneas de esta manera y ajustar su longitud y posición para que se vean bien. Visual Basic también tiene algunas herramientas convenientes en el menú Formato que ayudarán. Esta es una gran oportunidad para practicar con ellos..

Además de la cuadrícula de juego, necesitaremos algunos objetos para los símbolos X y O que se colocarán en la cuadrícula. Como hay nueve espacios en la cuadrícula, crearemos una matriz de objetos con nueve espacios, llamados elementos en Visual Basic.

Hay varias formas de hacer casi todo en el entorno de desarrollo de Visual Basic, y la creación de matrices de control no es una excepción. Probablemente la forma más fácil es crear la primera etiqueta (hacer clic y dibujar como la herramienta de línea), nombrarla, establecer todos los atributos (como Font y ForeColor) y luego hacer copias de ella. VB 6 le preguntará si desea crear una matriz de control. Use el nombre lblPlayGround para la primera etiqueta.

Para crear los otros ocho elementos de la cuadrícula, seleccione el primer objeto de etiqueta, establezca la propiedad Index en cero y presione CTRL + C (copiar). Ahora puede presionar CTRL + V (pegar) para crear otro objeto de etiqueta. Cuando copie objetos como este, cada copia heredará todas las propiedades excepto el índice de la primera. El índice aumentará en uno por cada copia. Esta es una matriz de control porque todos tienen el mismo nombre, pero diferentes valores de índice.

Si crea la matriz de esta manera, todas las copias se apilarán una encima de la otra en la esquina superior izquierda del formulario. Arrastre cada etiqueta a una de las posiciones de la cuadrícula de juego. Asegúrese de que los valores del índice sean secuenciales en la cuadrícula. La lógica del programa depende de ello. El objeto de etiqueta con el valor de índice 0 debe estar en la esquina superior izquierda, y la etiqueta de abajo a la derecha debe tener el índice 8. Si las etiquetas cubren la cuadrícula de reproducción, seleccione cada etiqueta, haga clic con el botón derecho y seleccione Enviar al reverso.

Dado que hay ocho formas posibles de ganar el juego, necesitaremos ocho líneas diferentes para mostrar la victoria en la grilla de juego. Utilizará la misma técnica para crear otra matriz de control. Primero, dibuje la línea, asígnele el nombre linWin y establezca la propiedad Index en cero. Luego use la técnica de copiar y pegar para producir siete líneas más. La siguiente ilustración muestra cómo configurar los números de índice correctamente.

Además de la etiqueta y los objetos de línea, necesita algunos botones de comando para jugar y más etiquetas para mantener la puntuación. Los pasos para crearlos no se detallan aquí, pero estos son los objetos que necesita.

Dos objetos de botón:

  • cmdNewGame
  • cmdResetScore

Objeto de marco fraPlayFirst que contiene dos botones de opción:

  • optXPlayer
  • optOPlayer

Objeto de marco fraScoreBoard que contiene seis etiquetas. Solo lblXScore y lblOScore se cambian en el código del programa.

  • lblX
  • lblXScore
  • lblO
  • lblOScore
  • lblMinus
  • lblColon

Finalmente, también necesita el objeto de etiqueta lblStartMsg para 'enmascarar' el botón cmdNewGame cuando no se debe hacer clic en él. Esto no es visible en la siguiente ilustración porque ocupa el mismo espacio en el formulario que el botón de comando. Puede que tenga que mover el botón de comando temporalmente para dibujar esta etiqueta en el formulario.

Hasta ahora, no se ha realizado ninguna codificación VB, pero finalmente estamos listos para hacerlo..

Inicialización

Ahora finalmente puedes comenzar a codificar el programa. Si aún no lo ha hecho, puede descargar el código fuente para seguirlo mientras se explica el funcionamiento del programa..

Una de las primeras decisiones de diseño que debe tomar es cómo realizar un seguimiento del "estado" actual del juego. En otras palabras, cuáles son las X y Os actuales en la cuadrícula de juego y quién se mueve a continuación. El concepto de 'estado' es crítico en mucha programación, y en particular, es importante en la programación de ASP y ASP.NET para la web

Hay varias maneras de hacer esto, por lo que es un paso crítico en el análisis. Si estaba resolviendo este problema por su cuenta, es posible que desee dibujar un diagrama de flujo y probar diferentes opciones con 'papel de borrador' antes de comenzar cualquier codificación.

Variables

Nuestra solución utiliza dos "matrices bidimensionales" porque eso ayuda a realizar un seguimiento del "estado" simplemente cambiando los índices de la matriz en los bucles del programa. El estado de la esquina superior izquierda estará en el elemento de matriz con índice (1, 1), la esquina superior derecha estará en (1, 3), la esquina inferior derecha en (3,3), y así sucesivamente . Las dos matrices que hacen esto son:

iXPos (x, y)

y

iOPos (x, y)

Hay muchas maneras diferentes de hacer esto y la solución final de VB.NET de esta serie le muestra cómo hacerlo con una sola matriz unidimensional.

La programación para traducir estos conjuntos en decisiones ganadoras del jugador y pantallas visibles en el formulario se encuentran en la página siguiente.

También necesita algunas variables globales de la siguiente manera. Observe que están en el código General y Declaraciones para el formulario. Esto los convierte en variables de "nivel de módulo" a las que se puede hacer referencia en cualquier parte del código para este formulario. Para obtener más información al respecto, consulte Comprender el alcance de las variables en la Ayuda de Visual Basic.

Hay dos áreas donde las variables se inicializan en nuestro programa. Primero, se inicializan algunas variables mientras se carga el formulario frmTicTacToe.

Private Sub Form_Load ()

En segundo lugar, antes de cada nuevo juego, todas las variables que deben restablecerse a los valores iniciales se asignan en una subrutina de inicialización.

Sub InitPlayGround ()

Tenga en cuenta que la inicialización de carga de formulario también llama a la inicialización del patio de recreo.

Una de las habilidades críticas de un programador es la capacidad de utilizar las instalaciones de depuración para comprender lo que está haciendo el código. Puedes usar este programa para probar:

  • Recorriendo el código con la tecla F8
  • Configurar un reloj en variables clave, como sPlaySign o iMove
    Establecer un punto de interrupción y consultar el valor de las variables. Por ejemplo, en el bucle interno de la inicialización:
lblPlayGround ((i - 1) * 3 + j - 1) .Caption = ""

Tenga en cuenta que este programa muestra claramente por qué es una buena práctica de programación mantener los datos en matrices siempre que sea posible. Si no tuviera matrices en este programa, tendría que escribir código como este:

Line0.Visible = False
Line1.Visible = False
Line2.Visible = False
Line3.Visible = False
Line4.Visible = False
Line5.Visible = False
Line6.Visible = False
Line7.Visible = False

en lugar de esto:

Para i = 0 a 7
linWin (i) .Visible = False
Siguiente yo

Haciendo un movimiento

Si alguna parte del sistema puede considerarse como 'el corazón', es la subrutina lblPlayGround_Click. Esta subrutina se llama cada vez que un jugador hace clic en la cuadrícula de juego. (Los clics deben estar dentro de uno de los nueve elementos lblPlayGround). Observe que esta subrutina tiene un argumento: (Índice como entero). La mayoría de las otras 'subrutinas de eventos', como cmdNewGame_Click () no lo hacen. El índice indica en qué objeto de la etiqueta se ha hecho clic. Por ejemplo, el índice contendría el valor cero para la esquina superior izquierda de la cuadrícula y el valor ocho para la esquina inferior derecha.

Después de que un jugador hace clic en un cuadrado en la cuadrícula del juego, el botón de comando para iniciar otro juego, cmdNewGame, se "activa" haciéndolo visible. El estado de este botón de comando tiene doble función porque también se usa como una variable de decisión booleana más tarde en el programa. Normalmente se desaconseja el uso de un valor de propiedad como variable de decisión porque si alguna vez se hace necesario cambiar el programa (por ejemplo, para hacer que el botón de comando cmdNewGame sea visible todo el tiempo), entonces el programa fallará inesperadamente porque es posible que no recuerde que también se usa como parte de la lógica del programa. Por esta razón, siempre es una buena idea buscar a través del código del programa y verificar el uso de cualquier cosa que cambie al realizar el mantenimiento del programa, incluso los valores de propiedad. regla en parte para hacer este punto y en parte porque es un código relativamente simple donde es más fácil ver lo que se está haciendo y evitar problemas más adelante.

La selección de un jugador de un cuadro de juego se procesa llamando a la subrutina GamePlay con Index como argumento.

Procesando el movimiento

Primero, verifica si se hizo clic en un cuadrado desocupado.

Si lblPlayGround (xo_Move) .Caption = "" Entonces

Una vez que estamos seguros de que este es un movimiento legítimo, el contador de movimientos (iMove) se incrementa. Las siguientes dos líneas son muy interesantes ya que traducen las coordenadas de la matriz unidimensional del componente If lblPlayGround a índices bidimensionales que puede usar en iXPos o iOPos. Mod y la división entera (la 'barra invertida') son operaciones matemáticas que no se usan todos los días, pero aquí hay un gran ejemplo que muestra cómo pueden ser muy útiles..

 Si lblPlayGround (xo_Move) .Caption = "" Entonces
iMove = iMove + 1
x = Int (xo_Move / 3) + 1
y = (xo_Move Mod 3) + 1

El valor de xo_Move 0 se traducirá a (1, 1), 1 a (1, 2) ... 3 a (2, 1) ... 8 a (3, 3).

El valor en sPlaySign, una variable con alcance de módulo, realiza un seguimiento de qué jugador realizó el movimiento. Una vez que se actualizan las matrices de movimiento, los componentes de la etiqueta en la cuadrícula de juego se pueden actualizar con el signo apropiado.

Si sPlaySign = "O" Entonces
iOPos (x, y) = 1
iWin = CheckWin (iOPos ())
Más
iXPos (x, y) = 1
iWin = CheckWin (iXPos ())
Terminara si
lblPlayGround (xo_Move) .Caption = sPlaySign

Por ejemplo, cuando el jugador X hace clic en la esquina superior izquierda de la cuadrícula, las variables tendrán los siguientes valores:

La pantalla del usuario muestra solo una X en el cuadro superior izquierdo, mientras que el iXPos tiene un 1 en el cuadro superior izquierdo y 0 en todos los demás. El iOPos tiene 0 en cada caja.

Los valores cambian cuando el jugador O hace clic en el cuadrado central de la cuadrícula. Ahora, iOPos muestra un 1 en el cuadro central, mientras que la pantalla del usuario muestra una X en la esquina superior izquierda y una O en el cuadro central. El iXPos muestra solo el 1 en la esquina superior izquierda, con 0 en todos los otros cuadros.

Ahora que sabe dónde hizo clic un jugador y qué jugador hizo clic (usando el valor en sPlaySign), todo lo que tiene que hacer es averiguar si alguien ganó un juego y descubrir cómo mostrarlo en la pantalla.

Encontrar un ganador

Después de cada movimiento, la función CheckWin verifica la combinación ganadora. CheckWin funciona sumando cada fila, a través de cada columna y a través de cada diagonal. El seguimiento de los pasos a través de CheckWin utilizando la función de depuración de Visual Basic puede ser muy educativo. Encontrar una victoria es cuestión de verificar primero si se encontraron tres 1 en cada una de las comprobaciones individuales en la variable iScore, y luego devolver un valor único de "firma" en Checkwin que se utiliza como índice de matriz para cambiar la propiedad Visible de un elemento en la matriz de componentes linWin. Si no hay ganador, CheckWin contendrá el valor -1. Si hay un ganador, la pantalla se actualiza, se cambia el marcador, se muestra un mensaje de felicitación y se reinicia el juego..

Veamos uno de los controles en detalle para ver cómo funciona. Los otros son similares.

'Comprobar filas para 3
Para i = 1 a 3
iScore = 0
CheckWin = CheckWin + 1
Para j = 1 a 3
iScore = iScore + iPos (i, j)
Siguiente j
Si iScore = 3 entonces
Función de salida
Terminara si
Siguiente yo

Lo primero que debe notar es que el primer contador de índice i cuenta hacia atrás las filas mientras que el segundo j cuenta a través de las columnas. El bucle externo, luego simplemente se mueve de una fila a la siguiente. El bucle interno cuenta los 1 en la fila actual. Si hay tres, entonces tienes un ganador.

Tenga en cuenta que también realiza un seguimiento del número total de cuadrados probados en la variable CheckWin, que es el valor que se devuelve cuando finaliza esta función. Cada combinación ganadora terminará con un valor único en CheckWin de 0 a 7 que se utiliza para seleccionar uno de los elementos en la matriz de componentes linWin (). ¡Esto hace que el orden del código en la función CheckWin también sea importante! Si movió uno de los bloques de código de bucle (como el anterior), se dibujaría una línea incorrecta en la cuadrícula de juego cuando alguien gana. Pruébalo y mira!

Detalles de acabado

El único código aún no discutido es la subrutina para un nuevo juego y la subrutina que restablecerá el puntaje. El resto de la lógica en el sistema hace que crearlos sea bastante fácil. Para comenzar un nuevo juego, solo tiene que llamar a la subrutina InitPlayGround. Para comodidad de los jugadores, ya que se puede hacer clic en el botón en medio de un juego, se solicita confirmación antes de continuar. También solicita confirmación antes de reiniciar el marcador.