jueves, 26 de junio de 2014

Tres en Raya. Parte IV.





Como añadí en el comentario de la parte III de este juego, he buscado cómo añadir un control para que el usuario no pueda introducir un valor incorrecto al pedir un número. He cogido este código de internet  ( http://www.cristalab.com/tutoriales/validacion-de-tipos-de-datos-en-c--c92149l/ ).

Para utilizarlo se puede utilizar como condición que sea un número correcto y si no es así, que repita un bucle para volver a introducir el valor correcto o salir del programa. Exactamente igual que en el "main" cuando preguntamos al usuario si quiere volver a jugar o no.



viernes, 20 de junio de 2014

Juego del ahorcado. Parte I.

Creo que todos conocemos el juego del ahorcado, en el que hay que adivinar la palabra oculta a través de sus letras (como la ruleta de la fortuna, pero más macabro). Vamos diciendo letras, si la palabra o frase contiene esa letra, se nos indica la posición o posiciones en los que se encuentra, si no contiene esa letra, se pierde una "vida" o lo que es lo mismo, se pinta una de las líneas que forman el muñequito del ahorcado, si el muñequito termina de formarse sin acertar la palabra, has perdido.

Como este será seguramente el último ejemplo práctico como aplicación de consola, me gustaría enfocarlo de una forma diferente, más en el diseño que en mostrar el código ya hecho. Vamos a empezar analizando los requisitos:

Para la primera versión, dispondremos de un fichero de texto en el que estarán las palabras que pueden aparecer en el juego, de ahí se seleccionará una palabra y se mostrará en pantalla el contador de vidas (para la primera versión no vamos a pintar muñequito) y la representación de las diferentes letras de la palabra. Se solicitará al usuario que introduzca una letra y se comprobará si ésta está contenida en la palabra, en caso afirmativo, se pintarán todas las coincidentes y en caso negativo, restaremos una "vida". Si el usuario completa la palabra gana y si se terminan sus vidas, pierde. Debe haber una opción para que el usuario pueda dejar de jugar en cualquier momento.

Tenemos una idea clara y concreta de qué nos están pidiendo, ¿pero cómo lo hacemos? Vamos a dividir el problema en partes más sencillas:
   1. Elegir y coger una palabra del fichero.
   2. Mostrar por pantalla el "tablero" de juego.
   3. Procesar cada palabra que introduzca el usuario.
   4. Ofrecer al usuario una opción de salida y de volver a jugar al terminar.

El primer paso, es aprender a abrir el fichero de texto (esto lo aprenderemos a hacer en el próximo post). Una característica de estos ficheros, es que hay que extraer su información línea a línea (en nuestro caso, como tendremos una sóla palabra por línea, será palabra a palabra), es decir, no podemos elegir a qué linea acceder directamente. Aquí podemos ver un ejemplo de un fichero de palabras:


Para escoger una palabra para el juego, se me han ocurrido dos ideas (todas las sugerencias serán bienvenidas):
 La primera opción es coger directamente la primera palabra (el usuario jamás debe tener acceso a esta lista de palabras, sería trampa) utilizarla para el juego y al terminar, colocarla en el último lugar de la lista. Esta opción es la que menos recursos utiliza y nos va a enseñar mucho sobre cómo manejar ficheros.
La segunda opción es mantener intacto el fichero, copiar todo su contenido y manejarlo de forma interna en el programa. La parte buena es que será mucho más rápido, ya que sólo tendrá que abrir y leer el fichero una vez.

Mañana seguiremos viendo cómo hacer las siguientes partes del programa.

sábado, 14 de junio de 2014

Tres en Raya. Parte III.



Vamos a ver en detalle las diferentes funciones que invoca el 'main'. La primera y más sencilla es 'reiniciarTablero'. Es una función destinada a poner en blanco el tablero de juego (en nuestro caso, en blanco supone el valor '-1'). Para ellos utilizamos dos bucles 'for' anidados (uno dentro de otro) para recorrer todas las posiciones de la matriz de dos dimensiones.



La siguiente función es 'pintarTablero'. Como su nombre indica, pinta el tablero de juego. Primero añade muchas líneas en blanco para que no se vea el tablero anterior y después comienza a pintar el tablero. Para saber qué valor hay que pintar (vacío o el símbolo de uno de los jugadores) utiliza la función 'comprobarValores' que veremos más adelante.


Esta función 'comprobarTablero' repasa las condiciones para que el último jugador que haya jugado (cuyo número se pasa como argumento) gane la partida, es decir, tres símbolos en raya. Si ha ganado la partida devuelve 'true' y si no es una jugada ganadora, devuelve 'false'.


La función 'comprobarValores' es la que es llamada desde 'pintarTablero' y se encarga de decirnos qué valor debemos dibujar en cada casilla. Si el valor es '-1' se dibuja la casilla en blanco, si el valor es 0 se dibuja '()' y si es 1 se dibuja ')('. Esto lo realiza para una línea completa.


La función más interesante es la función 'jugada'. Un jugador introduce las coordenadas de la casilla que quiere ocupar, se comprueba que las coordenadas son correctas, si es así, almacena el valor correspondiente en el tablero y se pinta el tablero actualizado. Después se comprueba si la jugada es ganadora y por último, se comprueba si el tablero está completo (el contador está a cero, es decir, se han terminado las casillas libres).

Y con esto... está listo el programa. ¿Alguna sugerencia para una modificación o mejora?

martes, 10 de junio de 2014

Tres en Raya. Parte II.


Por fin, aquí tenemos el main de nuestro juego. Es más corto que los anteriores, cada vez intentaremos que sea más y más pequeño y que el peso del programa recaiga en las funciones.

Al principio vemos las variables más importantes: una matriz 'valores' que guardará los valores del tablero, un contador que cuenta atrás desde 9 para saber si el tablero está completo, una variable para indicar que salimos del programa y una variable 'char' (un carácter) para almacenar la opción que elegimos cuando nos pregunta si queremos seguir jugando o no.

Después podemos ver las llamadas a nuestras funciones. Vamos a recordar la lista de funciones que ya comentamos en la entrada anterior:

       * 'reiniciarTablero' --> Es una función que reinicia el tablero, es decir, lo vacía de fichas.
       * 'pintarTablero' --> Dibuja en pantalla el tablero incluyendo las fichas introducidas.
       * 'comprobarValores' --> Esta función es llamada desde 'pintarTablero' y es la que se encarga de que cuando una ficha está en una casilla, la función que pinta, coloque el "dibujito" que corresponde con la ficha.
       * 'comprobarTablero' --> Es una función para comprobar si el último jugador que ha colocado una ficha ha realizado una jugada ganadora.
       * 'jugada' --> Es la función que permite a un jugador colocar una ficha en el tablero.


Podemos ver en el main la llamada a reiniciarTablero y pintarTablero nada más empezar, es decir, lo primero es reiniciar todo y mostrar el tablero.

Con el do-while hacemos que todo se repita hasta que los jugadores decidan que ya no quieren jugar más (opción 'N' a la pregunta de si quiere volver a jugar). Lo que caracteriza a todos los juegos es justamente un bucle que se repite mientras el jugador no quiera terminar.

Ahora viene algo nuevo e interesante, hemos metido en un if una función. Esto es totalmente posible siempre que el valor que devuelva la función sea coherente con la condición del if.


En este caso, la función jugada devuelve bool (true o false), es decir 100% compatible con la condición del if. ¿Qué supone esto? Pues en este caso para obtener el valor que devuelve la función, debe ejecutarse y una vez ejecutada, comprobamos si todo ha ido bien y si ha habido algún contratiempo, se ejecuta la salida del bucle.

El símbolo '!' delante de una variable bool o una función que devuelve bool significa 'lo contrario', es decir, el if se ejecutará si hay algún contratiempo. El símbolo '||' significa 'OR' (o en inglés) significa que todo será verdadero si se cumple la parte de la derecha 'o' la parte de la izquierda.

Para la llamada a la función jugada, introducimos el número de jugador (0 para redondos y 1 para Xs), el estado actual del tablero (sus valores) y el contador con las casillas que quedan libres. Lo llamamos dos veces para que juegen los dos jugadores una vez en cada ronda.

Si la partida ha finalizado, entramos al if y preguntamos al jugador si quiere jugar otra partida o prefiere dejarlo. Si prefiere jugar otra partida, reiniciamos el juego (vaciar tablero y colocar el contador con el número de casillas vacías a 9),

En la próxima entrada seguimos con las funciones.

sábado, 7 de junio de 2014

Tres en Raya. Parte I.



¡Empezamos con el Tres en Raya! Antes de entrar a ver código, quiero que visualicéis cómo va a ser el programa y que intentéis ver cómo se podría hacer con todo lo que ya conocemos:
       - Bucles para repeticiones.
       - Condiciones para actuar de diferente manera según los valores que va tomando el programa.
       - Funciones para reciclar el código.
       - Matrices para almacenar datos.



Al no tener ratón, para introducir la casilla en la que queremos colocar la "marca" se introduce la línea y la columna. Si el valor es correcto (entre 1 y 3), se comprueba si es una jugada ganadora y si no es así, se comprueba si el tablero está completo, en ambos casos, termina la jugada.




Nuestros jueguecillos simples empiezan a ser cada vez más complicados y más largos, por eso hay que empezar a estructurarlos mejor. Esto se hace incluyendo cada vez más funciones y dejando un main cada vez más pequeño y más simple que se dedica a ir llamando a las funciones según las necesita.




En un principio tenemos 5 funciones. No todas se llaman desde el main, en muchos casos, una función puede ser llamada por otra función, podemos utilizarlas como queramos.
       * 'reiniciarTablero' --> Es una función que reinicia el tablero, es decir, lo vacía de fichas.
       * 'pintarTablero' --> Dibuja en pantalla el tablero incluyendo las fichas introducidas.
       * 'comprobarValores' --> Esta función es llamada desde 'pintarTablero' y es la que se encarga de que cuando una ficha está en una casilla, la función que pinta, coloque el "dibujito" que corresponde con la ficha.
       * 'comprobarTablero' --> Es una función para comprobar si el último jugador que ha colocado una ficha ha realizado una jugada ganadora.
       * 'jugada' --> Es la función que permite a un jugador colocar una ficha en el tablero.






Mañana empezamos a ver el código y a explicar cómo funciona todo. Pero mientras, aquí os pongo un vídeo algo cutre del funcionamiento:



miércoles, 4 de junio de 2014

El juego de las siete y media. Parte V.

Y por fin, ¡la última modificación para nuestro primer juego! Me hace ilusión que esto avance y vayan saliendo cosillas interesantes. Ahora nuestra baraja es como una de verdad, no puede haber dos cartas iguales y se van gastando. Cuando se termina, se coge una nueva. Algo así:


En esta modificación he decidido incluir algo muy muy importante, el concepto de función. Básicamente una función es un trozo de código, que como se va a repetir más veces, para que quede más claro y más práctico, se saca fuera del main y se le llama cuando sea necesario. Vamos a verlo:



Justo antes del main aparece nuestra función, se llama 'inicializarBaraja' y dentro de ella se han anidado dos bucles 'for' para inicializar toda una matriz de dos dimensiones y también inicializa a 40 un contador. Bien ¿para qué sirve esto? Pues hemos creado una baraja imaginaria (la matriz de dos dimensiones) con 4 palos y 10 cartas cada uno. Le hemos dado un valor bool (verdadero o falso) según se haya utilizado esa carta o no. El contador de baraja es una cuenta atrás desde 40 cada vez que se utiliza una carta, así cuando la baraja se termina, este contador nos avisa.

¿Cómo estamos utilizando la función? Había pensado en poner un post teórico sobre esto, pero sería un rollo y creo que mejor ir viendo casos, así que vamos a ver cómo funciona ésta.

La palabra que hay delante del nombre nos dice el valor que devuelve, en este caso, la palabra 'void' (vacío en inglés) nos dice que no va a devolver nada.

Entre paréntesis detrás del nombre aparecen las variables que se le pasan a la función, en este caso, la baraja y el contador (hay que incluir el tipo de datos y el nombre es independiente). Fíjate que antes del nombre del contador aparece un '&', esto significa (sin entrar en detalles técnicos) que se puede modificar el valor de esa variable, en el caso de la matriz, no es necesario añadirlo.

Poco a poco iremos viendo más funciones y todo irá quedando más claro.

Ya en el 'main' podemos ver que al principio de la ejecución se llama a la función inicializarBaraja para hacer lo que sería "barajar la baraja" (qué mal suena). Después tenemos:



Al hacer una jugada (sacar una carta) comprobamos si la baraja está vacía (contadorBaraja == 0), si es así, avisamos con un mensaje y volvemos a inicializar la baraja, es decir, coger una baraja nueva.

Una vez tenemos los dos números aleatorios (palo y valor), comprobamos en nuestra baraja si esa carta en concreto se ha utilizado ya o no, en caso de que sí se haya utilizado (el valor de su posición sea 'true') utilizamos un 'continue' (continúa en inglés), esto supone avanzar el bucle justo a partir de ese punto, es decir, en nuestro caso, no seguiría mostrando la carta y añadiendo el valor, sino que directamente pasa a sacar una nueva carta y esto se repite hasta que tengamos una carta válida, entonces es cuando ponemos a 'true' su posición en la baraja y restamos uno al contador de la baraja.

Y ale, si no se os ocurre ninguna modificación más, aquí hemos terminado nuestro juego de las siete y media.

domingo, 1 de junio de 2014

El juego de las siete y media. Parte IV.

La modificación para que muestre la carta que sale en concreto puede ser muy sencilla, por ejemplo, además del número aleatorio de 1 a 10 para el valor de la carta, añadir otro aleatorio de 1 a 4 para el palo.


He añadido algo nuevo muy interesante, una alternativa a los if-else largos, es el switch-case. Se le pasa una variable, por ejemplo el número de la carta o el palo, y según el valor que tenga, se ejecutan unas cosas u otras. En el código podemos ver cómo se usa, tanto para el valor de la carta como para el palo.

Vamos a verlo:


El switch no deja utilizar double para la carta, sólo acepta valores enteros, así que hemos cambiado carta a 'int' y hemos creado una nueva variable "valor" como double y así guardar el valor concreto de cada tabla.

En el primer switch podemos ver cómo según el valor de 'carta' se muestra un mensaje según el valor ('case' es caso en inglés, es decir, se ejecuta un código para cada caso). Con el 'break' hacemos que pare la sección de código para cada 'case'. El segundo switch para el palo es exactamente igual.

Podéis ver cómo vamos encadenando los 'cout' para ir generando mensajes por partes con diferente información según nos interese.

La siguiente modificación es lógica después de ésta. Si ahora sabemos qué carta está saliendo, sería raro que apareciese varias veces la misma carta, por eso vamos a controlar que no aparezca dos veces la misma carta, es como tener una baraja que se va utilizando, cuando se termine, empezamos una nueva (o se reutiliza la baraja anterior completa, que para nosotros es lo mismo).

Señoras y señores, ¡a programar!