help with hangman game

Mar 17, 2017 at 11:48am
I have had a go at writing a hangman game. It kind of works at the moment but there are some issues. The game works fine if the word entered to guess only contains unique characters - it fails if there is more than q instance of the same character. Can anyone point me in the right direction on how to overcome this please!!
Also when the initial word is inputted it is world readable - is there a way to mask the input?

Any help is appreciated.
PS I know my program is messy - I'm just begining...!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135

#include <iostream>
#include <vector>
#include <string>



void printHangMan( int *, std::string & );
void revealWord( std::string &, unsigned long int, char );

int main(int argc, const char * argv[]) {
    
    //variables for hangman
    int wrongGuess = 0;// increment up each time guess is wrong
    int rightGuess = 0;
    char charGuess;// input for guess
    std::vector<char> lettersGuessed;// vector to store previous guesses and ask for another if already used
    
    
    std::string wordToGuess;// the actual word to guess
    std::string copyOfWord; //use this to compare strings to se if winner
    std::size_t found = wordToGuess.find(charGuess);// used to find if guess is in the word
    
    
    std::cout << "Input a word to guess: ";
    std::cin >> wordToGuess;
    std::cout << "\nThe word is " << wordToGuess.size() << " letters long" << std::endl;
    
    copyOfWord.append(wordToGuess.size(), 'X');// fill copy with X and reveal letter each time correct guess
    std::cout << copyOfWord << std::endl;// show X
    
    
    std::cout << std::endl;
    
    while( ( wrongGuess < 7 ) && ( rightGuess < wordToGuess.size() ) ){
        
        std::cout << "What is your guess:?";
        std::cin >> charGuess;
        
        found = wordToGuess.find( charGuess );// look for input in wordToGuess and mark pos in found
        
        if ( (found != std::string::npos ) ){
            if( std::find(lettersGuessed.begin(), lettersGuessed.end(), charGuess) != lettersGuessed.end() ) {
                std::cout << "You have used  " << charGuess << " before, try again" << std::endl;
            }
            else{
                std::cout << charGuess << " found at: " << found + 1 << '\n';
                lettersGuessed.push_back( charGuess );
                ++rightGuess;
                if( rightGuess == wordToGuess.size() ){
                    std::cout << "Well done you have guessed the word" << std::endl;
                }
                revealWord( copyOfWord, found , charGuess );
            }
        }
        else if( std::find(lettersGuessed.begin(), lettersGuessed.end(), charGuess) != lettersGuessed.end() ){
            std::cout << "You have used " << charGuess << " before, try again" << std::endl;
        }
        else{
            lettersGuessed.push_back( charGuess );
            wrongGuess++;
        }
        printHangMan( &wrongGuess, wordToGuess );
        
    }
    
    
    return 0;
}

void revealWord( std::string &reveal, unsigned long int position, char letter ){
    
    reveal[position] = letter;
    std::cout << reveal << std::endl;
    std::cout << std::endl;
}


void printHangMan( int *guesses, std::string &word ){
    
    switch( *guesses ){
        case 1:
            std::cout << "\t" << " O " << std::endl;
            break;
        case 2:
            std::cout << "\t" << " O " << std::endl;
            std::cout << "\t" << "/";
            std::cout << std::endl;
            break;
        case 3:
            std::cout << "\t" << " O " << std::endl;
            std::cout << "\t" << "/";
            std::cout <<  "|";
            std::cout << std::endl;
            break;
        case 4:
            std::cout << "\t" << " O " << std::endl;
            std::cout << "\t" << "/";
            std::cout <<  "|";
            std::cout <<  "\\";
            std::cout << std::endl;
            break;
        case 5:
            std::cout << "\t" << " O " << std::endl;
            std::cout << "\t" << "/";
            std::cout <<  "|";
            std::cout <<  "\\";
            std::cout << "\n\t" << " | ";
            std::cout << std::endl;
            break;
        case 6:
            std::cout << "\t" << " O " << std::endl;
            std::cout << "\t" << "/";
            std::cout <<  "|";
            std::cout <<  "\\";
            std::cout << "\n\t" << " | ";
            std::cout << "\n\t/";
            std::cout << std::endl;
            break;
        case 7:
            std::cout << "\t" << " O " << std::endl;
            std::cout << "\t" << "/";
            std::cout <<  "|";
            std::cout <<  "\\";
            std::cout << "\n\t" << " | ";
            std::cout << "\n\t/";
            std::cout << " \\";
            std::cout << "\n\tgame over" << std::endl;
            std::cout << "The word was " << word << std::endl;
        default:
            break;
    }
    
}
Mar 17, 2017 at 6:02pm
I have had a think and changed the code a little bit. It works at the moment, only for lower case input though.
I still can not get the original word to be masked when it is input. Can anyone help please...!

