# Juego del Ahorcado en C



## Davok (Oct 5, 2016)

Buenos días, estoy teniendo un problema con este programa y quería ver si me pueden ayudar...

Lo que debería hacer el programa es preguntar la palabra con la que se jugará al ahorcado, luego borra la pantalla. Después pide que ingreses una letra de la palabra, si esta coincide con una letra de la palabra ingresada, dará un mensaje por pantalla diciendo ""Ha acertado una de las letras: " y al lado la letra que acertó, y le sumará 1 al contador del while. Sigue el programa aumentando 1 a contador 2 hasta que este tenga la cantidad de letras de la palabra ingresada (así compobará letra por letra). Se sale del while general cuando la cantidad de letras sea la misma a la palabra que se ingreso (se saldría recién cuando adivinen todas las letras).
Cuando sale de los while (que por ende ya estaría adivinada la palabra) da un mensaje  diciendo "¡Adivino la palabra!: " y al lado "lapalabraqueseingresó".

El código es este, aver si alguien puede ayudarme 


```
#include <stdio.h>
#include <stdlib.h>

int main(){
    int cont,cont2,ing;
    char palabra[10];

    cont=0;
    cont2=0;

    printf("Ingrese la palabra para jugar al ahorcado: ");
    scanf("%s",&palabra);

    while (cont<strlen(palabra)){
        palabra[cont]=toupper(palabra[cont]);
        cont++;}

    cont=0;

    system("cls");

    while (cont<strlen(palabra)){
    printf("Ingrese una letra de la palabra: ");
    scanf("%s",&ing);
    while (cont2<strlen(palabra)){
    if (ing==palabra[cont2]){
        printf("Ha acertado una de las letras: ");
        printf("%s",ing);
        cont++;}
        cont2++;}}

    printf("¡Adivino la palabra!: ");
    printf("%s",palabra);

    return 0;
}
```


----------



## Dr. Zoidberg (Oct 5, 2016)

Davok dijo:


> Buenos días, *estoy teniendo un problema* con este programa y quería ver si me pueden ayudar...


Y cual se supone que es el problema...???   

PD: Bastante ESPANTOSA la forma de poner las llaves de apertura y cierre...


----------



## Davok (Oct 5, 2016)

Dr. Zoidberg dijo:


> Y cual se supone que es el problema...???
> 
> PD: Bastante ESPANTOSA la forma de poner las llaves de apertura y cierre...



El problema es que al ingresar una letra correctamente sigue pidiendo que ingreses y no hace nada, ni da el mensaje de "Ha acertado una letra"!

Lo sé  pero voy a mejorarlo en después


----------



## palurdo (Oct 5, 2016)

Adiós, scanf("%s",&ing);
Hola, ing=getchar();

Adiós, printf("%s",ing);
Hola, putchar(ing);

Adios toupper.


De todas formas tu enfoque no va a funcionar.

Mira: 
	
	



```
Ingrese la palabra para jugar al ahorcado: cielo
Ingrese una letra de la palabra: o
Ha acertado una de las letras: o
Ingrese una letra de la palabra: o
Ha acertado una de las letras: o
Ingrese una letra de la palabra: o
Ha acertado una de las letras: o
Ingrese una letra de la palabra: o
Ha acertado una de las letras: o
Adivinó la palabra cielo.
```


----------



## Dr. Zoidberg (Oct 5, 2016)

Primer error:

```
scanf("%s",[B][COLOR=Red]&[/COLOR][/B]palabra);
```
palabra es un arreglo de char (string, ponele) y el nombre de un arreglo es un puntero al primer elemento (te perdiste esa clase??). Así que como el scanf espera un puntero, lo que tenés que usar es:

```
scanf("%s",palabra);
```
de todas formas leer un string con una scanf es parecido a suicidarse, y lo que hay que usar es la función gets (debería usar la fgets, pero por ahora vamos bien así). Algo como:

```
gets( palabra );
```
Segundo error:

