sábado, 4 de julio de 2015

Juego: Tres en raya



Esta vez repasaremos matrices, funciones, condicionales e iteraciones, todo esto aplicado en el clásico juego del tres en raya, las reglas del juego son muy conocidas, sólo haré unos cuantos razonamientos previos antes de empezar a programar:

Sobre los turnos

Sabemos que son 2 jugadores que juegan por turnos hasta que alguno gana o el tablero se llena sin ganador (situación de empate).
Vemos que debe existir una iteración que finalice cuando el juego termina:

var fin_juego = false;
var turno = 0; //los jugadores son 0 y 1

while(!fin_juego)
{
//se hace la jugada
//si se gana en este turno fin_juego = true;
//si el tablero se llena sin ganador fin_juego = true;
turno = (turno + 1) % 2; //esto es para cambiar el turno de 0 a 1 y de 1 a 0
}



Sabemos que es un tablero de 9 casillas (3 filas y 3 columnas). En principio todas las casillas están vacías y en cada turno se va llenando alguna de las casillas con la jugada hecha en el turno.
Si todas las casillas están llenas y no hay ganador, entonces es un empate.
Para controlar que el juego termine en empate creamos un condicional en cada iteración que controle si se llenó el tablero o no.

var fin_juego = false;
var turno = 0; //los jugadores son 0 y 1
var casillas_vacias = 9;

while(!fin_juego)
{
//se hace la jugada
casillas_vacias = casillas_vacias - 1; //al hacer la jugada disminuye en 1 las casillas vacías

//si se gana en este turno fin_juego = true;

//si el tablero se llena sin ganador fin_juego = true;
if(!fin_juego && casillas_vacias == 0) fin_juego = true;
turno = (turno + 1) % 2; //esto es para cambiar el turno de 0 a 1 y de 1 a 0
}

Sobre la jugada

El jugador debe seleccionar la casilla que quiere marcar, para esto utilizaremos las filas y las columnas de la matriz que representa al tablero.

var boolean fin_juego = false;
var int turno = 0; //los jugadores son 0 y 1
var int casillas_vacias = 9;
var char tablero [3][3];//matriz de 3 x 3 que representa al tablero
var int fila_jugada;
var int columna_jugada;
var char ficha='0'; //será 'X' cuando el turno sea 1

while(!fin_juego)
{
//se hace la jugada
fila_jugada = leer(); //lee de consola la fila (de 0 a 2) que selecciona el jugador en ese turno
columna_jugada = leer(); //lee de consola la columna (de 0 a 2) que selecciona el jugador en ese turno
if(turno == 0) ficha = '0'; //escoge ficha
else ficha = 'X';
tablero[fila_jugada][columna_jugada] = ficha;
casillas_vacias = casillas_vacias - 1; //al hacer la jugada disminuye en 1 las casillas vacías

//si se gana en este turno fin_juego = true;

//si el tablero se llena sin ganador fin_juego = true;
if(!fin_juego && casillas_vacias == 0) fin_juego = true;
turno = (turno + 1) % 2; //esto es para cambiar el turno de 0 a 1 y de 1 a 0
}

Sobre el control de la jugada ganadora

Cuando se coloca la ficha se hace control en vertical, horizontal y diagonales a ver si es una jugada ganadora.
Para el control horizontal, todas las fichas de la fila_jugada deben ser iguales, por tanto haremos una validación iterando las columnas.
Para el control vertical, todas las fichas de la columna_jugada deben ser iguales, por tanto haremos una validación iterando las filas.
Para el control diagonal, no es necesario realizarlo siempre, sólo cuando la jugada esté en alguna diagonal. Y sólo si está en el medio del tablero la comprobación debe ser de la doble diagonal.
Comprobar diagonal 1
fila_jugada: 0 y columna_jugada:0,
fila_jugada: 2 y columna_jugada:2

Comprobar diagonal 2
fila_jugada: 2 y columna_jugada:0,
fila_jugada: 0 y columna_jugada:2

Comprobar ambas diagonales.
fila_jugada: 1 y columna_jugada:1



