Top

Cargando cosas bonitas...

Recargar...

Programando el Juego de los Chinos en C++


code-machineHace unas cuantas semanas nos pusieron como práctica de la asignatura Fundamentos de la Programación crear un juego. Se trataba del famoso juego de los chinos. Es un buen ejercicio para alguien que recién acaba de empezar en el mundo de la programación ya que utiliza la mayor parte de las cosas fundamentales de la programación (condicionales, bucles while, do-while, for, lectura y escritura de un archivo, funciones, procedimientos, etc). La práctica estaba organizada en diferentes versiones que iban poco a poco aumentando las funcionalidades del programa. La última versión ya era capaz de jugar una partida automática entre dos máquinas teniendo una de ellas cierta inteligencia.

La forma más tradicional de jugar es que cada jugador dispone de tres monedas y en cada ronda puede sacar 0, 1, 2 o 3 en su mano derecha. Entonces cada jugador, por turno, dice una cifra –su apuesta- intentando adivinar cuántas monedas suman todas las manos, de manera que no se puede repetir una cifra ya dicha por otro. Las reglas de evolución de la partida pueden ser variadas: ‘a la caída’ (el que gana la ronda se retira y se continúan las rondas hasta que sólo queda un jugador), ‘a un marcador de 3 rondas ganadas’ (el que gana 3 rondas se retira y se continúa hasta que sólo queda un jugador), etc. Y una cosa importante… para no confundir a los demás jugadores ¡no se puede mentir! Es decir, un jugador no puede apostar por un número de monedas que sea inviable de acuerdo con las monedas que él ha sacado. Por ejemplo, suponiendo que haya dos jugadores, un jugador debe apostar por un número de monedas que sea mayor o igual que el número de monedas que él ha sacado y menor o igual que el número de monedas que él ha sacado más el número máximo de monedas de que dispone el rival.

cplusplus-logoUna vez iniciado el juego, en cada ronda los jugadores (máquina y humano) decidirán cuántas monedas sacan (disponen de 3) y dirán cuántas creen que hay en total (primero la máquina y después el humano). El programa impedirá que el humano mienta en su apuesta –obligándole a decir una cifra viable– así como que repita la cifra dicha por la máquina. El programa decidirá quién gana cada ronda, indicando entonces la elección hecha por la máquina. El programa deberá permitir jugar todas las rondas que sean necesarias hasta que haya un jugador que consiga 2 rondas ganadas, es decir, vamos a jugar en base a ‘marcador de 2 rondas ganadas’.

Una vez determinado el ganador de la partida el programa indicará quién es, así como el número de rondas ganadas por el perdedor.

Detalles de la implementación

La solución de la práctica debía incluir como mínimo los siguientes subprogramas, sin embargo como verás más adelante en el código yo he optado por usar algún subprograma más como uno que lee la configuración del juego:

  • int monedasHumano(): devuelve el número de monedas que saca el jugador humano, quién introduce el valor por teclado. Debe controlar la validez del dato (¡no se pueden sacar más de NUMMONEDAS monedas!) y permitir repetir la introducción del dato por teclado todas las veces que sea necesario hasta que no haya error.
  • int apuestaHumano(int eleccionM, int numMonedasH): devuelve el número de monedas elegidas por el humano en la apuesta, controlando que el humano no mienta y que no repita la elección de la máquina. Tiene como parámetros la apuesta de la máquina (eleccionM) y el nº de monedas sacadas por el humano (numMonedasH). Si el humano miente o repite la elección de la máquina el programa le reprenderá y el proceso de introducción de la apuesta se repetirá tantas veces como sea necesario hasta que el humano cumpla las reglas del juego.
  • int quienGana(int numMonedasM, int numMonedasH, int eleccionM, int eleccionH): devuelve un valor que indica quién gana la ronda (MAQUINA si gana la máquina; HUMANO si gana el humano) o que nadie ha acertado (NADIE). Tiene como parámetros las monedas sacadas por la máquina y por el humano (numMonedasM y numMonedasH, respectivamente) así como la apuesta de la máquina y la del humano (eleccionM y eleccionH, respectivamente).
  • int menu(): muestra el menú, pide la opción y la devuelve como resultado. Sólo devolverá una opción válida (esto es, en el intervalo [0,4]).
  • int pedirMarcador(): lee de teclado y devuelve un valor de marcador válido.
  • int pedirMonedas(): lee de teclado y devuelve un número de monedas válido.
  • bool mostrarReglas(): si el archivo reglas.txt no se encuentra devolverá false; en otro caso devuelve true. Si el archivo se encuentra, mostrará su contenido por pantalla.
  • void juego(int marcador, int numMONEDAS): conduce el juego de una partida. Tiene como argumentos el valor del marcador (marcador) y el nº de monedas de que dispone cada jugador (numMONEDAS).

