domingo, 16 de octubre de 2016

Capítulo 77. Programando mi primer video juego en Small Basic Parte 4

Continuación del tutorial anterior...

Para hacerlo aún más completo, vamos a hacer que el juego nos indique un ganador, con lo cual dibujará una línea horizontal, vertical o diagonal, cuando un jugador lo haya logrado.
Para lograr esto, lo que voy a hacer es sumar las filas, columnas o diagonales de la matriz, recordemos que las X valen 1 mientras que los O valen 9, por lo tanto si completo por ejemplo una fila de X, entonces la suma será de 3, en cambio si completo una de O la suma será 27. Para manejar estos datos crearé una subrutina a la cual llamaré “SumaMatriz”

Sub SumaMatriz'Y raya final
  'raya horizontal superior
  If matriz[1][1] + matriz[1][2] + matriz[1][3] = 3 Or matriz[1][1] + matriz[1][2] + matriz[1][3] = 27 Then
    GraphicsWindow.PenWidth = 5
    GraphicsWindow.DrawLine(50,85,320,85)
  EndIf
EndSub

(Nota: La condición if debe estar en una sola línea. Por cuestiones de espacio horizontal es que se ve en dos líneas)
Como se puede ver, dejé una línea comentada indicando “raya horizontal superior” lo cual indica que este código es para dibujar una línea en la primera fila. Esta subrutina detecta que si la suma de los valores de la primera fila es igual a 3 o 27, entonces dibujará una línea. A esta subrutina la invoco desde aquí:

  'ubicacion 1,1
  If gmX >= 85 And gmX <= 145 And gmY >= 65 And gmY <= 105 Then
    If matriz[1][1] = 0 Then
      GraphicsWindow.DrawLine(100,70,130,100)
      GraphicsWindow.DrawLine(100,100,130,70)
      matriz[1][1] = 1
      inter()
      SumaMatriz()
     EndIf
   EndIf
 
  'ubicacion 1,2
  If gmX >= 155 And gmX <= 215 And gmY >= 65 And gmY <= 105 Then
    If matriz[1][2] = 0 Then
      GraphicsWindow.DrawLine(170,70,200,100)
      GraphicsWindow.DrawLine(170,100,200,70)
      matriz[1][2] = 1
      inter()
      SumaMatriz()
    EndIf
  EndIf
 
  'ubicacion 1,3
  If gmX >= 225 And gmX <= 285 And gmY >= 65 And gmY <= 105 Then
    If matriz[1][3] = 0 Then
      GraphicsWindow.DrawLine(240,70,270,100)
      GraphicsWindow.DrawLine(240,100,270,70)
      matriz[1][3] = 1
      inter()
      SumaMatriz()
     EndIf
   EndIf
La ubicación 1,1 a la 1,3 corresponde a la primera línea, por lo tanto, cada vez que se dibuje una figura en estas casillas, se estará comprobando la suma de la fila.
Veamos ahora como funciona. Ejecutemos el programa y comprobemos la primera línea:


