Finding words that a player says & block it - c++

I am wondering how to basically make the player's sentence stop after it has a swear word in it. Now, I have it already setup, BUT I need to know how to use the tolower method and how to stop it from saying the same word 3 times in a row while using this for loop:
std::size_t found;
std::string word[3] = { "swear", "swear1", "swear2" };
for(int i = 0; i < 3; i++)
{
found = msg.find(word[i]); // needs to have tolower
if(found != std::string::npos)
{
SendNotification("Message blocked. Does it contain swearing?");
return;
}
else
{
GetPlayer()->Say(msg, lang);
}
}
Help would be grateful!

The reason it is only blocking the first word, is because you are Say()ing the message inside the else block as soon as the first word is not matched. Keep a variable bool badWordFound = false before the start of the loop and set it true inside the if(...){ } block. Then, after checking all the words, if badWordFound == true display your warning, else Say()
set found to false
for each swear word
if found in the sentance
set found to true
if found is false
display sentance
else
display warning
HTH
Edit: Also, the comments about caching the filter list in memory are worth following up on if this is anything more than an exercise.

Related

Check to see if the letters in a word in another array and return true if all match

I am making a hangman game and I have to check to see that all the letters in the word are all in right array and then only return true. I am stuck at this point as I do not know how to return true once all the letters are in
I have tried different false and true scenarios but they don't seem to be working. The for loop below is what I have tried to do.
// This function returns true if the secret word has been guessed correctly.
// Otherwise, it will return false.
bool iswordcomplete(char secretword[], char rights[]) {
// Task 3. Finish this function
//
// Use a for loop to look at each position of the secret word
//
// If all letters in the secret word is in the rights array,
// return true; otherwise, return false.
//
for (i = 0; i < strlen(secretword); i++) {
if secretword[i] != rights
return false;
return false;
}
}
You can use a bool operator :
bool returned = true; //True by default
for (i = 0; i < strlen(secretword); i++)
{
if (secretword[i] != rights) // | If test returns false, returned is set to false
returned &= false; // | If test returns true, returned stays false if previously set to false
}
return returned;
It should put the value at false when the test is false but will not put it back to true
You are comparing the content of the secretword array cells with the rights array pointer: secretword[i] != rights.
This is not what you want.
You want to compare the cells data: secretword[i] != rights[i]
In order to know if a letter of secretword is in rights, you have to loop over rights for all letters of secretword:
bool iswordcomplete(char secretword[], char rights[]) {
for (int i = 0; i < strlen(secretword); i++) {
bool isInRights = false;
// we loop over all characters of rights. We stop at first match
for (int j = 0; j < strlen(rights) && !isInRights; j++)
{
isInRights = (secretword[i] == rights[j]);
}
if (!isInRights)
{
// We haven't found anything in right, let's stop
return false;
}
}
// If we reach this line, all the characters from secretword are in rights
return true;
}
Ok, I've got two bags full of letters, bags A and B. I want to know if bag A contains the same letters as bag B.
The steps you are following are:
Get a letter from bag A named a. If none are left go to step 4
Check if the letter a is equal to bag B.
If it isn't say both bags don't match.
Say both bags don't match.
Do you by chance see the flaws in your logic? Hint: steps 2 and 4 seem a bit off.
A naive way to solve this problem, but that would actually work would be:
Get a letter from bag A named a. If none are left go to step 4.
Go through all letters in bag B trying to find a match with current a.
If a match is found, go to step 1. If not, both bags don't match. Exit.
Bag A and bag B will contain the same letters only and only if the number of letters in A and B are the same.
You could try to use the <algorithm> library with std::all_of and std::find. Possible solution would be:
bool iswordcomplete(char secretword[], char rights[]) {
char* s_end = secretword + std::strlen(secretword);
char* r_end = rights + std::strlen(rights);
return std::all_of(secretword, s_end, [&rights,&r_end](char ch) {
return std::find(rights, r_end, ch) != r_end;
});
}

