TP1 - 4 en línea

Como primer trabajo práctico se solicita desarrollar una versión del juego 4 en línea para dos jugadores.

Acá unos links para probar el juego en el explorador web:

Explicación del juego

  • El juego generalmente se desarrolla en un tablero de tamaño 6x7 (siendo esto seis filas y siete columnas), pero nuestra versión admitirá cualquier tamaño NxM.
  • El cuatro en línea se juega de a dos jugadores que toman turnos, X y O. El tablero comienza vacío y X puede colocar el primer símbolo, continúa O, vuelve a X, y así sucesivamente.
    • En el juego real se utilizan fichas de dos colores diferentes para representar a los jugadores, pero para simplificar nuestra implementación optaremos por los caracteres X y O.
  • El jugador del turno actual puede colocar su símbolo en una columna determinada, donde este símbolo caerá hacia la posición más baja y vacía, quedando en su posición final.
    • Si una columna se encuentra llena (es decir que todos sus casilleros se encuentran ocupados por símbolos), no se pueden colocar más símbolos en dicha columna.
  • El juego termina cuando se cumpla una de estas condiciones:
    • Hay un 4 en línea en alguna parte del tablero. Es decir, hay cuatro símbolos iguales que forman una línea horizontal, vertical, o diagonal en alguna parte del tablero. El jugador de dicho símbolo es el ganador de la partida.
    • Todos los casilleros se llenaron, llegando a un empate.

Una posible representación de un juego 6x7 que pasó por la siguiente secuencia:

  • Empieza con X insertando un símbolo en la cuarta columna
  • Luego O inserta un símbolo en la tercer columna
  • Sigue con X insertando otro símbolo en la tercer columna

...tendría este estilo:

| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | |X| | | | |
| | |O|X| | | |

Supongamos que el juego sigue, y eventualmente X gana por un cuatro en línea en diagonal, podría tener este estilo:

| | | | | | | |
| | | | | | | |
| | |X|O| | | |
| | |O|X| | | |
| | |X|O|X| | |
| |O|O|X|X|X|O|

Objetivo del trabajo práctico

Se busca realizar una implementación del 4 en línea que se pueda jugar de a dos jugadores humanos, desde la terminal, permitiendo tableros de cualquier dimensión NxM, con N y M mayores o iguales a cuatro y menores a diez.

Material

Primera parte: Lógica del juego

La primera parte del trabajo práctico consiste en implementar la lógica del juego. Para ello se deberán implementar las funciones que están definidas dentro del archivo cuatro_en_linea.py de modo de cumplir con el contrato que especifica su documentación.

Las diferentes funciones nos permitirán llevar las responsabilidades del juego hacia código. Cada una responde a una acción o pregunta:

  • Acción - empezar un nuevo juego: crear_tablero
  • Acción - colocar el próximo símbolo en una columna: insertar_simbolo
  • Pregunta - ¿de quién es el turno?: es_turno_de_x
  • Pregunta - ¿tenemos un ganador?: obtener_ganador
  • Pregunta - ¿el tablero está completo?: tablero_completo

Con esto podemos manejar toda la lógica del juego. El código relacionado al programa (que suele incluir interacción con el usuario mediante las funciones print e input) deberá realizarse para la segunda parte del trabajo práctico.

Las funciones definidas en el cuatro_en_linea.py serán útiles para:

  • Manejar el programa de la segunda parte del trabajo práctico
  • Reutilizarlas y facilitar la lógica de otras funciones dentro del mismo archivo cuatro_en_linea.py
  • Verificar el funcionamiento del módulo en su totalidad, mediante el archivo cuatro_en_linea_test.py

Se admite crear otras funciones auxiliares en el archivo cuatro_en_linea.py si se considera necesario, pero no se permite eliminar las funciones definidas en el archivo base, ni tampoco cambiar sus parámetros o tipo de retorno.

Adicionalmente, tampoco se permite el uso de variables globales (pero sí el de constantes).

El detalle específico sobre qué debe hacer cada función está indicado en su respectiva documentación. Dentro del archivo existen varias definiciones como la siguiente:

def crear_tablero(n_filas: int, n_columnas: int) -> List[List[str]]:
    """Crea un nuevo tablero de cuatro en línea, con dimensiones
    n_filas por n_columnas.
    Para todo el módulo `cuatro_en_linea`, las cadenas reconocidas para los
    valores de la lista de listas son las siguientes:
        - Celda vacía: ' '
        - Celda con símbolo X: 'X'
        - Celda con símbolo O: 'O'

    PRECONDICIONES:
        - n_filas y n_columnas son enteros positivos mayores a tres.

    POSTCONDICIONES:
        - la función devuelve un nuevo tablero lleno de casilleros vacíos
          que se puede utilizar para llamar al resto de las funciones del
          módulo.

    EJEMPLO:
        >>> crear_tablero(4, 5)
        [
            [' ', ' ', ' ', ' ', ' '],
            [' ', ' ', ' ', ' ', ' '],
            [' ', ' ', ' ', ' ', ' '],
            [' ', ' ', ' ', ' ', ' ']
        ]
    """

La estructura del tablero

