-
Hangman game and strcmp
I made a basic hangman game that reads in a text file with words, selects a random word, prints out the letters from the random word represented as underscores, asks the user what letter they guess, etc etc. The game works fine, but at random, it won't realize that the user has uncovered the word. In the main function of the game is a call to a solved function, which calls strcmp on the string for the real word and the one for the word with the letters hidden. It returns 1 if strcmp says they're equal and returns 0 otherwise. Any ideas? I've gone through main and all of the functions of the game a good number of times but can't seem to isolate the problem. Again, the game (and strcmp) usually works fine, but sometimes it just won't recognize that the word has been solved.
-
1) Post the code you are having trouble with.
2) Make sure there are no stray characters in the input buffer (trailing spaces, newlines, etc.). It may be helpful to convert the input to all upper or lower case, as well.
-
Code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#define MAXSIZE 30
#define MAXWORDS 1000
#define MAXINCORRECT 5
char getGuess(int usedletters[26]);
int readWords(char allWords[][MAXSIZE], char word[MAXSIZE], FILE *fin, int n);
int doGuess(char word[MAXSIZE], char blankword[MAXSIZE], char guess[MAXSIZE], int length);
int solved(char word[MAXSIZE], char blankword[MAXSIZE]);
void printblank(int length, char blankword[MAXSIZE]);
int main(void)
{
srand(time(NULL));
char allWords[MAXWORDS][MAXSIZE];
char filename[MAXSIZE];
char word[MAXSIZE];
char blankword[MAXSIZE];
char guessletter[MAXSIZE];
char choice[16];
int usedletters[26];
int numWords = 0;
int wordlength = 0;
int attempts = 0;
int goodmove = 0;
int usedalready = 0;
printf("What file stores the puzzle words?\n"); // Ask the user for the input file
scanf("%s", filename);
printf("\n");
printf("Would you like to play hangman (yes,no)?\n");
scanf("%s", choice);
printf("\n");
while(strcmp(choice, "no") != 0)
{
attempts = 0; // Reset the number of attempts for each new game
int i; // Loop index
FILE* fin;
fin = fopen(filename, "r");
if(fin == (NULL))
{
printf("\nEnter a valid filename.\n\n");
break;
}
fscanf(fin, "%d", &numWords);
wordlength = readWords(allWords, word, fin, numWords); // Read all the words (also select a random word), and set wordlength
// to what is returned by the readWords function
fclose(fin); // Close the file
for(i = 0; i < wordlength; i++)
{
blankword[i] = '_'; // Initialize the "blank" word string
}
for(i = 0; i < 26; i++)
{
usedletters[i] = 0;
}
while(attempts != MAXINCORRECT)
{
printblank(wordlength, blankword); // Print the "blank" word the length of the real word
guessletter[0] = getGuess(usedletters); // Get the user's guess
goodmove = doGuess(word, blankword, guessletter, wordlength); // Find out if the letter was found in the real word
if(solved(word,blankword))
{
printf("\nCongratulations! You got the correct word, %s.\n", word); // Tell the user if they have solved the puzzle
break;
}
if(goodmove != 0 && usedletters[(int)(guessletter[0] - 'A')] >= 2) // If the letter has been guessed already and is in the puzzle, it counts as a miss
{
printf("\nSorry, you have guessed that letter already.\n");
printf("Now it counts as a miss.\n");
attempts++;
usedalready = 1;
}
else
{
usedalready = 0;
}
if(goodmove == 0) // If the letter the user guesses is not in the real word, subtract 1 from the number of attempts left
{
printf("\nSorry, that letter is NOT in the puzzle.\n");
attempts++;
}
else if(usedalready == 0 && goodmove != 0 && !solved(word,blankword))
{
printf("\nCongratulations, you guessed a letter in the puzzle!\n"); // Tell the user they guessed a letter in the puzzle
}
if(attempts != MAXINCORRECT)
{
printf("\nYou currently have %d incorrect guesses.\n", attempts); // Tell the user their number of incorrect guesses
}
}
if(attempts == MAXINCORRECT)
{
printf("\nSorry, you have made %d incorrect guesses, you lose. The word was %s.\n", MAXINCORRECT, word); // If the user has 0 attempts left, they lose and the real word is printed out
}
printf("\nWould you like to play hangman (yes,no)?\n"); // Asks the user to play again
scanf("%s", choice);
printf("\n");
}
printf("Thanks for playing!\n\n");
system("PAUSE");
return 0;
}
int readWords(char allWords[][MAXSIZE], char word[MAXSIZE], FILE *fin, int n)
{
int i; // Loop index
for (i=0; i < n; i++) // Loop through the file
{
fscanf(fin, "%s", allWords[i]); // Scan every word in the file
}
int randomword = 0; // The number for the random word
int length = 0; // The length of the word
randomword = rand() % n; // Makes randomword a random number less than the number of words
strcpy(word, allWords[randomword]); // Copies to random word to the puzzle word
length = strlen(word); // Determines the length of the random word
return length; // Returns the length of the random word
}
// Pre-conditions: needs the length of the "blank" word and the string of the blank word
// Post-conditions: prints out the "blank" word
void printblank(int length, char blankword[MAXSIZE])
{
int i = 0; // Loop index
printf("Here is your puzzle:\n");
for(i = 0; i < length; i++)
{
printf("%c ", blankword[i]); // Print out the "blank" word
}
printf("\n");
}
// Pre-conditions: none
// Post-conditions: returns the letter the used guessed and adds 1 to the number of times this letter has been used
char getGuess(int usedletters[26])
{
char guess[0];
printf("\nPlease enter your guess.\n"); // Ask the user for their guess
scanf(" %c", &guess[0]);
usedletters[(int)(guess[0] - 'A')]++; // Adds one to the number of uses for each letter
return guess[0];
}
int doGuess(char word[MAXSIZE], char blankword[MAXSIZE], char guess[MAXSIZE], int length)
{
int i = 0; // Loop indices
int j = 0;
int good = 0; //
for(i = 0; i < length; i++)
{ // If the letter they guess is in the real word, swap it for any "blank" letters and return a value > 0
if(guess[0] == word[i])
{
blankword[i] = guess[0];
good++;
}
}
return good;
}
int solved(char word[MAXSIZE], char blankword[MAXSIZE])
{
if(strcmp(word,blankword) == 0)
{
return 1;
}
else
{
return 0;
}
}
Good luck lol. A sample .txt file for it looks like this:
4
COMPUTER
PROGRAM
MONITOR
MOUSE
With the first line being the number of words.
-
>> char guess[0];
First of all, this should be a single character. Second, an array of zero length means you are entitled to manipulate exactly that many characters in the array (ie, NONE!). Made some simple changes, and it works fine for me...
Code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#define MAXSIZE 30
#define MAXWORDS 1000
#define MAXINCORRECT 5
char getGuess(int usedletters[26]);
int readWords(char allWords[][MAXSIZE], char word[MAXSIZE], FILE *fin, int n);
int doGuess(char word[MAXSIZE], char blankword[MAXSIZE], char guess, int length);
int solved(char word[MAXSIZE], char blankword[MAXSIZE]);
void printblank(int length, char blankword[MAXSIZE]);
int main(void)
{
srand(time(NULL));
char allWords[MAXWORDS][MAXSIZE];
char filename[MAXSIZE];
char word[MAXSIZE];
char blankword[MAXSIZE];
char guessletter;
char choice[16];
int usedletters[26];
int numWords = 0;
int wordlength = 0;
int attempts = 0;
int goodmove = 0;
int usedalready = 0;
printf("What file stores the puzzle words?\n"); // Ask the user for the input file
scanf("%s", filename);
printf("\n");
printf("Would you like to play hangman (yes,no)?\n");
scanf("%s", choice);
printf("\n");
while(strcmp(choice, "no") != 0)
{
attempts = 0; // Reset the number of attempts for each new game
int i; // Loop index
FILE* fin;
fin = fopen(filename, "r");
if(fin == (NULL))
{
printf("\nEnter a valid filename.\n\n");
break;
}
fscanf(fin, "%d", &numWords);
wordlength = readWords(allWords, word, fin, numWords); // Read all the words (also select a random word), and set wordlength
// to what is returned by the readWords function
fclose(fin); // Close the file
for(i = 0; i < wordlength; i++)
{
blankword[i] = '_'; // Initialize the "blank" word string
}
for(i = 0; i < 26; i++)
{
usedletters[i] = 0;
}
while(attempts != MAXINCORRECT)
{
printblank(wordlength, blankword); // Print the "blank" word the length of the real word
guessletter = getGuess(usedletters); // Get the user's guess
goodmove = doGuess(word, blankword, guessletter, wordlength); // Find out if the letter was found in the real word
if(solved(word,blankword))
{
printf("\nCongratulations! You got the correct word, %s.\n", word); // Tell the user if they have solved the puzzle
break;
}
if(goodmove != 0 && usedletters[(int)(guessletter - 'A')] >= 2) // If the letter has been guessed already and is in the puzzle, it counts as a miss
{
printf("\nSorry, you have guessed that letter already.\n");
printf("Now it counts as a miss.\n");
attempts++;
usedalready = 1;
}
else
{
usedalready = 0;
}
if(goodmove == 0) // If the letter the user guesses is not in the real word, subtract 1 from the number of attempts left
{
printf("\nSorry, that letter is NOT in the puzzle.\n");
attempts++;
}
else if(usedalready == 0 && goodmove != 0 && !solved(word,blankword))
{
printf("\nCongratulations, you guessed a letter in the puzzle!\n"); // Tell the user they guessed a letter in the puzzle
}
if(attempts != MAXINCORRECT)
{
printf("\nYou currently have %d incorrect guesses.\n", attempts); // Tell the user their number of incorrect guesses
}
}
if(attempts == MAXINCORRECT)
{
printf("\nSorry, you have made %d incorrect guesses, you lose. The word was %s.\n", MAXINCORRECT, word); // If the user has 0 attempts left, they lose and the real word is printed out
}
printf("\nWould you like to play hangman (yes,no)?\n"); // Asks the user to play again
scanf("%s", choice);
printf("\n");
}
printf("Thanks for playing!\n\n");
system("PAUSE");
return 0;
}
int readWords(char allWords[][MAXSIZE], char word[MAXSIZE], FILE *fin, int n)
{
int i; // Loop index
for (i=0; i < n; i++) // Loop through the file
{
fscanf(fin, "%s", allWords[i]); // Scan every word in the file
}
int randomword = 0; // The number for the random word
int length = 0; // The length of the word
randomword = rand() % n; // Makes randomword a random number less than the number of words
strcpy(word, allWords[randomword]); // Copies to random word to the puzzle word
length = strlen(word); // Determines the length of the random word
puts(word);
return length; // Returns the length of the random word
}
// Pre-conditions: needs the length of the "blank" word and the string of the blank word
// Post-conditions: prints out the "blank" word
void printblank(int length, char blankword[MAXSIZE])
{
int i = 0; // Loop index
printf("Here is your puzzle:\n");
for(i = 0; i < length; i++)
{
printf("%c ", blankword[i]); // Print out the "blank" word
}
printf("\n");
}
// Pre-conditions: none
// Post-conditions: returns the letter the used guessed and adds 1 to the number of times this letter has been used
char getGuess(int usedletters[26])
{
char guess;
printf("\nPlease enter your guess.\n"); // Ask the user for their guess
scanf(" %c", &guess);
usedletters[(int)(guess - 'A')]++; // Adds one to the number of uses for each letter
return guess;
}
int doGuess(char word[MAXSIZE], char blankword[MAXSIZE], char guess, int length)
{
int i = 0; // Loop indices
int j = 0;
int good = 0; //
for(i = 0; i < length; i++)
{ // If the letter they guess is in the real word, swap it for any "blank" letters and return a value > 0
if(guess == word[i])
{
blankword[i] = guess;
good++;
}
}
return good;
}
int solved(char word[MAXSIZE], char blankword[MAXSIZE])
{
if(strcmp(word,blankword) == 0)
{
return 1;
}
else
{
return 0;
}
}
Also, you should work on checking for errors more robustly...
-
Hmm I should've seen that. The game still acts funny though. I changed the functions around a bit, but to no avail. For some reason the blank word string and the real word string aren't the same sometimes even if you have solved the word. Here's the updated code. All I did was make a function to load a word separate from the function that loads all the words.
Code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#define MAXSIZE 30
#define MAXWORDS 1000
#define MAXINCORRECT 5
char getGuess(int usedletters[26]);
int readWords(char allWords[][MAXSIZE], FILE *fin);
int loadWord(char allWords[][MAXSIZE], char word[MAXSIZE], int numWords);
int doGuess(char word[MAXSIZE], char blankword[MAXSIZE], char guess, int length);
int solved(char word[MAXSIZE], char blankword[MAXSIZE]);
void printblank(int length, char blankword[MAXSIZE]);
int main(void)
{
srand(time(NULL));
char allWords[MAXWORDS][MAXSIZE];
char filename[MAXSIZE];
char word[MAXSIZE];
char blankword[MAXSIZE];
char guessletter;
char choice[16];
int usedletters[26];
int numWords = 0;
int wordlength = 0;
int attempts = 0;
int goodmove = 0;
int usedalready = 0;
int number_words = 0;
printf("What file stores the puzzle words?\n"); // Ask the user for the input file
scanf("%s", filename);
printf("\n");
printf("Would you like to play hangman (yes,no)?\n");
scanf("%s", choice);
printf("\n");
FILE* fin;
fin = fopen(filename, "r");
if(fin == (NULL))
{
printf("\nEnter a valid filename.\n\n");
system("PAUSE");
return 0;
}
numWords = readWords(allWords, fin); // Read all the words and set numWords
// to what is returned by the readWords function
fclose(fin); // Close the file
while(strcmp(choice, "no") != 0)
{
wordlength = loadWord(allWords, word, numWords);
attempts = 0; // Reset the number of attempts for each new game
int i; // Loop index
for(i = 0; i < wordlength; i++)
{
blankword[i] = '_'; // Initialize the "blank" word string
}
for(i = 0; i < 26; i++)
{
usedletters[i] = 0;
}
while(attempts != MAXINCORRECT)
{
printblank(wordlength, blankword); // Print the "blank" word the length of the real word
guessletter = getGuess(usedletters); // Get the user's guess
goodmove = doGuess(word, blankword, guessletter, wordlength); // Find out if the letter was found in the real word
if(solved(word,blankword))
{
printf("\nCongratulations! You got the correct word, %s.\n", word); // Tell the user if they have solved the puzzle
break;
}
if(goodmove != 0 && usedletters[(int)(guessletter - 'A')] >= 2) // If the letter has been guessed already and is in the puzzle, it counts as a miss
{
printf("\nSorry, you have guessed that letter already.\n");
printf("Now it counts as a miss.\n");
attempts++;
usedalready = 1;
}
else
{
usedalready = 0;
}
if(goodmove == 0) // If the letter the user guesses is not in the real word, subtract 1 from the number of attempts left
{
printf("\nSorry, that letter is NOT in the puzzle.\n");
attempts++;
}
else if(usedalready == 0 && goodmove != 0 && !solved(word,blankword))
{
printf("\nCongratulations, you guessed a letter in the puzzle!\n"); // Tell the user they guessed a letter in the puzzle
}
if(attempts != MAXINCORRECT)
{
printf("\nYou currently have %d incorrect guesses.\n", attempts); // Tell the user their number of incorrect guesses
}
}
if(attempts == MAXINCORRECT)
{
printf("\nSorry, you have made %d incorrect guesses, you lose. The word was %s.\n", MAXINCORRECT, word); // If the user has 0 attempts left, they lose and the real word is printed out
}
printf("\nWould you like to play hangman (yes,no)?\n"); // Asks the user to play again
scanf("%s", choice);
printf("\n");
}
printf("Thanks for playing!\n\n");
system("PAUSE");
return 0;
}
int readWords(char allWords[][MAXSIZE], FILE *fin)
{
int numWords = 0;
fscanf(fin, "%d", &numWords);
int i; // Loop index
for (i=0; i < numWords; i++) // Loop through the file
{
fscanf(fin, "%s", allWords[i]); // Scan every word in the file
}
return numWords;
}
int loadWord(char allWords[][MAXSIZE], char word[MAXSIZE], int numWords)
{
int load_word = 0; // The number for the random word
int length = 0; // The length of the word
load_word = rand() % numWords; // Makes randomword a random number less than the number of words
strcpy(word, allWords[load_word]); // Copies to random word to the puzzle word
length = strlen(word); // Determines the length of the random word
return length; // Returns the length of the random word
}
// Pre-conditions: needs the length of the "blank" word and the string of the blank word
// Post-conditions: prints out the "blank" word
void printblank(int length, char blankword[MAXSIZE])
{
int i = 0; // Loop index
printf("Here is your puzzle:\n");
for(i = 0; i < length; i++)
{
printf("%c ", blankword[i]); // Print out the "blank" word
}
printf("\n");
}
// Pre-conditions: none
// Post-conditions: returns the letter the used guessed and adds 1 to the number of times this letter has been used
char getGuess(int usedletters[26])
{
char guess;
printf("\nPlease enter your guess.\n"); // Ask the user for their guess
scanf(" %c", &guess);
usedletters[(int)(guess - 'A')]++; // Adds one to the number of uses for each letter
return guess;
}
int doGuess(char word[MAXSIZE], char blankword[MAXSIZE], char guess, int length)
{
int i = 0; // Loop indices
int j = 0;
int good = 0; //
for(i = 0; i < length; i++)
{ // If the letter they guess is in the real word, swap it for any "blank" letters and return a value > 0
if(word[i] == guess)
{
blankword[i] = guess;
good++;
}
}
return good;
}
int solved(char word[MAXSIZE], char blankword[MAXSIZE])
{
if(strcmp(blankword,word) == 0)
{
return 1;
}
else
{
return 0;
}
}
-
Maybe something was funky with the .txt file I was giving it. I made a new .txt file with just two words and now it works perfect.
-
Or maybe not...man I hate bugs like this. I've been through the program line by line, function by function, been through the whole algorithm...still can't figure out what's going wrong.
-
And you set the \0 character in blankword where?
-
WOW thank you so much :) I totally wasn't thinking about that null terminator lol.
-
how do you get it to print out the actualy hangman design? like a little picture?
-
where do you add the null terminator?
-
>> where do you add the null terminator?
At the end, perhaps?
>> WOW thank you so much :) I totally wasn't thinking about that null terminator lol.
Still not either, apparently. ;)
-
at the end of the program or where in blank word?