C++ Hangman Swapping Underscores For Actual Chars - c++

I am developing a Hangman game for an Uni assessment in C++ and I am having trouble displaying my hidden words after the user types a letter. So I have got the word being displayed as '_ _ _ _ _ _ _' but when I type a letter it doesn't swap the underscore for the actual letter.
game::game() {
words[0] = "strongly";
words[1] = "cheese";
words[2] = "computer";
words[3] = "coffee";
words[4] = "potatoes"; //words that can be in the game
words[5] = "zebra";
words[6] = "extinguisher";
words[7] = "solution";
words[8] = "diligent";
words[9] = "flabbergasted";
numGuesses = 0;
hiddenWord = words[rand() % 10]; //pick a random word from array words
completedWord = hiddenWord;
//for loop for changing the word to underscores
for (int i = 0; i < completedWord.length(); i++) {
completedWord[i] = '_';
}
//for loop adding a space after underscore
for (int i = 0; i < completedWord.length(); i++) {
cout << completedWord[i] << " ";
}
cout << endl;
cout << "Please enter a letter: ";
char guessedLetter;
cin >> guessedLetter;
if (guessedLetter = completedWord[0]) {
completedWord = guessedLetter;
//cout << guessedLetter << endl;
cout << completedWord << endl;
}
}
My whole program is separated into different header files and cpp files. So the code above is from my gameguesses.cpp and the header for that is below:
class game {
public:
string words[10];
game();
string hiddenWord;
int numGuesses;
string completedWord;
};
And this is what I actually get:
A help would be appreciated. Thank you!

I see 2 issues:
if (guessedLetter = completedWord[0])
That line needs == not =.
Secondly, you are comparing the guess only to the first letter of the hidden word. You need to write a loop to check each letter and substitute where it matches the guess, not just in element [0].

See if this helps.
#include <iostream>
#include <vector>
#include <string>
#include <stdlib.h>
#include <locale>
using namespace std;
class Game
{
public:
Game()
{
gameDictionary.push_back("strongly");
gameDictionary.push_back("cheese");
gameDictionary.push_back("computer");
gameDictionary.push_back("coffee");
gameDictionary.push_back("potatoes");
gameDictionary.push_back("zebra");
gameDictionary.push_back("extinguisher");
gameDictionary.push_back("solution");
gameDictionary.push_back("diligent");
gameDictionary.push_back("flabbergasted");
}
// Play until winning or losing. Returns true on win, false on loss.
bool playGame()
{
numGoodGuesses = 0;
numBadGuesses = 0;
numWordLettersFound = 0;
hiddenWord = gameDictionary[rand() % gameDictionary.size()]; //pick a random word from array words
guessedWordTracker = hiddenWord;
for (string::size_type i = 0; i < hiddenWord.size(); i++)
{
completedWord += "_ ";
}
for (;;)
{
cout << completedWord << endl;
cout << "Please enter a letter: ";
char guessedLetter;
do
{
cin >> guessedLetter;
guessedLetter = tolower(guessedLetter);
if (!isalpha(guessedLetter))
{
cout << "Invalid letter, try again." << endl;
}
} while (!isalpha(guessedLetter));
string::size_type pos;
int numMatchesFoundThisTime = 0;
while ((pos = guessedWordTracker.find_first_of(guessedLetter)) != string::npos)
{
completedWord[pos * 2] = guessedWordTracker[pos];
guessedWordTracker[pos] = '\x01';
numMatchesFoundThisTime++;
}
numWordLettersFound += numMatchesFoundThisTime;
if (numMatchesFoundThisTime > 0)
{
numGoodGuesses++;
cout << "Wow, you found " << numMatchesFoundThisTime
<< (numMatchesFoundThisTime > 1 ? " letters!" : " letter!")
<< endl;
if (numWordLettersFound == hiddenWord.size())
{
cout << "Congrats... the word is '" << hiddenWord << "' ... great job!" << endl;
return true;
}
}
else
{
numBadGuesses++;
cout << "Sorry, the letter '" << guessedLetter << "' is not in the word." << endl;
}
int totalGuesses = numGoodGuesses + numBadGuesses;
cout << "You've made " << numGoodGuesses << " good guesses, "
<< numBadGuesses << " bad guesses, "
<< totalGuesses << " total guesses." << endl;
// Example failure:
const int BAD_GUESSES_ALLOWED = 30;
if (numBadGuesses > BAD_GUESSES_ALLOWED)
{
cout << "Sorry, you have no more guesses left. You lose." << endl;
return false;
}
}
}
private:
vector<string> gameDictionary;
string hiddenWord;
string guessedWordTracker;
string completedWord;
int numGoodGuesses;
int numBadGuesses;
int numWordLettersFound;
};
int _tmain(int argc, _TCHAR* argv[])
{
Game g;
g.playGame();
return 0;
}

