RYG: el C64 por fin decide su jugada #Programación retro del Commodore 64

¡¡Por fin el C64 va a decidir su jugada!! ¿¿No es emocionante??

🙂

No sé si seréis conscientes, pero para llegar hasta aquí hemos tenido que recorrer todo este camino:

  • Generar las jugadas o movimientos básicos de los gatos.
  • Generar tableros hijo a partir de un tablero padre, aplicando un movimiento.
  • Generar el primer nivel del árbol de juego.
  • Corregir la validación de jugadas, que tenía errores.
  • Generar un árbol de juego de profundidad N aplicando recursividad.
  • Evaluar tableros aplicando criterios posicionales.
  • Evaluar el árbol de juego completo con la función de evaluación.
  • Pintar el árbol de juego completo con sus evaluaciones y vinculaciones entre tableros.
  • Evaluar las hojas del árbol con la función de evaluación, y llevar estas evaluaciones hasta la raíz con el procedimiento minimax.

Todo este camino es para eso: ¡¡para que el C64 decida su jugada!! El camino ha sido tan largo que es fácil perder la perspectiva…

Gráficamente, la situación en la que nos encontramos es ésta:

Minimax - raíz2

Es decir, tenemos un tablero de partida (raíz del árbol), este tablero tiene una serie de hijos (posibles movimientos de los gatos) y, tras desarrollar el árbol de juego hasta una profundidad N y evaluarlo con minimax, hemos llegado a unas valoraciones para los hijos e, incluso, nos hemos quedado con la menor de ellas (la más beneficiosa para los gatos: $82). Por tanto, ya sólo se trata de algo tan sencillo como optar por el hijo que tenga esa valoración mínima.

En este caso particular se ha producido un empate, porque todos los tableros hijo han sido valorados con $82. Por tanto, podemos optar por el primero de ellos, el último de ellos, elegir uno aleatoriamente, o tomar el que más rabia nos dé.

Si queremos darle emoción al asunto, y que el C64 juegue de una forma más imprevisible, podemos apoyarnos en el Jiffy Clock (posiciones $a0 – $a1 – $a2) para elegir uno de los tableros empatados de forma aleatoria. A estas alturas, y con el objeto de simplificar, optaremos por el primero de los tableros en empate.

Lo importante es no tomar el caso particular por el general. En un caso general, especialmente cuando las partidas estén más avanzadas, el C64 tendrá que elegir entre puntuaciones que serán dispares.

Para optar por el hijo de puntuación mínima hacemos lo siguiente:

Rutina "decideJugadaMin":

En el fichero "EvalTableros.asm" dotamos una nueva rutina "decideJugadaMin" que, dado un tablero padre evaluado con minimax, determina el hijo que ha dado lugar a esa evaluación, es decir, determina el hijo con menor puntuación.

Primero recuperamos el valor del padre:

Rutina decideJugadaMin - parte1

Y luego recorremos los hijos buscando al que aporta esa valoración:

Rutina decideJugadaMin - parte2

Por último, cuando damos con el hijo que aporta esa valoración ("beq djmFin"), nos quedamos con los datos de ese hijo (número de hijo y dirección):

Rutina decideJugadaMin - parte3

Obsérvese que en caso de empate entre varios hijos estaríamos optando por el primero, puesto que en cuanto encontramos un hijo con la valoración correcta nos quedamos con él. Aquí es donde se podría meter aleatoriedad para darle más emoción al asunto.

Nuevo programa principal "RYG.asm":

Ahora que ya sabemos localizar al mejor hijo, al predilecto, vamos a optar por él. Para ello, volvemos a modificar el programa principal "RYG.asm":

Programa principal - decisión

Es decir, tras la evaluación del árbol con minimax:

  • Dejamos de pintar el árbol. Hasta ahora veníamos pintando el árbol para depurar la función de evaluación y el procedimiento minimax.
  • Optamos por la jugada de menor puntuación con "decideJugadaGatos".
  • Aplicamos esa jugada con "aplicaJugadaDecidida", igual que en su momento aplicamos la jugada elegida por el usuario humano con "aplicaJugadaSolicitada".
  • Y cerramos el bucle de juego con "jmp actualiza", que vuelve a pintar el tablero actual (ya actualizado) y vuelve a pedir la jugada del humano.

Respecto a la rutina "decideJugadaGatos" básicamente es una llamada a la ya presentada "decideJugadaMin":

Rutina decideJugadaGatos

Y respecto a la rutina "aplicaJugadaDecidida", consiste en copiar el hijo elegido sobre el tablero actual, el que controla la situación actual de la partida, y hacer alguna labor menor de inicialización:

Rutina aplicaJugadaDecidida

Resultado:

El resultado es la versión 14 del proyecto, que prácticamente ya está terminado. El juego está casi completo, ya que permite jugar al humano y al C64 de forma continuada, una jugada tras otra.

Queda detectar si la partida ha terminado, es decir, si tras un movimiento han ganado el ratón o los gatos. Pero esto ya lo haremos en la entrada siguiente.


Código del proyecto: RYG14


Editar

Josepzin

No hay comentarios:

Publicar un comentario