Informática

Juguemos al ahorcado:

//Juego del ahorcado. Este fichero ha de ir acompañado por otro de texto, en el que se escribirán los titulos de las pelis, nombres de personajes famosos o cualquier tema al que se quiera dedicar el juego. El archivo se ha de guardar en el mimo directorio, bajo el nombre "nombres"
//En este archvo se colocaran los nombres o titulos, uno por linea.

//Se incluyen las librerias de entrada y salida estándar de c++ y la que maneja los "strings", cadenas de carácteres

#include <iostream>
#include <string>
#include <fstream>
#include <ctime>
#include <cstdlib>


using namespace std;

#define NUMERO_MAXIMO_LETRAS 50;
#define MAX_INTENTOS 20;
#define MAX_LINEAS 16;
#define MAX_TEMAS 4;


//Función en la que se escribe en pantalla una presentación del juego

int mensaje_bienvenida ()
{
    cout<<"Bienvenido al popular juego del ahorcado"<<endl;
    cout<<"En él se te presentará en pantalla con guiones un titulo de pelicula, nombre de personaje famoso, etc"<<endl;
    cout<<"Tendrás que ir probando con distintas letras, hasta que lo adivines...o pierdas si cometes más de 7 fallos"<<endl;
    cout<<"Podrás salir del juego en cualquier momento tecleando un '0' en lugar de una tecla"<<endl;
    return 0;
}


//Función en la que se abre el fichero con los nombres y se pide un número del 1 al 15 para sortear el titulo. De momento es así porque no me he aclarado con random()

string sorteo_nombre(int n_jugadas, int * listado_numeros)
{
    string nombre_elegido;
    ifstream fichero;
    int n;
    int numero_elegido;
    int numero_azar;
    int elegir_o_no;
    int fichero_elegido;

//inicializamos la semilla para la secuencia d elos nñúmeros aleatirios. La semilla será un número de segundos que da el reloj del ordenador
    srand(time(0));

//Como queremos acotar el intervalo de números que pueden salir al azar, dividimos el valor que da la llamada a rand
//por el número máximo que puede ser elegido, que dará un número entre 0 y 1, y lo multiplicamos por el valor de número que acota el intervalo. Le sumamos 1 para que este valor también pueda salir. Finalemnte nos quedamos con la parte entera de ese numero. En lugar de "20" preferiría utilizar "MAX_LINEAS", pero no se'porque cuando escribo el #define MAX_LINEAS 20 y sustituyo el 20 por MAX_LINEAS, no lo reconoce y le asigna valores arbitrarios o directamente no compila

    numero_azar=rand();

    numero_elegido=(int)(((double)numero_azar/(double)RAND_MAX)* 16)+1;    

    
//Para que el juegos más ameno, se puede elegir la modalida (titulos de pelis, nombres de personajes relacionados con la astronomía, las metámitas,etc) o dejáreselo al azar

    cout<<"¿Quieres elegir el tema sobre el que irá el juego del ahorcado o prefieres que te sorprenda?"<<endl;
    cout<<"Si quieres elegir, teclea 1. Si quieres que elija yo, teclea 0"<<endl;
    cin>>elegir_o_no;

//Comprobamos que se ha introducido un '0' o un '1'

    while (elegir_o_no!= 0 && elegir_o_no!=1)
	{
	    cout<<"Te has equivocado. Solo puedes teclear 0 ó 1, para decidir si elijo yo  o eliges tú"<<endl;
	    cin>>elegir_o_no;
	}

    if(elegir_o_no==1)
    {
	cout<<"Introduce un número del 1 al 3 dependiendo de tu elección:"<<endl;
	cout<<"1.Titulos de películas (teclea '1')"<<endl;
	cout<<"2.Personajes relacionados con la astronomía (teclea 2)"<<endl;
	cout<<"3.Matemáticos y matemáticas(teclea 3)"<<endl;
	cout<<"4.Científicas que consiguieron vencer todo tipo de obstáculos y dedicar su vida a lo que deseaban(teclea 4)"<<endl;

	cin>>fichero_elegido;

	while (fichero_elegido<1 || fichero_elegido>4)
	{
	    cout<<"Te has equivocado. Solo puedes teclear 1, 2, 3 ó 4  para elegir el tema";
	    cin>>fichero_elegido;
	}
    }

    if (elegir_o_no==0)
    {
	  numero_azar=rand();

	  fichero_elegido=(int)(((double)numero_azar/(double)RAND_MAX)*4)+1;

    }

//Comando para abrir el fichero

    switch(fichero_elegido)
    {
    case 1:
	fichero.open("titulos_pelis");
	cout<<"El tema es 'titulos de pelis'"<<endl;
	break;
    case 2:
	fichero.open("nombres_astronomos");
	cout<<"El tema es nombres de personajes relacionados con la astronomía"<<endl;
	break;
    case 3:
	fichero.open("nombres_matematicas");
	cout<<"el tema es nombres de personajes relacionados con las matemáticas"<<endl;
	break;
    case 4:
	fichero.open("nombres_cientificas");
	cout<<"El tema son nombres de científicas"<<endl;
	break;
    }

//Si no se encuentra el fichero, se imprime un mensaje de error y se sale del programa

    if (fichero.fail())
    {
	cerr << "No encuentro el fichero con los nombres.¿Lo has guardado en el mismo directorio que ahorcado.cpp?" << endl;
	exit(1);
  }

//Se lee el fichero hasta llegar a la linea 'n', correspondiente al número que ha salido al azar. Al llegar esta
//linea se guarda el titulo en la variable nombre_elegido y se sale del bucle, para devolver este valor a "main"
    n=0;

    while(n < numero_elegido)
    {
	getline(fichero, nombre_elegido);
	n++;
    }
    
    return nombre_elegido;
}