```
if (ing==palabra[cont2]){
```
palabra[cont2] es un char e ing es un int, así que la comparación correcta sería con un cast:

```
if ( [B][COLOR=Red](char)[/COLOR][/B]ing == palabra[cont2] ){
```
Tercer error:
Te dije que ing es un char!!! no un char[], así que está mal esto:

```
printf("%s",ing);
```
y para mostrarlo tenés que hacer:

```
printf("[B][COLOR=Red]%c[/COLOR][/B]", (char)ing );
```
o más fácil:

```
putchar( (char)ing );
```
y sumá lo de *palurdo*...



> Lo sé  pero voy a mejorarlo en después


La típica mentira del informático...


----------



## Nuyel (Oct 5, 2016)

Prueba cambiar "&palabra" a "palabra", el & no se usa cuando es array, &var significa "dirección de var", pero en un array_ el valor "array" ya es en si un puntero y por lo tanto, hacer &array es dirección de array no a donde este apunta._


----------



## palurdo (Oct 5, 2016)

En fin, estudia este código anda...

estúdialo, no lo copies....


```
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

void main(){

	int vidas=7, aciertos=0;
	char palabra[50],adivina[50]="",incognitas[2]="*",tecla;

	printf("\nIntroduce palabra a adivinar: ");
	fgets(palabra,50,stdin);
	for(int i=0;i<strlen(palabra);i++) if(palabra[i]=='\n') palabra[i]=0;
	for(int i=0;i<strlen(palabra);i++) strcat(adivina,incognitas);

	while(vidas&&stricmp(palabra,adivina)){
		printf("\nIntroduce un caracter de la palabra: ");
		while((tecla=getchar())=='\n');
		aciertos=0;
		for(int i=0;i<strlen(palabra);i++)
			if ((tolower(tecla)==tolower(palabra[i]))&&(tolower(tecla)!=tolower(adivina[i]))){
				adivina[i]=palabra[i];
				aciertos++;
			}
			else if (tolower(tecla)==tolower(adivina[i])) aciertos=-1;
		switch(aciertos){
		case -1:
			printf("Has repetido la letra %c en la palabra %s.\nTe penalizo una vida bandido!!\n",tecla,adivina);
			vidas--;
			break;
		case 0:
			vidas--;
			printf("No se encuentra la letra %c en la palabra %s.\nTe quedan %d vidas.\n",tecla,adivina,vidas);
			break;
		case 1:
			printf("La letra %c se encuentra en la palabra %s una vez.\nTe quedan %d vidas.\n",tecla,adivina,vidas);
			break;
		default:
			printf("La letra %c se encuentra en la palabra %s unas %d veces.\nTe quedan %d vidas.\n",tecla,adivina,aciertos,vidas);

		}
	}
	if(vidas) printf("\nHas acertado!! la palabra es %s\n",palabra);
	else printf("Agotaste tus vidas, la palabra era %s, toorpe...",palabra);
}
```


----------



## TRILO-BYTE (Oct 5, 2016)

para ingresar una cadena de caracteres puedes usar *gets();* de c++;

digamos:

char cadena[15];  // mi cadena de carcteres
char caracter;       //mi caracter para comparar caracteres
int i;                   //mi contador


printf("mete una cadena\n");  //mostrara meter cadena.
gets(cadena);                        // espera la cadena hasta que pisas enter.


para comprobar la letra que pises puedes usar scanf;

scanf( "%c", caracter );           //leemos solo 1 caracter

ahora para saber si esta o no en la cadena puedes hacer un barrido facil

digamos que en la palabra *transistor* buscaremos las letras *"s"* que hay 2

es simple con un bucle while buscaremos letra a letra dentro de la cadena si llegamos a caracter *nulo* que se representa asi : '\n' se acaba la busqueda.


i=0;
while(cadena_!='\0')    
{

if(cadena=='s')
{
printf("se encontro la letra: s");
}
i++;
}


bueno pude haber resuelto tu problema pero te di las bases para que hagas bien tu programa_


----------



## palurdo (Oct 5, 2016)

