Otro juego sencillo: Tres en raya

Volvamos a otro clásico sencillo, que nos ayude a desconectar de proyectos más avanzados y recordar lo básico. En este caso, será un juego de "Tres en raya", en el que, por turnos, los jugadores traten de colocar tres fichas en una línea horizontal, vertical o diagonal.

Esta primera versión será en modo consola, y ni siquiera incluirá ningún detalle avanzado de consola, como colores o borrado de pantalla.

El pseudocódigo del juego podría ser algo como:


Repetir:
    - Dibujar el tablero
    - Preguntar movimiento al jugador 1
    - Dibujar la casilla del jugador 1 (o todo el tablero)
    - Si no ha terminado la partida:
        + Preguntar movimiento al jugador 2
        + Dibujar la casilla del jugador 2 (o todo el tablero)
        + Comprobar si ha terminado la partida
Hasta 3 en raya o empate (tablero lleno)

Y la apariencia sería totalmente sobria, así:

3 en raya 1

Para implementarlo, basta con crear un "Main" que siga esa misma idea, convirtiendo cada uno de los pasos en una función:

/* --------------------------------------------------
Tres en raya básico en consola, por Nacho. Pseudocodigo:
 
Repetir:
    - Dibujar el tablero
    - Preguntar movimiento al jugador 1
    - Dibujar la casilla del jugador 1 (o todo el tablero)
    - Si no ha terminado la partida:
        + Preguntar movimiento al jugador 2
        + Dibujar la casilla del jugador 2 (o todo el tablero)
        + Comprobar si ha terminado la partida
Hasta 3 en raya o empate (tablero lleno)
 ---------------------------------------------------- */
 
using System;
 
public class TresEnRaya1
{
    static int[,] tablero;
    static bool terminado;
    static char[] simbolo = {' ', 'O', 'X'};
 
    public static void Main()
    {
        terminado = false;
        tablero = new int[3,3];
 
        // Dibujar el tablero inicial
        DibujarTablero();
        do
        {
            // Pedir al jugador
            PreguntarPosicion( 1 );
            // Dibujar la casilla del jugador 1 (o todo)
            DibujarTablero();
            // Comprobar si ha terminado la partida
            terminado = ComprobarGanador();
            if (terminado)
                Console.WriteLine("Gana jugador 1");
            else
            {
                terminado = ComprobarEmpate();
                if (terminado)
                    Console.WriteLine("Empate!");
                else
                {
                    // Pedir al jugador 2
                    PreguntarPosicion( 2 );
                    // Dibujar la casilla del jugador 2 (o todo)
                    DibujarTablero();
                    // Comprobar si ha terminado la partida
                    terminado = ComprobarGanador();
                    if (terminado)
                        Console.WriteLine("Gana jugador 2");
                }
            }
        }
        // Repetir hasta 3 en raya o empate (tablero lleno)
        while ( ! terminado );
    }
 
    // ----- Dibujar todo el tablero, incluyendo piezas ----- 
    static void DibujarTablero()
    {
        Console.WriteLine();
        Console.WriteLine("-------------");
        for (byte fila = 0; fila < 3; fila ++)
        {
            Console.Write("|");
            for (byte columna = 0; columna < 3; columna++)
                Console.Write(" "+simbolo[tablero[fila,columna]]+" |");
            Console.WriteLine();
            Console.WriteLine("-------------");
        }
    }
 
 
    // ----- Pregunta donde mover y lo anota en el tablero ----- 
    static void PreguntarPosicion( byte jugador )  // 1 = Jug.1, 2= Jug.2
    {
        int fila, columna;
        do
        {
            Console.WriteLine();
 
            // Pido fila
            do
            {
                Console.Write("En que fila (1 a 3) ");
                fila = Convert.ToByte( Console.ReadLine() ) - 1;
            }
            while ((fila < 0) || (fila > 2));
 
            // Pido columna
            do
            {
                Console.Write("En que columna (1 a 3) ");
                columna = Convert.ToByte( Console.ReadLine() ) - 1;
            }
            while ((columna < 0) || (columna > 2));
 
            if (tablero[fila,columna] != 0)
                Console.WriteLine("Casilla ocupada!");
 
        }
        while (tablero[fila,columna] != 0);
 
        // Si todo es correcto, se la asigno
        tablero[fila,columna] = jugador;
    }
 
 
    // ----- Devuelve "true" si hay tres en raya -----
    // (para mirar tras cada movimiento, y saber si acaba de ganar)
    static bool ComprobarGanador()
    {
        bool hay3enRaya = false;
 
        // Si en alguna fila todas las casillas son iguales y no vacias
        for (byte fila = 0; fila < 3; fila ++)
            if ((tablero[fila, 0] == tablero[fila, 1])
                    && (tablero[fila, 0] == tablero[fila, 2])
                    && (tablero[fila, 0] != 0)) 
                hay3enRaya = true;
 
        // Lo mismo para las columnas
        for (byte columna = 0; columna < 3; columna++)
            if ((tablero[0,columna] == tablero[1,columna])
                    && (tablero[0,columna] == tablero[2,columna])
                    && (tablero[0,columna] != 0))
                hay3enRaya = true;
 
        // Y finalmente miro las dos diagonales
        if ((tablero[0, 0] == tablero[1, 1])
                && (tablero[0, 0] == tablero[2, 2])
                && (tablero[0, 0] != 0)) 
            hay3enRaya = true;
        if ((tablero[0, 2] == tablero[1, 1])
                && (tablero[0, 2] == tablero[2, 0])
                && (tablero[0, 2] != 0)) 
            hay3enRaya = true;
 
        return hay3enRaya;
    }
 
 
    // ----- Devuelve "true" si hay empate -----
    static bool ComprobarEmpate()
    {        
        // Si no quedan huecos donde mover, es empate
        bool algunHueco = false;
 
        for (byte fila = 0; fila < 3; fila ++)  // Buscamos huecos
            for (byte columna = 0; columna < 3; columna++)
                if(tablero[fila,columna] == 0)
                    algunHueco = true;
 
        return ! algunHueco;  // Y si no hay huecos... empate
    }
}