Reputation: 1165
I am trying to make a simple word-guessing game in C++(11) and since it requires a "hidden word"
to be shown to the player I have made two strings; 1st one visible "test"
, and other one just filled with underscores "____"
. I have made a loop with string::iterator
to compare each character in the string with given (char
) input from user.
The problem here, is that it doesn't replace all occurrences in the string the very first time I give an input of 't
' which should result in "t__t
" instead of "t___
"
for the process I am using the replace
function from <algorithm>
header
which looks like this:
replace(str.begin(), str.end(), str.at(char_idx), newLetter);
and this function is inside a for loop which iterates through string; In another function called checkLetter()
void checkLetter(char &newLetter, string &randstr, int &strlen, string &hiddenWord){
string::iterator it;
char char_idx;
for(auto it = randstr.begin(); it != randstr.end();++it){
if(*it == newLetter){
char_idx=randstr.find(*it);
replace(hiddenWord.begin(), hiddenWord.end(), hiddenWord.at(char_idx), newLetter);
}
}
cout << hiddenWord << endl;
}
now this is what the output looks like:
The Word is 4 letters long.
t
t___
e
te__
s
tes_
t
tes_
but when i ran a simpler version of that such as
string RandomWord = "test";
replace(RandomWord.begin(),RandomWord.end(),'t','S');
cout << RandomWord << endl;
which gives 'SesS'
All of the code:
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <algorithm>
using namespace std;
// Function Declaration
string getRandWord();
void checkLetter(char&, string&, int&, string&);
int main() {
// string RandomWord = getRandWord();
string RandomWord = "test";
string hiddenWord = "";
unsigned long int _length_ = RandomWord.length();
int chances = int(_length_)+1;
char newLetter;
hiddenWord.append((_length_),'_');
cout << "The Word is "<< _length_ <<" letters long." << endl;
while(chances > 0){
cin >> newLetter;
checkLetter(newLetter, RandomWord, chances, hiddenWord);
chances--;
}
return 0;
}
// Functions
void checkLetter(char &newLetter, string &randstr, int &strlen, string &hiddenWord){
string::iterator it;
char char_idx;
for(auto it = randstr.begin(); it != randstr.end();++it){
if(*it == newLetter){
char_idx=randstr.find(*it);
replace(hiddenWord.begin(), hiddenWord.end(), hiddenWord.at(char_idx), newLetter);
}
}
cout << hiddenWord << endl;
}
string getRandWord(){
string filePath = "/Users/nedimkanat/XCODE/testcpp/testcpp/";
enum sizes {
ARRAY_SIZE = 5
};
// set seed
srand((unsigned)time(0));
// get random int between 0 and 5
int randint = rand() % ARRAY_SIZE;
// str to store each line from file
string str;
// array to store 5 (random) words
vector<string> arr;
// initialize file object & open file
ifstream file(filePath+"words.txt");
int counter = 0;
// loop trough file
if (file.is_open()){
while (getline(file,str) && counter < ARRAY_SIZE){
arr.push_back(str);
counter++;
}
file.close();
} else {
cout << "File is not open" << endl;
}
// send away random word
if(arr.empty()){
cout << "CANCER" << endl;
}
return arr.at(randint);
}
Upvotes: 0
Views: 342
Reputation: 7723
If based on your code, you shouldn't use std::replace since the third argument (meaning replace-from letter) can be appear twice in the text. So you can just replace the letter like below.
void checkLetter(char &newLetter, string &randstr, int &strlen, string &hiddenWord){
string::iterator it;
for(auto it = randstr.begin(); it != randstr.end();++it){
if(*it == newLetter){
hiddenWord.at(it - randstr.begin()) = newLetter;
}
}
cout << hiddenWord << endl;
}
Upvotes: 1
Reputation: 409364
If I understand you correctly you basically want to transform one string into another?
Using the two-input-iterator overload of std::transform
should be the function you need. The first input container could be the string with underscores that you want to replace, while the second input container is the string containing the actual word. Then you provide a functor or lambda using the input letter as a state or capture, and have the function return the current letter from the first container (the masked word) unless the letter is matching the current letter in the second container (the word to be guessed). The output iterator is the masked word (same as the first input iterator).
Perhaps something like this example program shows:
#include <iostream>
#include <string>
#include <algorithm>
int main()
{
std::string word = "foobar"; // The word to guess
std::string masked = "______"; // The masked word, that will be unmasked letter by letter
// "Guess" some letters...
for (auto const letter : { 'f', 'a', 'x', 'o', 'y', 'r', 'b' })
{
std::cout << "Before '" << letter << "': \"" << masked << "\"\n";
// Convert the masked word into a less masked word
// But only if the letter is found in the word to guess
std::transform(std::begin(masked), std::end(masked), std::begin(word),
std::begin(masked),
[letter](char const& masked_letter, char const& word_letter)
{
if (letter == word_letter)
return word_letter;
else
return masked_letter;
});
std::cout << "After '" << letter << "': \"" << masked << "\"\n";
}
}
Upvotes: 2