TRILO-BYTE dijo:


> gets(cadena);                        // espera la cadena hasta que pisas enter.



gets deberia estar prohibida. Se debería usar siempre fgets, precisamente para evitar...







...el temido buffer overrun/overflow.


----------



## Dr. Zoidberg (Oct 5, 2016)

palurdo dijo:


> gets deberia estar prohibida. Se debería usar siempre fgets, precisamente para evitar...
> 
> http://es.xkcd.com/site_media/strips/exploits_of_a_mom.png
> 
> ...el temido buffer overrun/overflow.



Si, pero la caricatura no es de ataque de "buffer overflow" sino de un "*sql injection*"


----------



## palurdo (Oct 5, 2016)

Dr. Zoidberg dijo:


> Si, pero la caricatura no es de ataque de "buffer overflow" sino de un "*sql injection*"



Si, eso ya lo se, pero de xkcd no hay ningun chiste que yo sepa sobre el buffer overflow, asi que he puesto esa viñeta porque es un ataque como tantos otros donde interviene una cadena "especial", vamos, que hay que tomar precauciones, ya sea por SQL injection, por Buffer Overflow, XSS Scripting, ARP poisoning, DNS hijacking (esta es la favorita de los malwares) etc...

Edit: Si que hay una caricatura de xkcd sobre el buffer overflow... Pero no es tan graciosa


----------



## TRILO-BYTE (Oct 5, 2016)

estan escribiendo algo que mi no entender y si mi no entender el colega que pregunto por un programa de escuela pues lo estan haciendo bolas.

ahora *fgets* ¿no es para abrir un fichero y obtener una cadena de caracteres?

yo se que es un programa en C pero no se podria usar funciones del C++ y en ese caso usar IOSTREAM para abrir ficheros?


----------



## Dr. Zoidberg (Oct 5, 2016)

fgets te permite operar (no abrir) sobre archivos, pero si usas stdin (que es un archivo --> FILE *) te permite leer del teclado directamente.
El C es muy poderoso, pero hay que saber lo que estas haciendo...
 PD: no podes mezclar la stdio.h con la iostream.h por que se desincronizan los buffers I/O. Sinceramente echaria a los docentes que enseñan esas barbaridades. No tienen NPI de C ni de C++


----------



## TRILO-BYTE (Oct 5, 2016)

jeje por desgracia ami nadie me enseño a programar.
tube que aprender de libros viejos de la biblioteca. 

asi que pues aprendi como dicen en mi pais a la brava, por eso no es de extrañar que diga palurdeces como mezclar C++ con C.


----------



## palurdo (Oct 6, 2016)

TRILO-BYTE dijo:


> asi que pues aprendi como dicen en mi pais a la brava, por eso no es de extrañar que diga palurdeces como mezclar C++ con C.



¿Alguien me ha invocado?

En Spain se usa la variante "a las bravas". De todas formas hay cosas de programación que no se aprenden en la escuela... (Sobre todo la programación "harry el sucio").

Edit: la diferencia entre gets y fgets es que ademas de que fgets acepta como entrada cualquier dispositivo de entrada y no solo stdin como gets, fgets conoce de antemano la cantidad maxima de bytes  que puede volcar desde el buffer de entrada a la variable referenciada, pero gets no. Si por ejemplo tienes memoria reservada para 10bytes y la entrada son 25bytes, gets va a escribir 15 bytes de memoria perteneciente a otra zona reservada, posiblemente una dirección de retorno de una rutina que si esta bien calculada apunta al código sobreescrito que puede tener las instrucciones necesarias para empezar a invadir la máquina.


----------



## TRILO-BYTE (Oct 6, 2016)

fijate eso no tenia idea y si me referia a *yo *como inepto "palurdo" no se si en otro lado palurdo sea sinonimo de inepto pero con ligeros conocimientos en programacion.

por desgracia tube malos maestros en programacion y pues como me daba curiosidad aprendi a la brava. 
desconocia eso del uso del fgets();