Se ve que funciona, así que haremos lo mismo para cada una de las filas restantes, columnas y diagonales.
Entonces, esto quedaría de la siguiente manera:
Sub SumaMatriz'Y raya final****************************************************
  'raya horizontal superior
  If matriz[1][1] + matriz[1][2] + matriz[1][3] = 3 Or matriz[1][1] + matriz[1][2] + matriz[1][3] = 27 Then
    GraphicsWindow.PenWidth = 5
    GraphicsWindow.DrawLine(50,85,320,85)
  EndIf
 
    'raya horizontal media
  If matriz[2][1] + matriz[2][2] + matriz[2][3] = 3 Or matriz[2][1] + matriz[2][2] + matriz[2][3] = 27 Then
    GraphicsWindow.PenWidth = 5
    GraphicsWindow.DrawLine(50,140,320,140)
  EndIf
 
  'raya horizontal inferior
  If matriz[3][1] + matriz[3][2] + matriz[3][3] = 3 Or matriz[3][1] + matriz[3][2] + matriz[3][3] = 27 Then
    GraphicsWindow.PenWidth = 5
    GraphicsWindow.DrawLine(50,195,320,195)
  EndIf
 
  'raya vertical izquierda
  If matriz[1][1] + matriz[2][1] + matriz[3][1] = 3 Or matriz[1][1] + matriz[2][1] + matriz[3][1] = 27 Then
    GraphicsWindow.PenWidth = 5
    GraphicsWindow.DrawLine(115,30,115,250)
  EndIf
 
  'raya vertical centro
  If matriz[1][2] + matriz[2][2] + matriz[3][2] = 3 Or matriz[1][2] + matriz[2][2] + matriz[3][2] = 27 Then
    GraphicsWindow.PenWidth = 5
    GraphicsWindow.DrawLine(185,30,185,250)
  EndIf
 
  'raya vertical derecha
  If matriz[1][3] + matriz[2][3] + matriz[3][3] = 3 Or matriz[1][3] + matriz[2][3] + matriz[3][3] = 27 Then
    GraphicsWindow.PenWidth = 5
    GraphicsWindow.DrawLine(255,30,255,250)
  EndIf
 
  'raya diagonal sup. izq. a der.
  If matriz[1][1] + matriz[2][2] + matriz[3][3] = 3 Or matriz[1][1] + matriz[2][2] + matriz[3][3] = 27 Then
    GraphicsWindow.PenWidth = 5
    GraphicsWindow.DrawLine(90,60,280,220)
  EndIf
 
  'raya diagonal inf. izq. a der.
  If matriz[3][1] + matriz[2][2] + matriz[1][3] = 3 Or matriz[3][1] + matriz[2][2] + matriz[1][3] = 27 Then
    GraphicsWindow.PenWidth = 5
    GraphicsWindow.DrawLine(90,220,280,60)
  EndIf
EndSub
No olvidar llamar a la subrutina SumaMatriz() desde las subrutinas figuraX y figuraO, así como en el siguiente ejemplo:
  If gmX >= 85 And gmX <= 145 And gmY >= 65 And gmY <= 105 Then
    If matriz[1][1] = 0 Then
      GraphicsWindow.DrawLine(100,70,130,100)
      GraphicsWindow.DrawLine(100,100,130,70)
      matriz[1][1] = 1
      inter()
      SumaMatriz()
     EndIf
   EndIf

Al ejecutar el programa podemos ver que funciona tanto en sus lineas horizontales, verticales y diagonales, pero hay otro pequeño inconveniente. Y es que luego de que el juego ha “finalizado” dibujando la raya, lo jugadores aún pueden seguir seleccionando casillas. Es como si en un partido de futbol, el arbitro  da por finalizado el partido pero los jugadores siguen pateando la pelota. Para solucionar este pequeño inconveniente, se me ocurre marcar las casillas que quedaron disponibles (en realidad lo que hago es marcarlas todas) ya que esas casillas, al tener un valor de cero, pueden ser escritas, pero si modifico su valor al finalizar el juego, entonces los jugadores no podrán hacer clic y marcarlas porque no se cumpliría la condición (De que la casilla tenga valor de cero). Por eso, crearé una nueva subrutina que me permita re escribir la matriz, rellenandola con un valor distinto de cero, por ejemplo 2.

Sub RellenaMatriz
  For fila = 1 To 3
    For columna = 1 To 3
      matriz[fila][columna] = 2
    EndFor
  EndFor
EndSub

Ahora, lo que voy a hacer es llamar a esta subrutina justo después de crear la raya que da por finalizado el juego, así los jugadores no podrán seleccionar las casillas que quedaron disponible.

  If matriz[1][1] + matriz[1][2] + matriz[1][3] = 3 Or matriz[1][1] + matriz[1][2] + matriz[1][3] = 27 Then
    GraphicsWindow.PenWidth = 5
    GraphicsWindow.DrawLine(50,85,320,85)
    RellenaMatriz()
  EndIf
