Thread: Hangman game and strcmp

  1. #1
    Registered User
    Join Date
    Oct 2008
    Posts
    25

    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.

  2. #2
    Guest Sebastiani's Avatar
    Join Date
    Aug 2001
    Location
    Waterloo, Texas
    Posts
    5,708
    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 <cmath>
    #include <complex>
    bool euler_flip(bool value)
    {
        return std::pow
        (
            std::complex<float>(std::exp(1.0)), 
            std::complex<float>(0, 1) 
            * std::complex<float>(std::atan(1.0)
            *(1 << (value + 2)))
        ).real() < 0;
    }

  3. #3
    Registered User
    Join Date
    Oct 2008
    Posts
    25
    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.

  4. #4
    Guest Sebastiani's Avatar
    Join Date
    Aug 2001
    Location
    Waterloo, Texas
    Posts
    5,708
    >> 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...
    Code:
    #include <cmath>
    #include <complex>
    bool euler_flip(bool value)
    {
        return std::pow
        (
            std::complex<float>(std::exp(1.0)), 
            std::complex<float>(0, 1) 
            * std::complex<float>(std::atan(1.0)
            *(1 << (value + 2)))
        ).real() < 0;
    }

  5. #5
    Registered User
    Join Date
    Oct 2008
    Posts
    25
    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;
        }
    }

  6. #6
    Registered User
    Join Date
    Oct 2008
    Posts
    25
    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.

  7. #7
    Registered User
    Join Date
    Oct 2008
    Posts
    25
    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.

  8. #8
    and the Hat of Guessing tabstop's Avatar
    Join Date
    Nov 2007
    Posts
    14,336
    And you set the \0 character in blankword where?

  9. #9
    Registered User
    Join Date
    Oct 2008
    Posts
    25
    WOW thank you so much I totally wasn't thinking about that null terminator lol.

  10. #10
    Registered User
    Join Date
    Nov 2008
    Posts
    31
    how do you get it to print out the actualy hangman design? like a little picture?

  11. #11
    Registered User
    Join Date
    Nov 2008
    Posts
    31
    where do you add the null terminator?

  12. #12
    Guest Sebastiani's Avatar
    Join Date
    Aug 2001
    Location
    Waterloo, Texas
    Posts
    5,708
    >> 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.
    Last edited by Sebastiani; 11-22-2008 at 01:00 PM. Reason: reworded
    Code:
    #include <cmath>
    #include <complex>
    bool euler_flip(bool value)
    {
        return std::pow
        (
            std::complex<float>(std::exp(1.0)), 
            std::complex<float>(0, 1) 
            * std::complex<float>(std::atan(1.0)
            *(1 << (value + 2)))
        ).real() < 0;
    }

  13. #13
    Registered User
    Join Date
    Nov 2008
    Posts
    31
    at the end of the program or where in blank word?

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. 20q game problems
    By Nexus-ZERO in forum C Programming
    Replies: 24
    Last Post: 12-17-2008, 05:48 PM
  2. game creation questions
    By ajrillik in forum Game Programming
    Replies: 4
    Last Post: 08-10-2005, 06:29 PM
  3. Text-based quiz game
    By MipZhaP in forum Game Programming
    Replies: 7
    Last Post: 09-09-2004, 02:33 PM