//Función dibuja_nombre. El titulo se presenta con guiones. Por ejemplo, para la peli
//'Thelma y Louise" se presentará "_ _ _ _ _   _   _ _ _ _ _". Para ello se distingue
//en la cadena entre letras y espacios. Una vez vaya introduciendo las letras
//que cree pueden estar en el titulo, si acierta se incluiran en la cadena
// "secuencia_letras_acertadas" y se imprimirán en lugar del "_"

string dibuja_nombre(string nombre_elegido, string letras_acertadas, int longitud_nombre)
{
    int n;
//se declara la string donde se almacenara la posición en la que acaba cada palabra del titulo, es decir, donde hay caracters vacios

    string posiciones_espacios("000000000000000000000000000000000000000000000000000000000000000");
    

//en este bucle se va escribiendo, carácter por carácter, el titulo. Para ello se han de evaluar los tres casos posibles:

    
//Primer caso: nos encontramos ante un espacio entre palabras. Lo identificamos e imprimimos como tal

    for(n=0;n<longitud_nombre;n++)
    {
	if (nombre_elegido.at(n)=='0') //Trampa, más adelante veremos como lo hacemos funcionar con espacios en lugar de ceros
	{
	    cout<<"  ";
	    posiciones_espacios[n]='1';
	}
	else
	{
//Segundo caso. Se comprueba si en esa posición se encuentra una letra de las que ya se han acertado. Al no ser así, se imprime en su lugar el característico guión "-"

	    if(letras_acertadas.at(n)=='0')
		cout<<"_";
	    else
// Tercer caso: sí que se trata de una letra acertada ya
 
		cout<<letras_acertadas.at(n);
	}

    }

//Se devuelve a "main" la string que contiene el número y posición de los espacios, que es útil a efectos de que se imprima correctamente

    return posiciones_espacios;

}


//Función "pide_letra". ¿Adivinas que hace? :)

