Erros no jogo da forca [RESOLVIDO]

13. Resolvido!!

Rafael L.
SrKon

(usa Manjaro Linux)

Enviado em 09/03/2021 - 10:10h


paulo1205 escreveu:

SrKon escreveu:


Agora ele executa, mas ao digitar a primeira letra o programa encerra.


Em minha primeira resposta, eu disse o seguinte a respeito da operação de leitura.

Esta operação de leitura possivelmente é uma parte importante do problema que você reportou, porque não basta que você aperte uma letra, mas tem de digitar uma letra seguida da tecla <Enter> (ou <Return>, se você estiver num computador da Apple), que provoca o aparecimento de dois caracteres na entrada: a letra em si, e um caráter de fim-de-linha ('\n') correspondente ao <Enter>. Cada um desses caracteres será consumido numa iteração diferente do laço de repetição, e você não fez nenhuma validação de se o valor lido realmente corresponde a uma letra ou a um caráter válido.

A leitura de dados de entrada a partir do terminal exige certos cuidados, porque ela é normalmente orientada a linha (i.e. o sistema procura ler sempre linhas inteiras; mesmo que você solicite apenas um caráter, o sistema vai verificar se esse caráter já existe num buffer interno e, se existir, ele devolve o tal caráter imediatamente, mas, caso não exista, o sistema vai procurar encher o buffer com tanto caracteres quantos forem possíveis, até encontrar uma marca de fim-de-linha ou até não haver mais espaço no tal buffer interno antes de lhe entregar o único caráter que você pediu). Além disso, a função scanf() é muito complexa (possivelmente a mais complexa de todas as funções da biblioteca padrão do C), e requer uma boa e cautelosa leitura de sua documentação — e possivelmente alguma prática — para ser usada de modo efetivo e competente, com o devido conhecimento de quando acontecem descartes automáticos de caracteres e quando eles não ocorrem, como usar conversões, conversões sem atribuição/alteração de valor ou textos fixos, limitações de largura ou de conjuntos de caracteres, alocação automática de memória, indicadores de quantos caracteres foram consumidos, alteração de ordem de argumentos que podem receber atribuições e sinalização de erros ou grau de sucesso das conversões, entre outros aspectos. E eu não estou exagerando.

No mínimo, eu sugiro a você fazer as seguintes mudanças referentes a este pedaço:

  • teste o valor de retorno de scanf(), para ter certeza de que não ocorreu erro de leitura;

  • dentro da própria string de formatação de scanf(), procure descartar todos os caracteres que não interessarem (especialmente espaços, incluindo quebras de linha, cujo tratamento é muito fácil);

  • após a leitura, verifique que fruto de leitura seja válido, e dê o tratamento adequado caso não seja.

Acima, uma das palavras do dicionário incluía um ç. Lembre-se de que ç e vogais acentuadas são caracteres distintos do c comum e das vogais não-acentuadas. Além disso, dependendo do conjunto de caracteres que esteja em uso tanto no momento da compilação quanto no momento da execução, a representação dos caracteres acentuados ou com cedilha pode ser diferente, inclusive com mais do que um byte (ou caráter, pois em C cada char corresponde exatamente a um byte) por sinal gráfico (por exemplo, com o conjunto de caracteres europeu e codificação ISO-8859-1, o c corresponde ao byte com valor 99 e o c corresponde ao valor 231; já com o Unicode e codificação UTF-8, que é a mais comum no Linux hoje em dia, o c corresponde ao mesmo byte com valor 99, mas o ç corresponde a um par de bytes, sendo o primeiro com valor 195 e o segundo com o valor 167). Se você quiser tratar caracteres com marcas diacríticas, seu programa certamente vai ter de ser mais sofisticado.


Como você não fez as modificações sugeridas, o programa continua com o mesmo comportamento de antes.


... Então Jesus afirmou de novo: “(...) eu vim para que tenham vida, e a tenham plenamente.” (João 10:7-10)


Muito obrigado, meu caro, sua ajuda foi de grande valia.

Segue o código com os erros corrigidos:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#include <ctype.h>
#include <stdbool.h>

char banco[30][30]=
{
"notebook",
"smartphone",
"pendrive",
"computador",
"seguranca"
};

char wordSorteada[30] = {0};
char wordDigitada[30] = {0};

void limpaWord()
{
const size_t tam = strlen(wordSorteada);
for(int r = 0; r < tam; r++)
{
wordDigitada[r] = '_';
}
}