Vector out of range- C++

I'm working on a project that requires me to make a game of Hangman in c++. I have most of it working, but I'm stuck at printing out the part of the word guessed correctly each time after the user enters a guess. I've created a class to represent a game of hangman, and in this class are the methods that determine what to do for a guess. If a guess is found in any location in the randomly chosen word from a dictionary, I save that char to the same location in a vector called currentWord. currentWord is initialized in the constructor to be contain "_" for the length of the randomly chosen word(that way it is the same size as the word and I can just update it as the user types a guess). For example, if the word is "semicolonialism", and the user's first guess is 'i', I want to replace the '_' in the currentWord vector with the letter 'i'.
string tempWord = word;
for (int i = 0; i < tempWord.size(); i++) {
u_long location = tempWord.find(guess);
currentWord->at(location) = tempWord[location];
tempWord[location] = '_';
}
What I've tried to do is store the member variable "word" in a temporary variable called tempWord. Then I iterate from 0 to the length of tempword. I use tempWord.find(guess) to find the location in tempWord that is a match for the guess, store that into a variable called location, and then update the currentWord vector at that location to equal the tempWord at that location. Since this would only work for the first time the matching char is found, I then change tempWord[location] to '_', that way the next time through, location will be different. But by doing this I some times get the out of range error. If I comment out
tempWord[location] = '_';
then I don't see this error, but only the first occurrence is replaced. Even though I get this out of bounds error, I can see in the debugger that each occurrence is properly replaced in the currentWord vector. This leaves me very confused, so any help would be greatly appreciated! Thanks
EDIT
Thanks to rapptz suggestion to check if location is equal to std::string::npos, I finally have it working. Here's the updated code segment with that check in place:
string tempWord = word;
for (int i = 0; i < tempWord.size(); i++) {
u_long location = tempWord.find(guess);
if (location != std::string::npos) {
currentWord->at(location) = tempWord[location];
tempWord[location] = '_';
}
}
I really liked Tristan's suggestion too, and will do that tomorrow most likely. Once I do, I'll post the updated code as well in case someone else might find it useful. Thanks again!
Was going to post this as a comment but it's easier in a bigger text box! You can avoid both the tempWord copy and the for loop like this:
std::string::size_type location = 0, start_pos = 0; // int would be fine, tbh
while ( (location = word.find(guess, start_pos)) != std::string::npos) {
currentWord.at(location) = word[location];
start_pos = location;
}
My guess is that tempword.find(guess) starts from 1 to the lenght of word, not 0. Please share that function too.

Pointers/C-Strings in C++. How to filter the strings?