Al ejecutar el programa, podemos ver que una vez finalizado el juego, los jugadores ya no podrán seguir rellenando las casillas vacías.

REINICIANDO EL JUEGO
Ahora que el juego ya ha decidido un ganador, lo ideal sería poder reiniciarlo y no tener que cerrarlo y volverlo a ejecutar para seguir jugando otra ronda.
Para ello voy a crear un botón que me permita reiniciar el juego cuando este ha concluido.
Para que este botón no se encuentre visible sino hasta que el juego finalice, debe estar dentro de una subrutina. La que voy a crear es la siguiente:

Sub Reinicio
  Controls.AddButton("Reiniciar",150,240)
  Controls.ButtonClicked = BtnReinicio
EndSub

Entonces, lo que este botón hará será borrar la pantalla y luego llamar a la subrutina inicio() para volver a empezar desde el principio. Esto quedaría más o menos así:

Sub BtnReinicio
  GraphicsWindow.Clear()
  inicio()
EndSub

Ahora, solo queda llamar a la subrutina Reinicio() cuando un jugador gane la partida. Esto se hará bajo estas líneas de código:

  'raya horizontal superior
  If matriz[1][1] + matriz[1][2] + matriz[1][3] = 3 Or matriz[1][1] + matriz[1][2] + matriz[1][3] = 27 Then
    GraphicsWindow.PenWidth = 5
    GraphicsWindow.DrawLine(50,85,320,85)
    RellenaMatriz()
    Reinicio()
  EndIf

En primer lugar vamos a probar si funciona el código con la primera fila. Ejecutemos el código:


Muy bien, probado el código podemos ver que se genera el botón y que además permite reiniciar el juego. Entonces solo queda agregar la llamada a la subrutina Reinicio() desde las otras condiciones que finalizan el juego.
Un detalle que me di cuenta al estar probando el juego, fue que hace falta agregar un botón "reiniciar" si se produce un empate.
¿Pero cómo le indicamos al programa que se produjo un empate?  Se me ocurren varias alternativas, una puede ser el crear un sistema de puntajes, donde al iniciar el juego, ambos empiezan con cero puntos, si uno de ellos gana entonces se le asigna un valor de 1 y se produce un empate si los puntajes se mantienen en cero... Otra alternativa (que es la que ocuparé) es un poco más sencilla y consiste en contar la cantidad de clics válidos, aprovechando de que ya tenemos un contador de clics. Agreguemos nuevamente una línea TextWindow para ver en qué valor termina nuestro contador al producirse un empate.

Sub inter
  interruptor = interruptor + 1
  TextWindow.WriteLine(interruptor)
EndSub

Al ejecutar el programa, esto es lo que aparece:


Vemos que la variable "interruptor" finaliza en 10 al producirse un empate. Entonces usaremos ese valor para llamar a la subrutina que contiene el botón. Lo vamos a hacer de la siguiente manera:
Sub inter
  interruptor = interruptor + 1
  If interruptor = 10 Then
    Reinicio()
  EndIf
EndSub
Al probar el juego y producir un empate, vemos que el código funciona:


Ahora sí, la mecánica principal del juego se encuentra lista. Ya se puede jugar y volver a reiniciar el juego cuantas veces queramos.
Esto es todo por ahora, en el próximo tutorial agregaré la última parte que me falta y con eso se daría término a este proyecto, el cual en un futuro cercano pretendo actualizar. Saludos.

Gustavo J. Cerda Nilo
Julio 2016, Octubre 2016


No hay comentarios:

Publicar un comentario

C++ El apuntador This

El apuntador This En C++, cada objeto tiene acceso a su propia dirección a través de un puntero o apuntador denominado This. Lo...