char pide_letra(string letras_usadas, int n_intentos)
{
    char letra;
    int n;
    cout<<endl;

//Se pide una letra al jugador

    cout<<"Prueba suerte con una letra. No se admiten mayúsculas"<<endl;
    cin>>letra;

//Habría que comprobar que efectivamente se trata de una letra

//Comprobamos si es un '0', que es el código de salida del programa

    if (letra=='0')
    {
	cout<<"Siento que te hayas aburrido. Para mi ha sido todo un placer jugar contigo"<<endl;
	cout<<"Espero que vuelvas pronto"<<endl;
	exit(0);
    }
//Se comprueba que está letra no ha sido propuesta antes. Sólo se saldrá del bucle cuando se introduzca una letra nueva

    for(n=0;n<n_intentos;n++)
    {
	while (letras_usadas.at(n)==letra)
	{
	    cout<<"Esta letra ya la has tecleado antes. Intentalo con otra"<<endl;
	    //cout<<"Te recuerdo que las letras que ya has tecleado son: "<<letras_usadas<<endl;
	    cin>>letra;
	}
    }
    return letra;
}


//Función comprueba_victoria

int comprueba_victoria(int n_fallos, string letras_acertadas, string nombre_elegido, int longitud_nombre, string posiciones_espacios)
{
    int n;
    int numero_maximo_letras;
    int numero_letras_acertadas;
    string nombre_para_imprimir;
    int final_partida=0;
    int paridad=0;

//Se comprueba si se ha llegado al número máximo de fallos, 7

    if (n_fallos>6)
    {
	 cout<<"Lo siento. Has perdido "<<endl;
	 final_partida= 1;
    }

//Se comprueba si se ha ganado ya, para lo que se compara la cadena del "nombnre_elegido" con la de "letras_acertadas"
//Algo un poco chapucero, pero...para al comparar las dos cadenas tal como sé (no han funcionado experimentos del tipo compare(0,longitud_nombre,letras_acertadas), el valor que devuelve compare es la cantidad de carácteres que difieren entre las dos cadenas, con un número negativo. Por ello defino la variable numero_letras_acertadas, que ha de coincidir con esta diferencia (son todos los ceros sobrantes de la cadena, de 50 carácteres de longitud).

    numero_letras_acertadas=longitud_nombre-NUMERO_MAXIMO_LETRAS;
    
    if (nombre_elegido.compare(letras_acertadas)==numero_letras_acertadas)
    {
	cout<<"¡Enhorabuena.Lo has conseguido"<<endl;
	final_partida=1;
	cout<<"En efecto,";
    }

// Escribimos el nombre, para que los que han perdido no se queden con las ganas y los que han ganado se recreen.Antes  reemplazamos los '0' por espacios, por ejemplo "la0guerra0de0" con "la  guerra" con " mediante string.replace(2,1,"  ",2) para que al imprimrlo quede más bonito
    //Para ello hemos de distinguir dos casos, si se trata de un espacio "par o impar". Por ejemplo, en "la guerra de " el primero es par y el segundo impar.

    if (final_partida==1)
    {
	for (n=0;n<longitud_nombre;n++)
	{
	    if(posiciones_espacios[n]!='0')
	    {
		switch(paridad)
		{
		case 1:
		    nombre_elegido.replace(n+1,1,"  ",2);
		    paridad=0;
		    break;

		case 0:
		    nombre_elegido.replace(n,1,"  ",2);
		    paridad=1;
		    break;
		}	    
	    }
	}

	cout<<"el nombre era "<<nombre_elegido;
	cout<<endl;
    }
    return final_partida;
}


//Función seguir jugando. Introduciendo un '1' se sale del juego.

int seguir_jugando()
{
    int seguir_o_no;
    cout<<"Si quieres seguir jugando, teclea 1. Si no, 0"<<endl;
    cin>>seguir_o_no;

//Comprobamos que se ha introducido un '0' o un '1'

    while (seguir_o_no!= 0 && seguir_o_no!=1)
	{
	    cout<<"Te has equivocado. Solo puedes teclear 0 ó 1, para seguir o salir";
	    cin>>seguir_o_no;
	}

    return seguir_o_no;

	   }


//Función principal