esa funcion la usaba unicamente para abrir archivos binarios y trabajar byte a byte hasta EOF();


----------



## Davok (Oct 10, 2016)

¡Gracias a todos! Pude solucionar el problema. 

Le agregué algunas cosas. Para terminarlo solamente me faltaría saber (ya que no he podido resolverlo) es, cómo hacer para que funcione la parte del código que les mostraré a continuación.

Lo que debería hacer, es mostrar guiones con la cantidad de letras de la palabra ingresada, cuando se ingresa una letra correcta, el guión es reemplazado por ésta, si hay varias letras, las reemplazará en el lugar correspondiente.
Es para que el usuario sepa las letras que ingresó y que se oriente algo. (Ustedes entienden.)

Acá el código: 

```
#include <stdio.h>
#include <stdlib.h>

int main(){
    int cont,cont2,cont3,cont4,tope,flag,vidas,dibu,acerto;
    char palabra[50],ingresadas[26],ing,guiones[50];

    cont=0;
    cont2=0;
    cont3=0;
    tope=1;
    vidas=6;
    dibu=0;

    printf("Ingrese la palabra para jugar al ahorcado: ");
    scanf("%s",palabra);

    while (cont<strlen(palabra)){
        palabra[cont]=tolower(palabra[cont]);
        cont++;}

    cont=0;

    while (cont<strlen(palabra)){
        guiones[cont]='_';
        cont++;}

    cont=0;

    system("cls");

    printf("Le quedan %d vidas.\n\n",vidas);


    while ((cont<strlen(palabra)) && (vidas>0)){
    printf("Ingrese una letra de la palabra: ");
    scanf("%s",&ing);
    ing=tolower(ing);
    fflush(stdin);
    flag=0;
    cont2=0;
    while ((flag==0)&&(cont2<tope)){
        if (ing==ingresadas[cont2]){
        flag=1;}
        cont2++;
            }
    if (flag==1){
        printf("La letra ya se ingreso anteriormente.\n\n");}
    else{
        ingresadas[tope]=(char)ing;
        tope++;
    cont2=0;
    acerto=0;
    while(cont2<strlen(palabra)){
    if (ing==palabra[cont2]){
        printf("Ha acertado una de las letras: ");
        printf("%c\n\n",ing);
        acerto=1;
        cont++;}
        cont2++;}
        if (acerto==0){
        vidas--;
        dibu++;
        system("cls");
        printf("Le quedan %d vidas.\n\n",vidas);
        [COLOR=Red]cont4=0;
        while (cont4<strlen(palabra)){
        if (ing==palabra[cont4]){
            guiones[cont4]=ing;}
        else {guiones[cont4]='_';}
        cont4++;}
        cont4=0;
        while (cont4<strlen(palabra)){
        if (guiones[cont4]==palabra[cont4]){
            printf("%s",palabra[cont4]);}
        if (guiones[cont4]!=palabra[cont4]){
            printf("%c",'_');}
        cont4++;}[/COLOR]
        dibujo(dibu);
        printf("\n");
        }}}

    cont=0;

    while (cont<strlen(palabra)){
        palabra[cont]=toupper(palabra[cont]);
        cont++;}

    if (vidas==0){
        printf("\t\t\t¡PERDIO EL JUEGO! LA PALABRA ERA: %s",palabra);}
    else{
    printf("\t\t\t¡ADIVINO LA PALABRA!: ");
    printf("%s",palabra);}



    return 0;
}


int dibujo(int errados){

    if (errados > 0) {
       printf ("  O  \n");}
    if (errados > 1) {
       printf ("  |  \n");}
    if (errados > 2) {
       printf (" / \\ \n");}
    if (errados > 3) {
       printf ("  |  \n");}
    if (errados > 4) {
       printf (" / \\ \n");}
    if (errados > 5) {
       printf ("_   _\n");}
}
```
Lo que remarqué en rojo es la parte que no funciona.


----------



## palurdo (Oct 10, 2016)

Es decir, tu buscas algo similar a esto pero con guiones:



Esto lo hace el código que te programé en unos minutos en unos mensajes atrás. Como ves no utiliza tantos contadores ni tantas comprobaciones. El enfoque del código es realmente sencillo. Simplemente hace lo que haria el maestro del juego. ¿que dispone en cada turno el maestro? El conteo de vidas, la palabra oculta, y las casillas (los guiones o asteriscos o huecos para las letras) que el jugador debe rellenar. Opcionalmente un contador para el numero de aciertos por turno, pero nada mas. El maestro del juego, tras conocer la palabra a adivinar, crea unas casillas con el mismo numero de letras. Tu lo has hecho casi bien, solo te falta, justo después de cerrar el bucle while, la sentencia guiones[cont]=0; ya que necesitas marcar el fin de la palabra generada con casillas.

No necesitas hacer mucho más. Cada turno, cuando cojes una letra, recorres con un índice la palabra secreta. Pueden pasar 3 cosas. Que la letra tecleada no coincida con ninguna de las posiciones de la palabra secreta, por lo tanto la letra es un fallo, que la letra se encuentre una o varias veces en la palabra, y en los lugares donde irian las letras en las casillas haya huecos vacios, por lo que habria uno o mas aciertos e inmediatamente los huecos vacios se reemplacen por la letra acertada, o bien la letra se encuentre una o varias veces en la palabra y en las casillas los huecos de las posiviones coincidentes ya se hayan rellenado, por lo que la letra es repetida. Esta situacion última yo la marco haciendl que el numero de aciertos sea -1 para despues mostrar el mensaje correspondiente y tomar la acción asociada, que es restar una vida. En los mensajes del turno de juego, la pista es precisamente la palabra guiones que poco a pocl se iria rellenando con las letras, como lo harias en el juego de papel. El juego termina cuando las vidas se agotan o cuando las casillas contienen la misma palabra que la palabra secreta (puedes usar la funcion stricmp para averiguarlo).

PD: El programa lo hice a correprisa así que se puede mejorar muchísimo y reducir el codigo a la mitad o menos, añadiendo mas funciones.

PD2: Usa los bucles while, solo los necesarios. Aprovecha la potencia del bucle for, acostumbrate a el y tu programación sera mas sencilla y potente.


----------



## Adriasp (Dic 10, 2019)

Buenas, tengo un trabajo de la universidad en el que tengo que hacer un código en C que consiste en el juego del ahorcado. Como estoy empezando en la universidad me piden que lo haga con herramientas muy sencillas. Lo he empezado pero no he podido terminarlo. Por eso pido ayuda.

En el código se utiliza un fichero donde se encuentran las palabras para adivinar.
Dejo por aquí el código hasta donde he podido llegar:

(Tambien podria utilizar la libreria <stdbool.h> pero no tengo idea de como introducirla).


```
#include <stdio.h>
#include <time.h>
#include <stdlib.h>
int main ()
{
    FILE *fitxer;
    int nContador, num, i, x, intents;
    char paraula[10], lletra[2];
    nContador=0;
    fitxer= fopen ("paraules.txt", "r");
    if (fitxer== NULL)
        printf ("No es pot obrir el fitxer %s \n", "paraules,txt");
    else
    {
        while (fscanf(fitxer,"%s", paraula) != -1)
        {
            nContador++;
        }
    printf ("\nNumero de paraules = %d \n", nContador);
    fclose(fitxer);
    }



    srand (time(NULL));
    num = rand ()% nContador;
    printf ("%d\n", num);
    i=0;
    fitxer= fopen ("paraules.txt", "r");
    while (i<num)
    {
        fscanf(fitxer,"%s", paraula);
        i++;
    }
    printf("%s\n", paraula);


    intents = 10;
    while (intents != 0)
    {
        scanf ("%c", &lletra[1]);
        x = 0;
        while (paraula[x] != '\0')
            {
                if (lletra[1] == paraula[x])
                {
                    printf ("%c", lletra[1]);
                }
                else
                {
                    printf ("_ ");
                }
             x++;
            }
        intents = intents -1;
    }

    fclose (fitxer);
}
```