Related

set.erase() is not working for me, am I doing something wrong?

Here's my current code:
#include <iostream>
#include <set>
using namespace std;
int main()
{
string numOne, numTwo, numThree;
int pointOne, pointTwo, pointThree, totalPoint;
set<string> ansOne = { "TOE", "TONGUE", "TOOTH" };
cout << "Give A Body Part That Starts With The Letter T";
cout << "\n1. ";
cin >> numOne;
if (ansOne.find(numOne) == ansOne.end())
{
ansOne.erase(numOne);
cout << "Wrong!";
pointOne = 0 + 0;
}
else
{
cout << "Nice, You got a Point!";
pointOne = 1 + 0;
}
cout << "\n2. ";
cin >> numTwo;
if (ansOne.find(numTwo) == ansOne.end())
{
ansOne.erase(numTwo);
cout << "Wrong!";
pointTwo = 0 + pointOne;
}
else
{
cout << "Nice, You got a Point!";
pointTwo = 1 + pointOne;
}
cout << "\n3. ";
cin >> numThree;
if (ansOne.find(numThree) == ansOne.end())
{
ansOne.erase(numThree);
cout << "Wrong!";
pointThree = 0 + pointTwo;
}
else
{
cout << "Nice, You got a Point!";
pointThree = 1 + pointTwo;
}
totalPoint = pointOne + pointTwo + pointThree;
cout << "\n" << totalPoint;
}
What I want to do is, if the answer is after they put the answers, and if the word is in there, I want to erase that word from the set so they can't duplicate the answer. But it's not getting erased from the set.
Per your declared logic, you put the erase in the wrong branch of the if, only erasing a word when the word wasn't in the set already, and not erasing it when it was. The first if/else block would be fixed with:
if (ansOne.find(numOne) == ansOne.end())
{
// Removed ansOne.erase(numOne); here, because you just confirmed it's not in ansOne
cout << "Wrong!";
pointOne = 0;
}
else
{
ansOne.erase(numOne); // It's in ansOne, remove it so it can't be guessed again
cout << "Nice, You got a Point!";
pointOne = 1;
}
Similar changes would be made to the other two if/else blocks.
Note that this code would be much simpler with a for loop that runs three times and maintains the running total, rather than individual variables for each of three nearly identical tests. For example, the fixed version of your code could simplify to:
int main()
{
string userinput; // Just one string for input
int totalPoints = 0; // Just one score counter
set<string> ansOne = { "TOE", "TONGUE", "TOOTH" };
cout << "Give A Body Part That Starts With The Letter T";
for (int i = 1; i <= 3; ++i) {
cout << '\n' << i << ". "; // Number prompts dynamically
cin >> userinput;
const auto inputloc = ansOne.find(userinput); // Storing off iterator speeds erasure later (admittedly not meaningful for three element set
if (inputloc == ansOne.end())
{
cout << "Wrong!";
}
else
{
ansOne.erase(inputloc); // Erase with iterator to element found
cout << "Nice, You got a Point!";
++totalPoints;
}
}
cout << '\n' << totalPoint << '\n';
}

Generate Random Letters Depending on User Input

I have to make a simple letter guessing game. So far I've finished almost everything but I'm not sure about what to do when it comes to one task.
So before the game begins it asks the user to input two things:
Enter the amount of different characters: (if 4 is entered for example, the letters chosen would be from A to the 4th letter, A-D only)
and
Enter the pattern length:
The pattern length input is working fine, but I'm having a tough time figuring out how to modify the generate code function to add the amount of different characters.
Any tips?
#include <iostream>
#include <random>
#include <string>
using namespace std;
size_t len;
string str;
void generate_code()
{
str.string::reserve(len);
random_device rd;
mt19937 gen{rd()};
uniform_int_distribution<char> dis{'A', 'Z'};
for (size_t i = 0; i < len; i++)
{
str += dis(gen);
}
}
void guess_checker()
{
string guess{};
size_t trial_count = 0, match_count = 0;
do
{
cout << "Enter your guess: " << endl;
cin >> guess;
if (guess.size() != len)
{
cout << "error: invalid guess" << endl;
}
else
{
match_count = 0;
for (size_t i = 0; i < len; i++)
{
if (guess[i] == str[i])
++match_count;
}
cout << "You guessed " << match_count << " character"
<< (match_count == 1 ? "" : "s") << " correctly." << endl;
}
++trial_count;
}
while (match_count != len);
cout << "You guessed the pattern in " << trial_count << " guess"
<< (trial_count == 1 ? "" : "es") << "." << endl;
}
int main()
{
int amount;
cout << "Enter the amount of different characters: ";
cin >> amount;
cout << "Enter the pattern length: ";
cin >> len;
generate_code();
guess_checker();
return 0;
}
Simply change your generator line to:
uniform_int_distribution<char> dis{'A', 'A' + amount - 1};
I would also recommend adding some validation beforehand, such as:
if (amount < 1 || amount > 26) {
cout << "Bad amount" << endl;
// exit or something
}