I have an array to filter.
Example:
str = "hellothere" and filter = "eo". What to do when i need to filter?
void filter_str(char* str, char* filter, char*result)
{
while(*str)
{
if() //If the current character in str is one to be filter.
{
*str++;
}
else
{
*result++ = *str++;
}
}
*result = '\0';
}
I just can't figure out how to check if the current character is one that needs to be filter. Since the filter can be more than one character, such as "eo". How do I check both "e" and "o" every loop, and then reset filter back to "e" at the start.
I wanted to make a pointer to the start of filter, then use that at the end of the while to go back to the start of filter. But I am not sure how to make it check *str against all the characters to be filtered.
In this case a function has already been written that will do the hard work for you
if (strchr(filter, *str))
In general this is the answer to any question where you have processing that is too complex for you to handle. Write a function to solve the 'inner' problem, and then use that function in the 'outer' problem. In this case the inner problem is finding a character in a string, and the outer problem is the filtering operation you are doing. You are just lucky that the inner problem has already been solved for you.
If you want to know if a letter is in filter, the "easy" way (without using STL functions) would be to loop through the elements of filter and check each one of them to see if you find the character you are looking for.
while(*str)
{
bool found = false;
// For each element in filter {
// If *str == element {
found = true;
break; // This function gets you out of the 'for' loop
}
}
if(found) //If the current character in str is one to be filter.
{
You can fill up the pseudocode in comments

Iterator inside of loop will not increment

I'm attempting to compare two string arrays. Whenever I get to the while loop inside of the if statement, I get stuck in an infinite loop because even though I have an iterator inside of the loop, it doesn't increment. I have the cout<< finder; in the loop just to see what finder is at, and it never increments above zero. If anyone could help I'd really appreciate it.
if (memory[p] == "J")
{
if (is_number(memory[p+1]))
{
worker = atoi(memory[p+1].c_str());
p = worker;
continue;
}
else
{
int finder = 0;
while (memory[p+1] != Symtablelab[finder])
{
cout << finder;
finder = finder + 1;
}
if (memory[p+1] == Symtablelab[finder])
{
int k = Symtablepos[finder];
worker = atoi(memory[k].c_str());
p = worker;
continue;
}
}
}
You said finder never increments above zero. Does it print finder = 0 at all? If it does, it means
memory[p+1] = Symtablelab[1]
just after 1st iteration, so the while loop gets terminated and finder sticks at 1.
EDIT
If you say, it prints finder = 0 continuously inside the while statement, then probably you have if (memory[p] == "J") inside an outer for or while (looping) statement.
If it is continuously printing finder and it is 0, then I must ask if this whole code snippet you posted is enclosed in a while statement that you did not post. It makes absolutely no sense that the while loop included in the statement you posted would not be incrementing finder if it is the loop that gets stuck in an infinite loop.
Or the other possibility is that Symtablelab has overriden the '[' ']' operators. If neither of these things are true, that something incredibly wonky is going on.

logic issue or something more?

My program simulates a video store. In my list there are multiple copies of some videos. If I try to rent a video and the first copy of that video in the list is already rented, my program fails to continue checking to see if the other copies are available (a film is available if custId is '0000'). Take a look at the text file from where the list gets its members for a better understanding of what i'm describing:
Could anyone take a look and let me know if they spot an issue? Any help is appreciated, thanks.
Code from main
try
{
int index = 0;
bool found = false;
while (!found)
{
if (strncmp(filmId,filmList.getAt(index).number,6) == 0 && strncmp("0000",filmList.getAt(index).rent_id,5) == 0)//If that film is rented by NO customer
{
found = true;//customer can rent it
strcpy(newItem.number,filmId);//copy filmId into newItem
filmList.retrieve(newItem);//copy the struct in our orderedList with the same filmId/copy into newItem
filmList.remove(newItem);//delete the struct with same filmId/copy as newItem from the orderedList
strcpy(newItem.rent_id,custId);//update info in
strcpy(newItem.rent_date,rentDate);// newItem to show
strcpy(newItem.return_date,dueDate);// that it has been rented
filmList.insert(newItem);//put NewItem into list, effectivily replacing the removed item.
cout << "Rent confirmed!" << endl;
}
else
{
if (strncmp(filmId,filmList.getAt(index).number,6) > 0 || strncmp("0000",filmList.getAt(index).rent_id,5) > 0)
{
++ index;
}
else
{
throw string ("Not in list");
}
}
}
}
catch (string s)
{
cout << "\n***Failure*** " << s << endl;
}
Let me know if more code is required from any other parts of the program.
Here's my best guess with the code provided.
Let's say we are looking up 101001Casablanca, therefore I'm assuming filmId = "101001Casablanca". Also, assume the 101001Casablanca is checked out to customer 0001. We are comparing the first 6 characters of filmId to filmList.getAt(index).number, which I'm going to assume is at the very least "101001". This passes, but since it is checked out the second condition fails.
In the else we check the same strings in the first condition and still get 0 returned from strncmp which is false. The second condition is also false since strncmp("0000", "0001", 5) is -1. Therefore we go to the final else which throws.
If you are only checking string equality with strncmp, remember that it can return -1, therefore check if equal or not equal to 0.