void imprimirForca(int erro)
{
switch(erro)
{
case 0:
printf("\n-------\n");
printf("| \n");
printf("| \n");
printf("| \n");
break;
case 1:
printf("\n-------\n");
printf("| o\n");
printf("| \n");
printf("| \n");
break;
case 2:
printf("\n-------\n");
printf("| o\n");
printf("| / \n");
printf("| \n");
break;
case 3:
printf("\n-------\n");
printf("| o\n");
printf("| /| \n");
printf("| \n");
break;
case 4:
printf("\n-------\n");
printf("| o\n");
printf("| /|\\ \n");
printf("| \n");
break;
case 5:
printf("\n-------\n");
printf("| o\n");
printf("| /|\\ \n");
printf("| / \n");
break;
default:
printf("\n-------\n");
printf("| o\n");
printf("| /|\\ \n");
printf("| / \\ \n");
}
}

bool verifyLetter(char letra, char vetor[26])
{
const size_t tam2 = strlen(vetor);
for(int i = 0; i < tam2; i++)
{
if(letra == vetor[i])
{
return true;
}
}

return false;
}

void alocandoLetra(char letra)
{
const size_t tam = strlen(wordSorteada);
for(int i = 0; i < tam; i++)
{
if(wordSorteada[i] == letra)
{
wordDigitada[i] = letra;
}
}
}

void letrasDigitadas(char let[26], int tam)
{
printf("\nJá fora digitadas: ");
const size_t len = strlen(let);
for(int r = 0; r < len; r++)
{
printf("%c,", let[r]);
}
printf("\n");
}

bool wordCompleta()
{
const size_t tam = strlen(wordSorteada);
for(int r=0;r<tam;r++)
{
if(wordDigitada[r] == '_')
{
return false;
}
}
return true;
}

int main()
{
srand(time(NULL));
int palavra = rand() % 5;
strcpy(wordSorteada, banco[palavra]);
limpaWord();
int contLetras = 0;
int contaErros = 0;
char letraDig[26] = {0};
char letter;

while(contaErros<=6)
{
const size_t tam = strlen(wordSorteada);
imprimirForca(contaErros);
printf("\n%zu letras\n%s", tam, wordDigitada);
letrasDigitadas(letraDig, contLetras);
printf("\n\nTentativas restantes: %d\n", 6-contaErros);
printf("\n\n");
printf("Digite uma letra: \n");
scanf("%c", &letter);
fflush(stdin);
getchar();
if(strchr(letraDig, letter)!=NULL)//verifyLetter(letter, letraDig)
{
printf("\nEssa letra já foi digitada\nTente novament\n");
} else
{
letraDig[contLetras] = letter;
contLetras++;
if(strchr(wordSorteada, letter)!=NULL)//verifyLetter(letter, wordSorteada)
{
alocandoLetra(letter);
} else
{
printf("Letra incorreta\nTente novamente\n\n");
contaErros++;
}
}
if(contaErros>5)
{
setenv("PATH", "/bin:/usr/bin", 1);
printf("Game Over for you");
break;
} else if(wordCompleta())
{
printf("YOU WIN");
break;
}

}

return 0;
}





  


14. Curioso!

Rafael L.
SrKon

(usa Manjaro Linux)

Enviado em 09/03/2021 - 10:17h


paulo1205 escreveu:

WalkerPR escreveu:

Achei legal a imagem do seu avatar e resolvi fazer um plágio.
Espero que não se importe . . . . rsrsrsrs!!!


Eu não registrei nenhuma marca, e não creio que eu mesmo tenha sido muito original, então é evidente que você pode usar sua própria imagem à vontade.

Parece-me que nós protestamos contra coisas diferentes. Vergonha, para mim, está num STF que destrói a Constituição da República, legisla sem mandato para tal e interfere descaradamente nos outros Poderes da República, e também num Congresso Nacional que se ajoelha num dia e, dois dias depois, cria uma PEC para blindar quem sobrou, a fim de não acontecer com eles o que eles deixaram acontecer impunemente com um dos seus pares.

Não que eu tenha qualquer simpatia pelo Daniel Silveira, de quem nunca antes tinha ouvido falar. Mas é inegável que esse foi um caso de muitas formas emblemático.

E não vou nem falar sobre o que aconteceu hoje...

Só espero que não venha nenhum STF nos perseguir e nenhuma turba para nos cancelar por conta de nossas mensagens de protesto.


... Então Jesus afirmou de novo: “(...) eu vim para que tenham vida, e a tenham plenamente.” (João 10:7-10)


Taí algo que não esperava encontrar, que coincidência eu pensar de forma tão semelhante com alguém que vem ajudando-me a dias. Foi de fato um prazer saber que tem gente na área que pensa de forma concisa. (Eu pensava que sua foto do perfil fosse meme ou algo de futebol rs).