Thanks in advance.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170

#include <iostream>
#include <vector>
#include <string>
#include <cstring>






void printHangMan( int *, std::string & );
void revealWord( std::string & );

int main(int argc, const char * argv[]) {
    
    //variables for hangman
    int wrongGuess = 0;// increment up each time guess is wrong
    int rightGuess = 0;
    char charGuess;// input for guess
    std::vector<char> lettersGuessed;// vector to store previous guesses and ask for another if already used
    
    
    std::string wordToGuess;// the actual word to guess
    std::string copyOfWord;//copy of word to pass to function
    std::size_t found = wordToGuess.find(charGuess);// used to find if guess is in the word
    
    
    std::cout << "Input a word to guess: ";
    std::cin >> wordToGuess;
    copyOfWord = wordToGuess;
    std::cout << "\nThe word is " << wordToGuess.size() << " letters long" << std::endl;

    
    // for loop to replace charcters in copyofword with X - which can be revealed with correct gueses
    for (int i = 0; i < wordToGuess.size(); i++) {
        std::cout << "X";
        copyOfWord[i] = 'X';
    }
    
    std::cout << std::endl;
    
   
    
    
    //loop to play game, game ends with hangman if too many wrong guess
    //or the player guess the word.
    while( ( wrongGuess < 7 ) && ( rightGuess < wordToGuess.size() ) ){
        
        std::cout << "What is your guess:?";
        std::cin >> charGuess;
        
        found = wordToGuess.find( charGuess );// look for input in wordToGuess and mark pos in found
        
        // first if statement checks if guess is in the word
        if ( (found != std::string::npos ) ){
            //2nd if statement check if it has been guessed before
            if( std::find(lettersGuessed.begin(), lettersGuessed.end(), charGuess) != lettersGuessed.end() ) {
                std::cout << "You have used  " << charGuess << " before, try again" << std::endl;
            }
            //shows that the guess is correct and at which positions in the word to guess
            else{
                std::cout << charGuess << " found at: " << found + 1 << '\n';
                copyOfWord[found] = charGuess;// changes th echaracter from X to crrectly guessed letter
                //loop thorugh word to find any other instances of guessed letter
                //and modify appropriate position on word accordingly
                for( unsigned long int i = found + 1; i < wordToGuess.size(); i++ ){
                    if( charGuess == wordToGuess[i] ){
                        std::cout << "also found at " << i + 1 << std::endl;
                        copyOfWord[i] = charGuess;
                        ++rightGuess;// increment each time same letter is found - to keep word tally correct
                    }
                }
                lettersGuessed.push_back( charGuess );//insert correctly guessed letter in vector
                ++rightGuess;
                if( rightGuess == wordToGuess.size() ){
                    std::cout << "Well done you have guessed the word" << std::endl;
                }
                revealWord( copyOfWord );
            }
        }
        // if guess is not in the word and has been used before inform the player
        else if( std::find(lettersGuessed.begin(), lettersGuessed.end(), charGuess) != lettersGuessed.end() ){
            std::cout << "You have used " << charGuess << " before, try again" << std::endl;
        }
        //guess is not in the word or been used before insert into vector
        //for usage checking each time round the loop
        else{
            lettersGuessed.push_back( charGuess );
            wrongGuess++;//increment wrog guess count to stop game if can't guess word
             printHangMan( &wrongGuess, wordToGuess );
        }
       
        
    }
    
    
    return 0;
}