Como esta lógica es un poco larga, la encapsularemos en una función y la utilizaremos en cada jugada para comprobar si la jugada es ganadora:

Entrada: ¿Qué necesito?
Tablero, fila_jugada, columna_jugada
Salida: ¿Qué quiero?
Booleano que indique si es una jugada ganadora o no
Función: ¿Cómo lo hago?
Comprobando la Horizontal, Vertical y cuando toque las diagonales.

Boolean esGanador(tablero, fila_jugada, columna_jugada)
{
Boolean jugada_ganadora = false;
//validación horizontal 
if(Tablero[fila_jugada][0] == Tablero[fila_jugada][1] &&
Tablero[fila_jugada][0] == Tablero[fila_jugada][2])
{
return true; //jugada ganadora en la horizontal, termina la ejecución
}
//validación vertical 
if(Tablero[0][columna_jugada] == Tablero[1][columna_jugada] &&
Tablero[0][columna_jugada] == Tablero[2][columna_jugada])
{
return true; //jugada ganadora en la vertical, termina la ejecución
}
//verifica la diagonal 1 (sólo si es necesario)
if( (fila_jugada == 0 && columna_jugada == 0) || (fila_jugada == 2 && columna_jugada == 2))
{
if(Tablero[0][0] == Tablero[1][1] &&
Tablero[0][0] == Tablero[2][2])
{
return true; //jugada ganadora en la diagonal 1, termina la ejecución
}
}

//verifica la diagonal 2 (sólo si es necesario)
if( (fila_jugada == 0 && columna_jugada == 2) || (fila_jugada == 2 && columna_jugada == 0))
{
if(Tablero[0][2] == Tablero[1][1] &&
Tablero[0][2] == Tablero[2][0])
{
return true; //jugada ganadora en la diagonal 2, termina la ejecución
}
}

//verifica la doble diagonal(sólo si es necesario)
if( fila_jugada == 1 && columna_jugada == 1)
{
if((Tablero[0][2] == Tablero[1][1] &&
Tablero[0][2] == Tablero[2][0]) ||
(Tablero[0][0] == Tablero[1][1] &&
Tablero[0][0] == Tablero[2][2]))
{
return true; //jugada ganadora en alguna de las diagonales, termina la ejecución
}
}


return jugada_ganadora; //sólo llega a esta línea de código cuando no es jugada ganadora
}



Incorporamos la llamada a la función en el programa principal
var boolean fin_juego = false;
var int turno = 0; //los jugadores son 0 y 1
var int casillas_vacias = 9;
var char tablero [3][3];//matriz de 3 x 3 que representa al tablero
var int fila_jugada;
var int columna_jugada;
var char ficha='0'; //será 'X' cuando el turno sea 1

while(!fin_juego)
{
//se hace la jugada
fila_jugada = leer(); //lee de consola la fila (de 0 a 2) que selecciona el jugador en ese turno
columna_jugada = leer(); //lee de consola la columna (de 0 a 2) que selecciona el jugador en ese turno
if(turno == 0) ficha = '0'; //escoge ficha
else ficha = 'X';
tablero[fila_jugada][columna_jugada] = ficha;
casillas_vacias = casillas_vacias - 1; //al hacer la jugada disminuye en 1 las casillas vacías

//si se gana en este turno fin_juego = true;
fin_juego = esGanador(tablero, fila_jugada, columna_jugada);

//si el tablero se llena sin ganador fin_juego = true;
if(!fin_juego && casillas_vacias == 0) fin_juego = true;
turno = (turno + 1) % 2; //esto es para cambiar el turno de 0 a 1 y de 1 a 0
}


Con esto tendríamos lo básico para el tres en raya, pero ¿qué pasaría si el jugador pusiera la ficha en un lugar ocupado? ¿qué pasaría si inicialmente el tablero está ocupado?¿No vendría bien agregar una impresión del tablero para que jugador sepa en cada jugada cuáles son sus opciones de juego?

¿Cómo modificaríais el programa para agregar estas funcionalidades?

Enlaces




No hay comentarios:

Publicar un comentario