Eu tbm espero que a PF não venha atrás de nós, mas diante dos acontecimentos recentes...

"A pior ditadura é a ditadura do poder judiciário, pois dela não há a quem recorrer" ~Rui Barbosa (nunca fora tão atual).

Auf Wiedersehen.




15. Re: Erros no jogo da forca [RESOLVIDO]

Walker Luiz de Freitas
WalkerPR

(usa KDE Neon)

Enviado em 09/03/2021 - 15:16h

SrKon escreveu:


paulo1205 escreveu:

WalkerPR escreveu:

Achei legal a imagem do seu avatar e resolvi fazer um plágio.
Espero que não se importe . . . . rsrsrsrs!!!


Eu não registrei nenhuma marca, e não creio que eu mesmo tenha sido muito original, então é evidente que você pode usar sua própria imagem à vontade.

Parece-me que nós protestamos contra coisas diferentes. Vergonha, para mim, está num STF que destrói a Constituição da República, legisla sem mandato para tal e interfere descaradamente nos outros Poderes da República, e também num Congresso Nacional que se ajoelha num dia e, dois dias depois, cria uma PEC para blindar quem sobrou, a fim de não acontecer com eles o que eles deixaram acontecer impunemente com um dos seus pares.

Não que eu tenha qualquer simpatia pelo Daniel Silveira, de quem nunca antes tinha ouvido falar. Mas é inegável que esse foi um caso de muitas formas emblemático.

E não vou nem falar sobre o que aconteceu hoje...

Só espero que não venha nenhum STF nos perseguir e nenhuma turba para nos cancelar por conta de nossas mensagens de protesto.


... Então Jesus afirmou de novo: “(...) eu vim para que tenham vida, e a tenham plenamente.” (João 10:7-10)


Taí algo que não esperava encontrar, que coincidência eu pensar de forma tão semelhante com alguém que vem ajudando-me a dias. Foi de fato um prazer saber que tem gente na área que pensa de forma concisa. (Eu pensava que sua foto do perfil fosse meme ou algo de futebol rs).

Eu tbm espero que a PF não venha atrás de nós, mas diante dos acontecimentos recentes...

"A pior ditadura é a ditadura do poder judiciário, pois dela não há a quem recorrer" ~Rui Barbosa (nunca fora tão atual).

Auf Wiedersehen.



Minha indignação é de modo geral!
Desrespeito entre o Poderes, tratamento dos Governos em relação à COVID (Estados e Federal), aumento do preço do dolar (este é o pior, sobe tudo!).
Saudades do FHC!!!

--------------------------------------------------------------
"Linux: several flavors, one way: - Freedom of choice!"


16. Re: Erros no jogo da forca [RESOLVIDO]

Paulo
paulo1205

(usa Ubuntu)

Enviado em 10/03/2021 - 05:13h

SrKon escreveu:

Muito obrigado, meu caro, sua ajuda foi de grande valia.

Segue o código com os erros corrigidos:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#include <ctype.h>
#include <stdbool.h>

char banco[30][30]=
{
"notebook",
"smartphone",
"pendrive",
"computador",
"seguranca"
};

char wordSorteada[30] = {0};
char wordDigitada[30] = {0};

void limpaWord()
{
const size_t tam = strlen(wordSorteada);
for(int r = 0; r < tam; r++)
{
wordDigitada[r] = '_';
}
}


Essa função pode ser substituída pela função padronizada memset(). Por exemplo:
memset(wordDigitada, '_', strlen(wordSorteada)); 



void imprimirForca(int erro)
{
switch(erro)
{
case 0:
printf("\n-------\n");
printf("| \n");
printf("| \n");
printf("| \n");
break;
case 1:
printf("\n-------\n");
printf("| o\n");
printf("| \n");
printf("| \n");
break;
case 2:
printf("\n-------\n");
printf("| o\n");
printf("| / \n");
printf("| \n");
break;
case 3:
printf("\n-------\n");
printf("| o\n");
printf("| /| \n");
printf("| \n");
break;
case 4:
printf("\n-------\n");
printf("| o\n");
printf("| /|\\ \n");
printf("| \n");
break;
case 5:
printf("\n-------\n");
printf("| o\n");
printf("| /|\\ \n");
printf("| / \n");
break;
default:
printf("\n-------\n");
printf("| o\n");
printf("| /|\\ \n");
printf("| / \\ \n");
}
}

bool verifyLetter(char letra, char vetor[26])
{
const size_t tam2 = strlen(vetor);
for(int i = 0; i < tam2; i++)
{
if(letra == vetor[i])
{
return true;
}
}

return false;
}


Essa função pode ser substituída pela função padronizada strchr(). Por exemplo:
strchr(vetor, letra)!=NULL 