//function to show correct guessed letters in word
void revealWord( std::string &reveal){
    
    std::cout << reveal << std::endl;
    std::cout << std::endl;
    
}

//function to incremently pring hangman until either guessed or not
void printHangMan( int *guesses, std::string &word ){
    
    std::cout << "\nSorry wrong guess" << std::endl;
    
    switch( *guesses ){
        case 1:
            std::cout << "\t" << " O " << std::endl;
            break;
        case 2:
            std::cout << "\t" << " O " << std::endl;
            std::cout << "\t" << "/";
            std::cout << std::endl;
            break;
        case 3:
            std::cout << "\t" << " O " << std::endl;
            std::cout << "\t" << "/";
            std::cout <<  "|";
            std::cout << std::endl;
            break;
        case 4:
            std::cout << "\t" << " O " << std::endl;
            std::cout << "\t" << "/";
            std::cout <<  "|";
            std::cout <<  "\\";
            std::cout << std::endl;
            break;
        case 5:
            std::cout << "\t" << " O " << std::endl;
            std::cout << "\t" << "/";
            std::cout <<  "|";
            std::cout <<  "\\";
            std::cout << "\n\t" << " | ";
            std::cout << std::endl;
            break;
        case 6:
            std::cout << "\t" << " O " << std::endl;
            std::cout << "\t" << "/";
            std::cout <<  "|";
            std::cout <<  "\\";
            std::cout << "\n\t" << " | ";
            std::cout << "\n\t/";
            std::cout << std::endl;
            break;
        case 7:
            std::cout << "\t" << " O " << std::endl;
            std::cout << "\t" << "/";
            std::cout <<  "|";
            std::cout <<  "\\";
            std::cout << "\n\t" << " | ";
            std::cout << "\n\t/";
            std::cout << " \\";
            std::cout << "\n\tgame over" << std::endl;
            std::cout << "The word was " << word << std::endl;
        default:
            break;
    }
    
}

Mar 17, 2017 at 11:00pm
It's hard to look over such many rows of code, so I decided to re-write it starting from another point of view.
I hope you can find some hints in my code; if not, just ignore it.

Before compiling it, if you decide to test it, you'd better follow this link:
http://www.mieliestronk.com/corncob_lowercase.txt
Copying and pasting that list of words into a file named "corncob_lowercase.txt" is necessary to make my code run. That file should stay in the same folder of the executable.

And here you are:
EDIT: code reloaded because of errors - sorry
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
#include <fstream>
#include <iostream>
#include <random>
#include <set>
#include <string>
#include <vector>

void printHangMan(int guesses, std::string& word);
void revealWord(std::string & reveal);