int main(void)
{
    string nombre_elegido;
    int n_intentos;
    int n_fallos;
    int longitud_nombre;
    int n;
    char letra_propuesta;
    int numero_espacios;
    string letras_acertadas;
    string letras_usadas;
    string posiciones_espacios;
    int numero_letras;
    int vidas;
    int acierto;
    int n_aciertos;
    int n_jugadas=1;
    int listado_numeros[]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
    int tiempo=0;

//Se llama a la función que imprimirá la introducción al juego
    mensaje_bienvenida();

//Todo el código que queda está englobado dentro de un bucle do---while, del que sólo se sale al perder o ganar, si el jugador así lo desea. Si no sale, podrá jugar todas las veces que quiera, adivinando cada vez un titulo diferente

    do
    {

//Se (re)inicializan a cero todas las variables cuyo valor puede variar cada vez que se intenta adivinar un nuevo titulo

	n_intentos=0;
	n_aciertos=0;
	vidas=0;
	numero_espacios=0;
//Forma chapucera de inicializar estas variables, pero ...

	letras_acertadas="00000000000000000000000000000000000000000000000000";
	letras_usadas="0000000000000000000000000000000000";

//Se llama a la función en la que se eligirá uno entre los distintos titulos que constan en el fivhero "nombres". El nombre elegido al azar será el que el jugador tendrá que adivinar

	    nombre_elegido=sorteo_nombre(n_jugadas,listado_numeros);
	    
//Se llama a la función que dibujará el titulo o nombre con guiones. Esta función además 
//devuelve el número de letras (espacios incluidos) que tiene el nombre, imprescindible para evaluar cuando se ha ganado

	    longitud_nombre=nombre_elegido.length();


//Segundo bucle do...while, que comprende la parte del código correspondiente a jugar un titulo de nuevo. Se sale de él cuando se pierde o se gana, y quedas dentro del primer bucle para elegir si sigues jugando y lo intentas con otro titulo de nuevo. Si es así, entras de nuevo en este bucle, para enfrentarte al segundo titulo.
	do
	{


//Se llama a la función que escribe el titulo en pantalla, con los guiones y letras acertadas correspondientes

	    posiciones_espacios=dibuja_nombre(nombre_elegido, letras_acertadas, longitud_nombre);
	    numero_letras=longitud_nombre-numero_espacios;
	    
//Llamada a la función que pide la letra
	    
	    letra_propuesta=pide_letra(letras_usadas, n_intentos);
	    
//Se pone a cero una variable que indica si se ha acertado o no con la letra, a diferencia de n_aciertos, que lo que almacena es el número de carácteres acertados.

	    acierto=0;
	    
//se guarda en la variable "letras acertadas" la letra que se acaba de proponer, para que se pueda comprobar que no se repite
	    
	    letras_usadas[n_intentos]=letra_propuesta;

//Un bucle donde se compara, carácter por carácter del título, las coincidencias que hay con la letra propuesta

	    for(n=0;n<longitud_nombre;n++)
	    {
		if (nombre_elegido.at(n)==letra_propuesta)
		{

//si hay coincidencia, la letra se almacena en la posición correspondiente de la variable "letras_acertadas" y se iguala la variable acierto a 1

		    letras_acertadas[n]=letra_propuesta;
		    acierto=1;
		}

	    }
//Se suma a n_aciertos el valor de "acierto", que recordemos es 0 si no se ha acertado y 1 si era correcta.

	    n_aciertos+=acierto;
	    n_fallos=n_intentos-n_aciertos;

//número de intentos que quedan para perder

	    vidas=7-n_fallos;

//Si se ha fallado, se advierte del número de intentos que quedan
	    if (vidas!=0)
	    {
		if (acierto==0)
		{
		    cout<<endl;
		    if(vidas>4)
			cout<<"Has fallado, pero tranquilo, aún te quedan "<<vidas<< " intentos"<<endl;
		    else
		    {
			cout<<"No pierdas la calma, pero te aviso de que sólo tienes "<<vidas<<" intentos antes de perder"<<endl;
			if(vidas<3)
			    cout<<"Ten mucho cuidado"<<endl;
		    }
		}
	    }
//La variable n_intentos, que lleva la cuenta de las letras que se prueban, se aumenta en uno

  n_intentos++;

	}
	while (comprueba_victoria(n_fallos,letras_acertadas,nombre_elegido,longitud_nombre,posiciones_espacios)!=1);

	n_jugadas=n_jugadas+1;
	
    }
    
    while(seguir_jugando()==1);
    
    return 0;
}