void alocandoLetra(char letra)
{
const size_t tam = strlen(wordSorteada);
for(int i = 0; i < tam; i++)
{
if(wordSorteada[i] == letra)
{
wordDigitada[i] = letra;
}
}
}

void letrasDigitadas(char let[26], int tam)
{
printf("\nJá fora digitadas: ");
const size_t len = strlen(let);
for(int r = 0; r < len; r++)
{
printf("%c,", let[r]);
}
printf("\n");
}


Você não usou o parâmetro tam. Para que declará-lo, então?

Além disso, a função inteira pode ser substituída por um simples
printf("\nJá foram digitadas: %s\n", let); 



bool wordCompleta()
{
const size_t tam = strlen(wordSorteada);
for(int r=0;r<tam;r++)
{
if(wordDigitada[r] == '_')
{
return false;
}
}
return true;
}


Mais uma função desnecessária, pois pode ser substituída pela expressão
strchr(wordDigitada, '_')!=NULL 



int main()


Não deixe a lista de argumentos de main() vazia, pois isso vai contra o que diz o padrão do C (no padrão de 2011, §5.1.2.2.1). Se você não quer receber argumentos do sistema operacional, use
int main(void) 


{
srand(time(NULL));
int palavra = rand() % 5;
strcpy(wordSorteada, banco[palavra]);
limpaWord();
int contLetras = 0;
int contaErros = 0;
char letraDig[26] = {0};
char letter;

while(contaErros<=6)
{
const size_t tam = strlen(wordSorteada);
imprimirForca(contaErros);
printf("\n%zu letras\n%s", tam, wordDigitada);
letrasDigitadas(letraDig, contLetras);
printf("\n\nTentativas restantes: %d\n", 6-contaErros);
printf("\n\n");
printf("Digite uma letra: \n");
scanf("%c", &letter);
fflush(stdin);
getchar();


Evite "fflush(stdin)". O padrão do C só define o comportamento de fflush() para fluxos de saída de dados, não para os de entrada. Muitos sistemas não seguem o comportamento do Windows de usar fflush() com fluxos de entrada para remover caracteres que estejam antes da próxima marca de fim de linha (aliás, isso possivelmente afeta você mesmo, pois se o fflush(stdin) tivesse funcionado, não seria necessário ter também getchar() logo em seguida).

Uma maneira relativamente simples de fazer o que você quer sem fazer nenhum bacalhau é a seguinte (note o tratamento de dados inválidos ou indesejados).
    int c;
while(true){
c=getchar(); /* getchar() é mais econômico do que usar scanf() para ler um mísero caráter. */
if(isalpha(c)){
/* É uma letra. Converte para minúscula e sai do laço de repetição. */
letter=tolower(c);
break;
}
if(c=='\n')
continue; /* Ignora quebra de linha, passando para a próxima iteração do laço. */
if(c!=EOF){
/* Não é letra nem quebra de linha (testados antes) nem erro de leitura (testado agora), logo é um caráter inválido. */
fprintf(stderr, "Caráter '%c' é inválido. Desprezando caracteres até o fim da linha.\n", c);
do c=getchar(); while(c!=EOF && c!='\n');
if(c!=EOF){
/* Imprime novamente a mensagem pedido a próxima letra. */
printf("\n\nDigite uma letra: \n");
continue; /* Vai para a eitura do próximo caráter */
}
}
/* Se chegou neste ponto, houve erro durante a leitura ou durante o descarte após encontrar caráter inválido. */
fprintf(stderr, "Erro de leitura. Abortando o programa.\n");
exit(1);
}


        if(strchr(letraDig, letter)!=NULL)//verifyLetter(letter, letraDig)
{
printf("\nEssa letra já foi digitada\nTente novament\n");
} else
{
letraDig[contLetras] = letter;
contLetras++;
if(strchr(wordSorteada, letter)!=NULL)//verifyLetter(letter, wordSorteada)
{
alocandoLetra(letter);
} else
{
printf("Letra incorreta\nTente novamente\n\n");
contaErros++;
}
}
if(contaErros>5)
{
setenv("PATH", "/bin:/usr/bin", 1);


Para que esse setenv()?

            printf("Game Over for you");
break;
} else if(wordCompleta())
{
printf("YOU WIN");
break;
}

}

return 0;
}



... Então Jesus afirmou de novo: “(...) eu vim para que tenham vida, e a tenham plenamente.” (João 10:7-10)



01 02



Patrocínio

Site hospedado pelo provedor RedeHost.
Linux banner
Linux banner

Destaques

Artigos

Dicas

Tópicos

Top 10 do mês

Scripts