English to Morse code program

#include <iostream>
#include <iomanip>
#include <conio.h>
#include <stdlib.h>
#include <string>
using namespace std;
int main()
{
string text[39] = {"A","B","C","D","E","F","G","H","I","J","K","L","M",
"N","O","P","Q","R","S","T","U","V","W","X","Y","Z",
"1","2","3","4","5","6","7","8","9","0","Stop",",","?"};
string code[39] = {".-","-...","-.-.","-..",".","..-","--.","....","..",".---","-.-",".-..","--",
"-.","---",".--.","--.-",".-.","...","-","..-","...-",".--","-..-","-.--","--..",
".----","..---","...--","....-",".....","-....","--....","---..","----.","-----",".-.-.-","--..--","..--.."};
string English, Morse, output_string;
int option, string_size = 0, location;
char again = 'y', letter;
while(again == 'y')
{
system("cls");
cout << "1 - Encode(Text to Morse)\n";
cout << "2 - Decode(Morse Code to Text)\n";
cout << "3 - Display the Morse Code\n";
cout << "4 - Quit\n";
cout << "Enter 1,2,3 or 4:";
cin >> option;
cin.ignore(256,'\n');
system("cls");
switch(option)
{
case 1:
cout << "\nEnter a string with multiple words to encode:";
getline(cin, English);
system("cls");
cout << "\nThe target string to be translated is:" << "\n";
cout << English << "\n";
string_size = English.length();
for(int n = 0; n <= string_size-1; n++)
{
letter = (char)English.at(n);
if(letter != ' ')
{
for(int t = 0; t <=39; t++)
{
if(letter == text[t])
{
cout << code[t] << " ";
break;
}
}
}
else if(letter == ' ')
{
cout << "\n";
}
}
getch();
break;
}
}
}
I didn't finish it yet, but I don't know why I can't run if(letter == text[t]), it says it's an error. how can I fix it? And I have no idea to write the code that Morse to English. how can I know the position of the array that the user entered?
Error message:
error: no match for 'operator==' (operand types are 'char' and 'std::string {aka std::basic_string}')|
You are trying to compare between strings and char.
You need to write the array like that (if you want to use just characters):
char text[39] = {'A','B','C','D','E','F','G','H','I','J','K','L','M'};
and not:
string text[39] = {"A","B","C","D","E","F","G","H","I","J","K","L","M"};
for (int t = 0; t <= 39; t++)
You have 39 items starting at zero index, therefore your loop should go up to (but not including) 39
for (int t = 0; t < 39; t++)
{
...
}
You can declare a temporary string to copy each letter to string. You would also need to make sure text is upper case:
letter = (char)English.at(n);
if (letter != ' ')
{
for (int t = 0; t < 39; t++)
{
std::string temp;
temp = toupper(letter);
if (temp == text[t])
{
cout << code[t] << " ";
break;
}
}
}
If you want the array to be string - then use strcmp() function.
if(strcmp(text[t],letter)==0)
{
cout << code[t] << " ";
break;
}
Have a good luck!

Why the randomize() function not working?

I and my friend are trying to make a "Hangman" game using C++ for our school project. But on compilation, the messages show that the standard functions randomize() and random were not declared in this scope. What is wrong in the code?
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
using namespace std;
const int MAXLENGTH=80;
const int MAX_TRIES=5;
const int MAXROW=7;
int letterFill (char guess, char secretword[], char guessword[]) {
int matches = 0;
for (int i = 0; secretword[i]!='\0'; i++) {
if (guess == guessword[i])
return 0;
if (guess == secretword[i]) {
guessword[i] = guess;
matches++;
}
}
return matches;
}
void initUnknown (char word[], char unknown[]) {
int i, length = strlen(word);
for (i = 0; i < length; i++)
unknown[i]='*';
unknown[i]='\0';
}
int main () {
char unknown [MAXLENGTH];
char letter;
int wrong_guesses=0;
char word[MAXLENGTH];
char words[][MAXLENGTH] = { "batman begins", "superman returns", "2012",
"tarzan", "goal", "300", "space jam", "transformers", "megamind",
"spiderman" };
randomize();
int n=random(10);
strcpy(word,words[n]);
initUnknown(word, unknown);
cout << "\n\nWelcome to hangman...Guess a Movie Name";
cout << "\n\nEach letter is represented by a star.";
cout << "\n\nYou have to type only one letter in one try";
cout << "\n\nYou have " << MAX_TRIES << " tries to try and guess the word.";
cout << "\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~";
while (wrong_guesses < MAX_TRIES) {
cout << "\n\n" << unknown;
cout << "\n\nGuess a letter: ";
cin >> letter;
if (!letterFill(letter, word, unknown)) {
cout << endl << "Whoops! That letter isn't in there!" << endl;
wrong_guesses++;
} else
cout << endl << "You found a letter! Isn't that exciting!" << endl;
cout << "You have " << MAX_TRIES - wrong_guesses;
cout << " guesses left." << endl;
if (!strcmp(word, unknown)) {
cout << word << endl;
cout << "Yeah! You got it!";
break;
}
}
if(wrong_guesses == MAX_TRIES) {
cout << "\nSorry, you lose...you've been hanged." << endl;
cout << "The word was : " << word << endl;
}
cin.get();
}
In C++ or C, you can use rand to generate random number. you can see more information at http://www.cplusplus.com/reference/cstdlib/rand/
regularly!
Use srand() to seed rand().
#include <cstdlib>
#include <cstddef>
#include <ctime>
...
int main(...){
...
srand(time(NULL));
int randomByte = rand()%256;
...
}