La primera función a implementar será crear_tablero, y habrás notado que se espera un valor del tipo de dato ya definido: una lista de listas de cadenas. No se puede cambiar el tipo de dato del tablero, debe ser explícitamente una lista de listas de cadenas donde cada cadena solo puede tomar los valores ' ', 'X', o 'O'.

Un ejemplo de estado posible para un tablero válido sería el siguiente:

[
    [' ', ' ', ' ', ' ', ' '],
    [' ', ' ', ' ', 'O', ' '],
    [' ', ' ', 'X', 'X', ' '],
    ['X', 'O', 'O', 'X', ' ']
]

Dicha estructura nos servirá para llevar adelante toda una partida de cuatro en línea. El resto de las funciones del módulo reciben un tablero que esperan esta estructura.

Pruebas

Para saber si su implementación está funcionando correctamente deberán ejecutar el archivo cuatro_en_linea_test.py, que correrá un conjunto de pruebas automáticas y les indicará si su implementación está funcionando correctamente.

Para utilizarlo, copiá el archivo cuatro_en_linea_test.py en la misma carpeta que cuatro_en_linea.py, y ejecutá:

python3 cuatro_en_linea_test.py

Nota: Las pruebas automáticas están para simplificar el desarrollo y ofrecerles un feedback rápido sobre si su código está funcionando o no. Es necesario para la entrega que las pruebas pasen, pero esto no implica que el trabajo esté aprobado. Las pruebas no contemplan todos los casos posibles.

Cada prueba es una función dentro del archivo cuatro_en_linea_test.py. Si alguna prueba falla, te recomendamos que leas el código de la prueba para ver cuál es el caso que falla y cómo solucionar el problema.

Sobre la condición de victoria

La función más complicada de la Parte 1 es obtener_ganador, que verifica si hay un 4 en línea en horizontal, vertical, o diagonal. En esta subsección se incluye una ayuda para encarar dicha función, pero recomendamos primero que lo intentes hacer por tu cuenta, y si no te sale recurras al texto incluido acá.

Ayuda para condición de victoria.

Segunda parte: Interfaz de usuario

Finalizada la lógica de juego, deberán implementar una interfaz de usuario que permita jugar al 4 en línea en un nuevo archivo main.py. El programa debe pedirle al usuario las dimensiones N y M para hacer el tamaño del tablero NxM (con N y M entre 4 y 10) para luego comenzar el juego. El programa finaliza cuando haya un ganador o todas las columnas se encuentren llenas.

Los requerimientos para la interfaz son:

  • Debe mostrarse el tablero en un formato agradable para el usuario.
    • Debe incluirse una ayuda visual para identificar las coordenadas de la celda, a los bordes del tablero.
    • Con "un formato agradable" sería evitando el uso de un simple print(grilla) o algún uso de print que resulte en la visualización de corchetes o comas resultantes por imprimir una lista de Python.
  • Una vez creado el tablero, se le debe indicar al usuario de quién es el turno y en qué columna quiere colocar la próxima ficha.
  • En cualquier momento a lo largo de la ejecución el programa no debe explotar. El código también debe realizar todas las validaciones correspondientes para que las entradas del usuario no finalicen el programa con un error.
  • Debe incluirse una tecla para finalizar el juego actual.

A continuación les dejamos un ejemplo de una interfaz de usuario para que tengan como referencia. No es necesario que sea idéntica, tómenla como una guía.

Demo

Recomendaciones

  • Investigar el uso de las funciones str.ljust y str.rjust para mostrar un tablero alineado. No es necesario su uso, pero tenerlas en cuenta.
  • Recordar que cuatro_en_linea es un módulo y debe importarse/usarse en main.py como tal:
import cuatro_en_linea

def main():
    tablero = cuatro_en_linea.crear_tablero(...)

main()

Restricciones y condiciones de entrega

  • La entrega debe pasar todas las pruebas para ser considerada como tal.
  • No se permite el uso de ninguna biblioteca externa.
  • El código debe estar correctamente modularizado y seguir las convenciones y buenas prácticas establecidas por el lenguaje y el curso.
  • El uso de módulos de la biblioteca estándar de Python deberá ser previamente autorizado por un docente.
  • No se permite el uso de funcion(*argumentos).
  • No se permite el uso de variables globales (sí el de constantes!).
  • No se permite el uso de eval.

Entrega

La corrección de los trabajos a partir del TP1 serán por la plataforma GitHub. Para esto será necesario crearse una cuenta de GitHub e indicarnos el usuario antes de realizar la entrega al sistema.

En total, la secuencia completa de entrega y corrección tiene los siguientes pasos:

  1. Llená el siguiente formulario para indicarnos la cuenta de GitHub. Si no tenés cuenta, te podés crear una en https://github.com/ usando el mail que quieras.
  2. Subí los archivos cuatro_en_linea.py y main.py en nuestra página de entregas.
  3. Una vez realizada la entrega te debería llegar un mail de una invitación a un repositorio de GitHub con tu entrega. Será necesario aceptar la invitación pues la misma vence a los 7 días una vez realizada.
  4. Tu ayudante hará la corrección en este repositorio de GitHub y te lo indicará al estar disponible.