comparing each character in a string. c++

Started by
21 comments, last by Zahlman 15 years, 8 months ago
Quote:Original post by Zahlman
Quote:Original post by agm_ultimatex
Quote:Original post by Portmanteau
AFAIK, the STL string class does not have an at method, just an [] operator.


visual studio brings up the at in the list when you type string1. However using [] also gives me the error: Error 2 error C2784: 'bool std::operator ==(const std::vector<_Ty,_Alloc> &,const std::vector<_Ty,_Alloc> &)' : could not deduce template argument for 'const std::vector<_Ty,_Alloc> &' from 'const char'


Show the part of the code where you declare the variables you're using here.


I added [0] to letter in the if comparison, that fixed the error. Never the less, heres my current code and variable declarations.

void Game::Play(){	DrawHangMan(0);	std::string words[10];	words[0] = "mitsubishi";	words[1] = "georgian";	words[2] = "battlecruiser";	words[3] = "ubuntu";	words[4] = "paladin";	words[5] = "ferrari";	words[6] = "macintosh";	words[7] = "canada";	words[8] = "zeitgeist";	words[9] = "windows";		srand(time(0));	int wordNum = (rand() %10);	const std::string theWord = words[wordNum];	int numOfTries = 0;	std::string displayWord(theWord.size(), '-');	std::string lettersUsed = "";	do	{		std::cout << "Word to guess: " << displayWord << "\n";		if(lettersUsed.size() > 0)		{			std::cout << "You have used letters: " << lettersUsed << "\n";		}				std::string letter;		std::getline(std::cin, letter);		//if letter is found		if(theWord.find(letter) != std::string::npos)		{			if(lettersUsed.find(letter) == std::string::npos)			{				std::cout << "You got a letter in the word.\n";				for(unsigned int i = 0; i < theWord.length(); i++)				{					if(theWord == letter[0])					{						displayWord += letter;					}					else if(theWord != "-")					{						displayWord += "-";					}				}			}		}		else		{			std::cout << "That letter is not in the word.\n\n";			numOfTries++;			DrawHangMan(numOfTries);		}		lettersUsed += letter;		std::vector<std::string>::iterator it;	}while(displayWord != theWord && numOfTries < 6);	std::cout << "You got it!\n";}


Advertisement
For your consideration, std::replace. See if you can figure out a good place to use it [smile]
if (answer.find(guess, 0)!= string::npos)
{
//tell the player that it was a good guess.
}


I recently made a hangman game and used the above to check to see if the guess was right. If answer.find(blah) was not equal to string::npos then the guess was found in the answer.

When you finish yours let me know, I'd like to compare mine to yours because I like looking at all the different ways a program can be written and you've done yours differently from what I can see so far.
I wonder why you accept a whole string and not a single character for input. For example why is the user allowed to input "cat", why do you look for "cat" in theWord - and should it by any coincidence be in there - why would you add only the 'c' character to the output?
Quote:Original post by visitor
I wonder why you accept a whole string and not a single character for input.
I'd accept a whole string from the input, much the same way as it's being done now using std::getline but then validate that it has a length of one. That way if the user does enter multiple chars instead of just one then not only will they all get pulled from the stream but the user can be informed of their mistake.
Quote:Original post by dmatter
Quote:Original post by visitor
I wonder why you accept a whole string and not a single character for input.
I'd accept a whole string from the input, much the same way as it's being done now using std::getline but then validate that it has a length of one. That way if the user does enter multiple chars instead of just one then not only will they all get pulled from the stream but the user can be informed of their mistake.


Thats a good idea for an error check thanks. I didnt use a char cause it didnt really fix any problems i had, so i went back to string, as I like them.
Quote:Original post by agm_ultimatex
Quote:Original post by dmatter
I'd accept a whole string from the input, much the same way as it's being done now using std::getline but then validate that it has a length of one. That way if the user does enter multiple chars instead of just one then not only will they all get pulled from the stream but the user can be informed of their mistake.
Thats a good idea for an error check thanks. I didnt use a char cause it didnt really fix any problems i had, so i went back to string, as I like them.
You could probably do better than that really: Let the user type multiple characters if they want to and handle it intuitively by searching for each of the characters one by one. In other words, set aside the fact the player has a limited number of lives, if they were type all the letters from a-z and press enter then it would always solve the word/game. This is most convenient near the end of the game where the user might have guessed the word before having all the letters; they can either type the word, or just the remaining letters, and win more speedily.
Quote:Original post by dmatter
Quote:Original post by agm_ultimatex
Quote:Original post by dmatter
I'd accept a whole string from the input, much the same way as it's being done now using std::getline but then validate that it has a length of one. That way if the user does enter multiple chars instead of just one then not only will they all get pulled from the stream but the user can be informed of their mistake.
Thats a good idea for an error check thanks. I didnt use a char cause it didnt really fix any problems i had, so i went back to string, as I like them.
You could probably do better than that really: Let the user type multiple characters if they want to and handle it intuitively by searching for each of the characters one by one. In other words, set aside the fact the player has a limited number of lives, if they were type all the letters from a-z and press enter then it would always solve the word/game. This is most convenient near the end of the game where the user might have guessed the word before having all the letters; they can either type the word, or just the remaining letters, and win more speedily.


Yeah I know I wanted to implement that so they could take a guess at any time. Im currently trying to implement the replace() into my code, but im having some trouble working the logic out. I know im not calling it correctly, but this is my current version.

if(theWord.find(letter) != std::string::npos){	if(lettersUsed.find(letter) == std::string::npos)	{		std::cout << "You got a letter in the word.\n";				for(unsigned int i = 0; i < theWord.length(); i++)		{			if(theWord == letter[0])			{				std::replace(displayWord, '-', letter[0]);			}			else if(theWord == '-' || theWord != letter[0])			{				displayWord += "-";			}		}	}}
std::replace() is intended to be used with a range. Ranges can be obtained from C++ Standard Library containers (you can think of a string as a container designed with character operations in mind) by calling their begin() and end() member functions.

Lets read the description of std::replace()
Quote:
Replace replaces every element in the range [first, last) equal to old_value with new_value


The notation [first, last) denotes a "half open range". In other words, this means that "first" is included in the range, but "last" is not. The range [a, e) over the alphabet is "a, b, c, d". This may seem at odd way to think at first, but remember that a half open range is the most natural way of writing a for loop in C++:
// i loops over the range [0, 10)for( int i = 0 ; i < 10 ; ++i ){    // do stuff}

In the C++ Standard Library usage of range, we mean a range of elements. In this case, we are talking about the characters in the string. We note that the begin() member function of the std::string class gives us an "iterator" to the start of the range defining the string. The end() member function gives us an iterator that is one past the end of the string.

Graphically, if our string were "Hello, World":
Hello, World^           ^begin       end

As you should be able to see, looping over the half open range [begin, end) will visit each character in the string.

An iterator is a type that allows us to inspect or modify the value of each element as we loop over a range.

For example, consider the following:
int main(){    std::string string = "Hello, World\n";    for(std::string::const_iterator it = string.begin() ; it != string.end() ; ++it)    {         // print the character         std::cout << *it;    }}

We can note that some of the things that the standard string iterator allows us to do is compare them against each other (the it != string.end() part), advance the iterator to the next element (the ++it part) and to inspect the value (the *it part). In this case I have used a "const_iterator" because I am not intending to modify the string.

Let us consider an example that modifies the string:
int main(){    std::string string = "Hello, World\n";    for(std::string::iterator it = string.begin() ; it != string.end() ; ++it)    {         // make the character uppercase         *it = std::toupper(*it);    }    std::cout << string;}

As you can see, we are now allowed to assign to the dereferenced iterator, allowing us to modify the string. If you had made "it" a "const_iterator", this would not have compiled.

Finally, back to std::replace. It goes through the half open range that you pass to it, and replaces any element equal to "old_value" with the element "new_value". That is, it could be written like this:
function replace(begin, end, old_value, new_value)   current = begin   while current != end      if *current == old_value then          *current = new_value      end      ++current   endend

It may seem like overkill, but there is method in the madness [smile]. A great many manually written loops in C++ programs can be eliminated in favour of such algorithms. This can help increase the clarity of the code, as well as reduce the amount of code written.

That said, I may have spoken too soon when I suggested that std::replace could be used for that loop, its actually a more complicated algorithm called replace_copy (as we have two strings, theWord and displayWord). However, even that may not be the algorithm you eventually want (because you only want to conditionally replace the characters). My apologies about leading you astray with that [embarrass].

While the C++ Standard Library does have a nice algorithm to handle that, I won't go into it yet, unless of course you are interested. But I really think you should finish your game first.
Only a topic involving C++ would require so many responses for something so trivial.

This topic is closed to new replies.

Advertisement