C++ - Replacing "_" with a character

Using C++, I'm trying to make a hangman game to become better at using C++ and programming in general. Anyways, the issue I'm facing is that I'm not sure how to replace the dashes within a string with the letter the user has guessed.
I think my problem is with the fact the word chosen is randomly chosen from an array and I'm not sure how to go about finding the positions within the randomly chosen string which consists of the guessed character.
I have commented out the area that's causing the issue.
#include <iostream>
#include <array>
#include <string>
#include <stdlib.h>
#include <time.h>
#include <cstddef>
#include <algorithm>
using namespace std;
int main()
{
string words[3] = {"stack", "visual", "windows"};
string guess;
cout << "Welcome to hangman.\n";
cout << "\n";
srand(time(NULL));
int RandIndex = rand() % 3;
string selected = words[RandIndex];
for (int i = 1; i <= selected.size(); i++) {
cout << "_ ";
}
cout << "\n";
cout << "\nType in a letter: ";
cin >> guess;
cout << "\n";
if (selected.find(guess) != string::npos) {
/*for (int i = 1; i <= selected.size(); i++) {
if (selected.find(guess) != string::npos) {
cout << "_ ";
} else {
cout << guess << " ";
}
}*/
} else {
cout << "\nNay!\n";
cout << "\n";
}
cout << "\n";
cout << "\n";
system("PAUSE");
return 0;
}
I was thinking about using the replace() function but the problem I face here is that I'm not replacing the string within selected variable but sort of iterating through the word itself, if that made any sense whatsoever?
Use a second string, that is initialized with the underscores. If the find function doesn't return string::npos it returns the position in the string, and this is the same position you should change in the string with the underscores as well.
You actually need to use a second string to store the "guessed" string; this is because you need to keep track of all the guessed letters and display them.
something like :
string s ="test";
string t=""; //empty string
for(int i=0;i<s.size();i++)
t.append("_"); //initialize the guess string
cout<<t<<'\n';
char c;
cin >> c;
int pos = s.find(c); //get the first occurrence of the entered char
while(pos!=-1) //look for all occurrences and replaced them in the guess string
{
t.replace(pos,1,1,c);
pos = s.find(c, pos+1);
}
I think you need to maintain some extra state while looping - to keep track of which letters have / haven't been guessed.
You could add a new string current_state which is initially set to the same length as the word but all underscores. Then, when the player guesses a letter, you find all instances of that letter in the original word, and replace the underscore with the letter guessed, at all the positions found but in current_state.
First i would initialize a new string to show the hidden word:
string stringToDisplay = string( selected.length(), '_');
Then For each letter given by the user i would loop like this:
(assuming guess is letter)
size_t searchInitPos = 0;
size_t found = selected.find(guess, searchInitPos));
if (found == string::npos)
{
cout << "\nNay!\n";
cout << "\n";
}
while( found != string::npos)
{
stringToDisplay[found] = guess;
searchInitPos = found+1;
found = selected.find(guess, searchInitPos));
}
cout << stringToDisplay;
Hope this will help
I think it should be that:
string words[3] = {"stack", "visual", "windows"};
char guess;
string display;
cout << "Welcome to hangman.\n";
cout << "\n";
srand(time(NULL));
int RandIndex = rand() % 3;
string selected = words[RandIndex];
for (int i = 0; i < selected.size(); i++) {
display.insert(0, "_ ");
}
cout << display;
while(display.find("_ ") != string::npos) {
cout << "\n";
cout << "\nType in a letter: ";
cin >> guess;
cout << "\n";
bool flag = false;
for (int i = 0; i < selected.size(); i++) {
if (selected[i] == guess) {
display.replace(i*2, 1, 1, guess);
flag = true;
}
}
if (!flag) {
cout << "\nNay!\n";
cout << "\n";
} else {
cout << display;
}
}