int main()
{
    // 1) Open a text file with an English word per row
    // 2) generate a randon integer
    // 3) read rows from the file until the random generated number
    // 4) store the result in a std::string
    std::ifstream dictfile("corncob_lowercase.txt");
    std::random_device rd;
    std::mt19937 mt(rd()); // initialise engine
    std::uniform_int_distribution<int> dist(1, 58110); // 58110: number of rows 
                                                       // in corncob_lowercase.txt
    std::string wordToGuess;
    int randnum = dist(mt);
    for(int i{0}; i<randnum; i++)
        std::getline(dictfile, wordToGuess);

    std::cout << "\nThe word is " << wordToGuess.size() 
              << " letters long";
    int wrongGuess = 7; // decrases for every wrong guess
    std::cout << " and you have just " << wrongGuess << " chances left!" 
              << std::endl;
    
    //loop to play game, game ends with hangman if too many wrong guess
    //or the player guess the word.
    // copyOfWord will display the guessed characters
    std::string copyOfWord(wordToGuess.size(), '-');
    std::set<char> lettersGuessed; // store previous guesses

    while((wrongGuess > 0) && (copyOfWord != wordToGuess)) { 

        std::cout << "\nChances left: " << wrongGuess << "; " 
                  << "word to guess: " << copyOfWord << std::endl;
        std::cout << "What is your guess (provide a single character)? ";
        char charGuess;// input for guess
        std::cin >> charGuess;

        // Firstly, let's check if charGuess has already being tried
        // std::set::emplace() returns a std::pair<iterator,bool>
        // if 'key' already exists in std::set, the second element of std::pair
        // will be set to false
        if((lettersGuessed.emplace(charGuess)).second == false) {
            std::cout << "You have used  " << charGuess 
                      << " before, try again." << std::endl;
        } else {
            // Secondly, let's upgrade copyOfWord with the guessed character.
            // If we can't change any '-', it means the guess was wrong
            int changes{0};
            for(unsigned int i{0}; i<wordToGuess.length(); i++) {
                if(wordToGuess.at(i) == charGuess) {
                    copyOfWord.at(i) = wordToGuess.at(i);
                    changes++;
                }
            }
            if(!changes) { // if changes still == 0
                wrongGuess--;
            }
        }
    } // end of while

    // Ok, now we need to discover if we exited "while" because the number 
    // of wrong guesses or because copyOfWord == wordToGuess;
    if(copyOfWord == wordToGuess)
        revealWord( copyOfWord ); // victory!
    else
        printHangMan(wrongGuess, wordToGuess);
 
    return 0;
}


//function to show correct guessed letters in word
void revealWord(std::string& reveal)
{
    std::cout << "\nVery good! You guessed the word "
              << reveal << std::endl << std::endl;
}

//function to incremently pring hangman until either guessed or not
void printHangMan(int guesses, std::string& word)
{
    std::cout << "\nSorry wrong guess" << std::endl;
    
    switch(guesses){
        case 6:
            std::cout << "\t" << " O " << std::endl;
            break;
        case 5:
            std::cout << "\t" << " O " << std::endl;
            std::cout << "\t" << "/";
            std::cout << std::endl;
            break;
        case 4:
            std::cout << "\t" << " O " << std::endl;
            std::cout << "\t" << "/";
            std::cout <<  "|";
            std::cout << std::endl;
            break;
        case 3:
            std::cout << "\t" << " O " << std::endl;
            std::cout << "\t" << "/";
            std::cout <<  "|";
            std::cout <<  "\\";
            std::cout << std::endl;
            break;
        case 2:
            std::cout << "\t" << " O " << std::endl;
            std::cout << "\t" << "/";
            std::cout <<  "|";
            std::cout <<  "\\";
            std::cout << "\n\t" << " | ";
            std::cout << std::endl;
            break;
        case 1:
            std::cout << "\t" << " O " << std::endl;
            std::cout << "\t" << "/";
            std::cout <<  "|";
            std::cout <<  "\\";
            std::cout << "\n\t" << " | ";
            std::cout << "\n\t/";
            std::cout << std::endl;
            break;
        case 0:
            std::cout << "\t" << " O " << std::endl;
            std::cout << "\t" << "/";
            std::cout <<  "|";
            std::cout <<  "\\";
            std::cout << "\n\t" << " | ";
            std::cout << "\n\t/";
            std::cout << " \\";
            std::cout << "\n\tgame over" << std::endl;
            break;
        default:
            break;
    }
    std::cout << "\nThe word was " << word << std::endl;
}


Happy coding!
Last edited on Mar 17, 2017 at 11:28pm
Topic archived. No new replies allowed.