----------



## Miembro eliminado 356005 (Dic 10, 2019)

¿Y la parte de electrónica está en...?


----------



## Fogonazo (Dic 10, 2019)

Adriasp dijo:


> Buenas, tengo un trabajo de la universidad en el que tengo que hacer un código en C que consiste en el juego del ahorcado. Como estoy empezando en la universidad me piden que lo haga con herramientas muy sencillas. Lo he empezado pero no he podido terminarlo. Por eso pido ayuda.
> 
> En el código se utiliza un fichero donde se encuentran las palabras para adivinar.
> Dejo por aquí el código hasta donde he podido llegar:
> ...


Describe "En detalle" que hace o que se supone debería hacer tu programa, preferentemente línea por línea


----------



## Adriasp (Dic 11, 2019)

El código tiene que coger una palabra aleatoria del fichero que sera la palabra para adivinar. Entonces el jugador tiene que teclear una letra y si esta está contenida en la palabra, mostrar la la letra en la ubicación de la palabra y las letras restantes con guiones. Por ejemplo: patata--->_ _ t _ t _ (si el jugador teclea la letra t). Eso teniendo 10 intentos, si se falla la letra se resta un intento, si se acierta se mantienen los intentos, y así hasta llegar a 0 intentos o hasta que la palabra este completa. También tienen que haber la opción de, tecleando "0", poder introducir la palabra entera. Si se acierta ganas y sino pierdes.

Gracias.


----------



## Fogonazo (Dic 11, 2019)

Adriasp dijo:


> El código tiene que coger una palabra aleatoria del fichero que sera la palabra para adivinar. Entonces el jugador tiene que teclear una letra y si esta está contenida en la palabra, mostrar la la letra en la ubicación de la palabra y las letras restantes con guiones. Por ejemplo: patata--->_ _ t _ t _ (si el jugador teclea la letra t). Eso teniendo 10 intentos, si se falla la letra se resta un intento, si se acierta se mantienen los intentos, y así hasta llegar a 0 intentos o hasta que la palabra este completa. También tienen que haber la opción de, tecleando "0", poder introducir la palabra entera. Si se acierta ganas y sino pierdes.
> 
> Gracias.



Gracias por la descripción del juego, pero pedí la descripción del programa, *NO *del juego.



Fogonazo dijo:


> Describe "En detalle" que hace o que se supone debería hacer tu programa, preferentemente línea por línea



Resumiendo, sabes o no que cosa hace el programa.


----------



## Adriasp (Dic 12, 2019)

Primero lo que hace el programa es abrir el fichero en modo lectura donde se encuentran las palabras. Si este no existe escribe que no se puede abrir el fichero, pero si existe el programa empieza a contar las palabras del fichero. Mas adelante con el numero de palabras el programa elige un numero aleatorio que indicara la palabra para adivinar, que sera aleatoria también. Entonces viene la parte donde se me complica: lo que intento hacer es que, con un bucle, los intentos se reduzcan cuando fallas la letra que debería contener la palabra aleatoria. Dentro de este se lee la letra y con otro bucle iguala todas las letras de la palabra con la letra introducida, si son iguales escribe la letra, en caso contrario escribe un guion. Ademas debería hacer que las letras acertadas se mantuvieran completando la palabra a medida que se aciertan las letras.


----------



## Fogonazo (Dic 12, 2019)

Para eso estableces salidas condicionales del bucle, por ejemplo
Letra repetida decrementa intentos
Letra acertada, NO altera intentos restantes y escape a sub-rutina


----------



## Dr. Zoidberg (Dic 12, 2019)

Fogonazo dijo:


> y escape a sub-rutina


Mepa que esa clase se la perdió....y ni te digo la de análisis y diseño....


----------



## Fogonazo (Dic 12, 2019)

Dr. Zoidberg dijo:


> . . . . y ni te digo la de análisis y diseño....


Esas llegó tarde


----------