Generación de valores aleatorios

robotPara generar números aleatorios debes utilizar las funciones rand() y srand(semilla) de la biblioteca cstdlib. Una secuencia de números aleatorios comienza en un primer número entero que se denomina semilla.

Para establecer la semilla el programa deberá invocar a la función srand con el argumento deseado. Lo que hace que la secuencia se comporte de forma aleatoria es precisamente la semilla. Una semilla habitual es el valor de la hora del sistema que se obtiene con una invocación a time(NULL), de la biblioteca ctime, ya que así es siempre distinta para cada ejecución. Así pues, el programa deberá invocar una vez a srand(time(NULL)). Una vez establecida la semilla, la función rand() genera, de forma pseudoaleatoria, otro entero positivo a partir del anterior. Si quieres que los números aleatorios generados estén en un determinado intervalo, deberás utilizar el operador %. Por ejemplo, para obtener un entero aleatorio en el intervalo [0, limiteSuperior] hay que usar la expresión rand() % (limiteSuperior + 1); para obtener un entero aleatorio en el intervalo [1, limiteSuperior] debe usarse la expresión 1 + rand() % (limiteSuperior); y, en general, para obtener un entero aleatorio en el intervalo [limiteInferior, limiteSuperior] hay que usar la expresión limiteInferior + rand() % (limiteSuperior+1-limiteInferior).

Para que los posibles cambios realizados en el marcador y/o en el número de monedas no se pierdan entre ejecuciones del programa, hay que ampliar la versión anterior de manera que se puedan guardar ambos valores en un archivo (configP1.txt). Al inicio del programa debe realizarse la carga de los datos desde ese archivo y al final del programa guardar, para la próxima ejecución, los datos posiblemente modificados en el archivo. Si se da el caso de que no se encuentra el archivo al inicio del programa, se tomarán los valores por defecto (los de la versión 1) para el marcador y el número de monedas.

Parte opcional

Para finalizar, de manera opcional, se te ofrecía la posibilidad de extender la versión anterior con otra opción más en el menú que permita jugar una partida de forma automática, es decir, donde la máquina juegue contra sí misma.

También podías, de manera opcional, extender el programa de manera que el jugador humano pueda parar una partida no automática que se esté alargando mucho. Así, cuando se lleve un cierto nº de rondas MAXRONDAS, el programa preguntará al humano si quiere continuar con la partida o quiere abortarla. En caso de decidir abortarla, la ejecución del programa continuará con la visualización del menú de opciones. El valor de MAXRONDAS lo decides tú (por ejemplo, el doble del marcador, el marcador más diez, o lo que consideres oportuno). Si el humano permite que la partida se extienda más de MAXRONDAS rondas, el programa volverá a realizar la misma pregunta cuando hayan vuelto a pasar otras MAXRONDAS rondas (si es que antes no ha acabado la partida), y así sucesivamente.

El código de fuente ¡Al lío!

Aquí te dejo el código de fuente de la posible solución a este “ejercicio”. Sin embargo no te puedo prometer que no tenga errores o no sea la mejor posible. Pero ten en cuenta que llevo relativamente poco tiempo con la programación en C++. ¡Espero mejor en el futuro!

Para probar el juego solo te faltaría compilarlo. Yo por ejemplo te recomiendo que utilices MinGW. También te recomiendo que te leas el manual de C++ que tengo publicado en el apartado de apuntes. Son los mismos que utilizamos nosotros para seguir la asignatura y seguro que te vienen muy bien para iniciarte en el mundo de la programación.

Aquí te dejo algunas capturas de como se vería la ejecución del juego:


Dejar un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *