C++ What is wrong with this while loop? - c++

I attempted to code a code a simple text adventure game from scratch as a programming exercise and got surprising results. Here is the complete code:
//Twisty Passages All Alike.
//An adventure game designed as a practice exercise.
#include <iostream>
#include <string>
using namespace std;
int main()
{
cout << "\t\tTwisty Passages, All Alike!\n";
cout << "\tA text adventure by Jellypox Studios.\n";
//INVENTORY INDEX NUMBERS:
//0. note
//1. hammer
//2.
//ROOM NUMBERS:
//0. living room
//1. storeroom
//Setting up the current room.
int ALL_ITEMS = 10;
string inventory[ALL_ITEMS];
int currentRoom = 0;
string input = "DEFAULT";
//Room 0: living room.
bool haveNote = false;
bool haveHammer = false;
//Room descriptions
if (currentRoom == 0)
{
cout << "You are in the living room.\nThere are doors to the south and west and a staircase to the north.\nYou can see: a table, a cat, a fireplace.\n\n";
}
else if (currentRoom == 1)
{
cout << "You are in the storeroom.\nThe room is a jumbled mass of cupboards, hanging sausages, left-out scraps of food and cockroaches.\nThe only thing of interest here is a large chest in the corner.";
}
//THE LIVING ROOM
while (currentRoom == 0)
{
cin >> input;
//THE TABLE
if (input == "look table" || "look at table")
{
cout << "You see: some bones and scraps";
if (haveHammer = false)
{
cout << ", a hammer";
}
if (haveNote == false)
{
cout << ", a note";
}
cout << ".\n\n";
}
else if (input == "look scraps" || "look at scraps" || "look bones" || "look at bones")
{
cout << "What a mess!\n\n";
}
else if (input == "look note" || "look at note" || "read note")
{
if (haveNote == false)
{
cout << "Pick it up first!\n\n";
}
else
{
cout << "It reads: \"Gone hunting. Will be back soon.\"";
}
}
else if (input == "get note" || "take note" || "pick up note")
{
if (haveNote == false)
{
cout << "Got the note.";
inventory[0] = "note";
haveNote = true;
}
else
{
cout << "You already have the note!\n\n";
}
}
else if (input == "look hammer" || "look at hammer")
{
cout << "It's just an ordinary hammer.\n\n";
}
else if (input == "get hammer" || "take hammer" || "pick up hammer")
{
if (haveHammer == false)
{
cout << "Got the hammer.\n\n";
inventory[1] = "hammer";
haveHammer = true;
}
else
{
cout << "You already have the hammer!\n\n";
}
}
//ELSWHERE IN THE ROOM
else if (input == "look cat" || "look at cat")
{
cout << "It stares up at you irritably.\n\n";
}
else if (input == "look fireplace" || "look at fireplace")
{
cout << "A flickering fire warms the house.\n\n";
}
else if (input == "south" || "go south")
{
//CODE TO MAKE THE DOOR UNLOCKABLE GOES HERE!
cout << "The door is locked.\n\n";
}
else if (input == "west" || "go west")
{
currentRoom = 1;
}
else if (input == "north" || "go north" || "upstairs" || "go upstairs")
{
currentRoom = 2;
}
else
{
cout << "Say what?";
}
}
return 0;
}
I tried using a while loop for the input/output system so that if you type "look at table," it gives you a description of the table, etc. but instead, it does this:
look at table
You see: some bones and scraps, a note.
You see: some bones and scraps, a note.
You see: some bones and scraps, a note.
get note
You see: some bones and scraps, a note.
You see: some bones and scraps, a note.
get hammer
You see: some bones and scraps, a note.
You see: some bones and scraps, a note.
go west
You see: some bones and scraps, a note.
You see: some bones and scraps, a note.
What all did I get wrong?

there are typos in this code, for example
if (haveHammer = false)
which should have double `=' I believe. The compile won't yell at you but the logic is not what you want.
there are non C++ codes in this code,
if (input == "hall..." || "ass" )
In C++, we don't use that although it is valid. It should be
if (input =="hall....") || input == "bbbb")
Since I think you won't just want to compare the memory address of these string literals.
(I did not read the code carefully, thanks for the comments.

It prints "You see: some bones..." once for every word in your input. If you type "the quick brown fox jumped over the lazy dogs" it will probably print "You see: ..." 9 times. So it looks like your "cin >> input" is breaking up your input string into tokens. You have to figure out how to get it to read a whole line and give it to you as one string; I'm so rusty at C++ that I can't remember. :-)
Also, you wrote: if (input == "look table" || "look at table")
The problem here is that "look at table" is always true, so the expression is always true. You probably want: if (input == "look table" || input == "look at table")

Related

C++ Blackjack code only going to first if statement

I'm trying to code a blackjack game and everything is going smoothly so far but for this bit. No matter what I input into hitStand it always goes to the first if statement and "hits". I would like for if "h" is inputted it "Hits" and if "s" is inputted it "Stands" and, if there is an invalid input, it will tell the user to try again.
I'm still fairly new to C++, so some help would be appreciated.
while (repeat == 0)
{
char hitStand;
cout << "Would you like to HIT or STAND [H/S]";
cin >> hitStand;
if (hitStand = "H" || "h")
{
PcardNew = rand() % 13 + 1;
cout << endl;
cout << "Your new card is: " << PcardNew << endl;
if (PcardNew > 10)
{
PcardNew = 10;
}
playerTotal = playerTotal + PcardNew;
cout << "Your new total is: " << playerTotal << endl;
}
else if (hitStand = "S" || "s")
{
break;
}
else
{
cout << "Please enter a valid imput [H/S]" << endl;
}
}
There are (at least) three errors in the single if (hitStand = "H" || "h") line!
First, the = operator is an assignment, not a comparison; to test for the equality of two operands, you need the == operator.
Second, the "H" and "h" constants are string literals - that is, multi-character, null-terminated strings of characters. Use single quotes for single characters (thus, 'H' and 'h').
Third, you can't compare one object with two others like that with a logical or (||) operator. You need to make two separate comparisons and then or the results of each:
So, use this:
if (hitStand == 'H' || hitStand == 'h')
{
//...
And similarly for your second test:
else if (hitStand == 'S' || hitStand == 's')
{
//...
That is because your condition in if statement is always true. Since "h" is in or (||).
Instead use:
if (hitStand == 'H' || hitStand == 'h')
and
else if (hitStand == 'S' || hitStand =='s')

Why does this case statement need an "if else" and not just an "if"?

So I am new to C++, and I am working through a pdf tutorial that is getting me started with basic stuff. I was writing a simple case program, and I experienced something weird.
#include "pch.h"
#include <iostream>
#include <string>
using namespace std;
enum string_feeling {
eGood,
eBad,
eOk,
};
string_feeling hashit(string const& feeling) {
if (feeling == "Good" || feeling == "good" || feeling == "GOOD") {
return eGood;
}
if (feeling == "Bad" || feeling == "bad" || feeling == "BAD") {
return eBad;
}
if (feeling == "Ok" || feeling == "ok" || feeling == "OK") {
return eOk;
}
else cout << "";
}
int main() {
string username;
cout << "Hello! Please enter your first name here: \n";
cin >> username;
cout << "Hello, " << username << "!\n";
cout << "How are you today? ";
string feeling;
cin >> feeling;
cout << endl;
switch (hashit(feeling)) {
case eGood:
cout << "That's great!";
break;
case eBad:
cout << "I hope you are happy soon!";
break;
case eOk:
cout << "That's good.";
break;
default:
cout << "Ok.";
}
}
Whenever I didn't have the "else" after the "if (feeling == ok)" stuff, the default case would never be called and if I entered something random it would give me the text from the eGood case. I was wondering why this is happening and since I'm learning C++ I didn't want to just brush it off not ever knowing why it worked after I put the else statement in there. So, if anyone could explain this to me that would be great! Sorry for my bad grammar.
Compile your program with warnings enabled like g++ -Wall -Wextra -Werror and it won't even compile, because string_feeling hashit(string const& feeling) does not return a value in all cases.
Compiling code without warnings enabled is a surefire way to waste time.
When none of conditions in the three if statements in hashit function become true, no return statement is executed in the function and undefined behavior is invoked.
(Quote from N3337 6.6.3 The return statement)
Flowing off the end of a function is equivalent to a return with no value; this results in undefined behavior in a value-returning function.
To avoid this, you should add one more kind to the enum
enum string_feeling {
eGood,
eBad,
eOk,
eOther // add this
};
and return it when no conditions are met.
string_feeling hashit(string const& feeling) {
if (feeling == "Good" || feeling == "good" || feeling == "GOOD") {
return eGood;
}
if (feeling == "Bad" || feeling == "bad" || feeling == "BAD") {
return eBad;
}
if (feeling == "Ok" || feeling == "ok" || feeling == "OK") {
return eOk;
}
else cout << "";
return eOther; // add this
}
You always have to return a value else the behavior is undefined
If you cannot modify your enum to add a case for an unknown feeling you can modify hashit to return true if feeling is valid and in that case to set the output parameter with the corresponding enum value, else to return false without setting the output parameter :
#include <iostream>
#include <string>
using namespace std;
enum string_feeling {
eGood,
eBad,
eOk,
};
bool hashit(string const& feeling, string_feeling & r) {
if (feeling == "Good" || feeling == "good" || feeling == "GOOD") {
r = eGood;
}
else if (feeling == "Bad" || feeling == "bad" || feeling == "BAD") {
r = eBad;
}
else if (feeling == "Ok" || feeling == "ok" || feeling == "OK") {
r = eOk;
}
else
return false;
return true;
}
int main() {
string username;
cout << "Hello! Please enter your first name here: \n";
cin >> username;
cout << "Hello, " << username << "!\n";
cout << "How are you today? ";
string feeling;
cin >> feeling;
cout << endl;
string_feeling f;
if (! hashit(feeling, f))
cout << "I do not understand how you are" << endl;
else {
switch (f) {
case eGood:
cout << "That's great!" << endl;
break;
case eBad:
cout << "I hope you are happy soon!" << endl;
break;
case eOk:
cout << "That's good." << endl;
break;
}
}
}
Compilation and execution :
pi#raspberrypi:/tmp $ g++ -Wall c.cc
pi#raspberrypi:/tmp $ ./a.out
Hello! Please enter your first name here:
bruno
Hello, bruno!
How are you today? good
That's great!
pi#raspberrypi:/tmp $ ./a.out
Hello! Please enter your first name here:
bruno
Hello, bruno!
How are you today? aze
I do not understand how you are
pi#raspberrypi:/tmp $
Out of that :
to name your enum string_feeling is not very clear, whatever the feeling was input as a string, better to just name it Feeling
it can be practical in hashit to get the string by value to change it to lowercase then to just compare it with with "good" "bad" and "ok" or to use strcasecmp on its .c_str(), allowing to also manage "gOoD" etc
If no if conditions will meet, hashit went to
else cout << "";
Since you didn't explicitly write the return statement, the function returns the default value 0, which is equal to eGood.
However, the default return value is not always 0. This is an undefined behaviour.
If you runs this code with a different compiler, you may get different results.

How to take a word from a file, and store it in a variable? C++

I have made a simple Rock, Paper, Scissors game in C++ Console Application. The game so far, worked great.. until I tried storing a word from a file, inside a variable, and then trying to use that variable in IF statements.
Here's how I store my word from the file, in a variable.
string comp_selection;
char player_selection;
And here's the part of the code where I am trying to get it to work.
cout << "Rock, Paper, or Scissors?";
cin >> player_selection;
if (comp_selection =='r' || comp_selection == 'R')
{
if (player_selection == 'r' || player_selection == 'R')
{
cout << "Computer chose " << comp_selection << "... It's a draw!" << std::endl;
}
else if (player_selection == 'p' || player_selection == 'P')
{
cout << "Computer chose " << comp_selection << "... You win!" << std::endl;
}
else if (player_selection == 's' || player_selection == 'S')
{
cout << "Computer chose " << comp_selection << "... You lose!" << std::endl;
}
}
The output should be:
Computer chose Rock... You win!
If the player chose Paper for example.
Instead, I get this error message
Severity Code Description Project File Line Suppression State
Error C2678 binary '==': no operator found which takes a left-hand operand of type 'std::string' (or there is no acceptable conversion)
Any help or guidance, would be great! Many thanks in advance.
Your comp_selection is defined as a std::string, but you are comparing it against a char ('r', etc). You should compare it against another string ("r") or just redefine comp_selection to be a character:
char comp_selection;
char player_selection;
In C++, a single character is denoted by single quotes ('c') whereas a string of characters is denoted by double quotes ("full string").
So far, you have been enjoying cin >> overloading recognizing that it's writing to a char. When reading from a file, you've apparently utilized a string. This is fine, except now the compiler is complaining that it does not know how to compare a string and a char. In short, your types don't match.
You can compare only first character of comp_selection (comp_selection[0])
if (comp_selection[0] =='r' || comp_selection[0] == 'R')
{
It is not the best solution but it requires the minimum code changes...
I've just realised that my code does what it was intended to do! By setting my
comp_selection to char, like someone here suggested, I can manually input what the computer chose by using the IF Statements.
For example:
if (comp_selection == 's' || comp_selection == 'S')
{
if (player_selection == 'r' || player_selection == 'R')
{
cout << "Computer chose Scissors... You win!" << std::endl;
}
else if (player_selection == 'p' || player_selection == 'P')
{
cout << "Computer chose Scissors... You lose!" << std::endl;
}
else if (player_selection == 's' || player_selection == 'S')
{
cout << "Computer chose Scissors... It's a draw!" << std::endl;
}
}

C++: goto and user input not working together

I am working on C++, and using a basic authentication method using if statements, so what I have here, is when the the input is not the desired combination, it will say Access denied and ask the user if they want to try again or quit. I tried doing this using the goto variable, but it hasn't been working. Help please? (Full code: https://pastebin.com/49LdGgJX)
else {
cout << "Access denied..." << " Try again? (Y/N) >" << flush;
string ask;
cin >> ask;
if(ask == "N" || "n"){
cout << "Shutting down..." << endl;
goto end;
}
else if(ask == "Y" || "y"){
goto restart;
}
else {
cout << "Invalid option." << endl;
goto restart;
}
}
end:
return 0;
Your if statements are wrong as:
if(ask == "N" || "n")
always evaluates to true because the "n" operand always evaluates to true and you are using a logical OR operator. The string literal of "n" decays to const char* pointer whose value is not 0 thus evaluating to true. What you want is:
if(ask == "N" || ask == "n")
and:
else if(ask == "Y" || ask == "y")
That being said don't use goto.
One of the possible break-ups of that code structure into more procedural way (wouldn't dare to call this "object oriented").
You can use similar way to break up menu handling code into separate functions for each option, etc.
If this would be multi-user app, then you may want to store instead of simple true/false full credentials of the user authenticated, like having a structure containing name, code (password probably can be thrown away after authentication to not keep it in memory long, if you don't need it later).
// returns true if user wants to exit
// sets authenticated to true when the Drew user is detected
bool AuthenticateUser(bool & authenticated) {
cout << "Enter your username >" << flush;
...
if (name == "Drew" && ...) {
authenticated = true;
cout << "Access granted. Welcome, " << name << "." << endl;
cout << "Welcome to Database of Drew" << endl;
return false;
}
cout << "Access denied..." << " Try again? (Y/N) >" << flush;
...
return (ask == "N" || ask == "n"); // N = wants to exit
}
// returns true if user wants to exit
bool ProceedWithMenu() {
cout << "1.\tAdd new record." << endl;
cout << "2.\tDelete record." << endl;
...
if (1 == value) {
...
}
if (5 == value) {
cout << "Application quitting... " << endl;
}
return (5 == value);
}
void mainLoop {
bool authenticated = false;
bool exitApp = false;
do {
if (!authenticated) {
exitApp = AuthenticateUser(authenticated);
} else {
exitApp = ProceedWithMenu();
}
// repeat authentication / menu until user decides to quit app
} while (!exitApp);
}
This example is still quite crude and oversimplified, just trying to illustrate power of do {} while, return, and similar. Often also continue and break can be of great help to control the flow of code execution, without any goto and labels.

Want to go back to a function on if/else statement

Please look at this code, and I will explain:
void GameOver()
{
cout << "\nWelp, you died. Want to try again?" << endl;
cin >> choice;
if (choice == "Yes" || "yes")
{
/*This is where I want the code. I want it to go back to the last
function that the player was on.*/
}
if (choice == "No" || "no")
{
cout << "Are you sure? The game will start over when you open it back up." << endl;
cin >> choice;
if (choice == "No" || "no")
{
cout << "Well, bye now!" << endl;
usleep(1000000);
exit (EXIT_FAILURE);
}
}
return;
}
I would like it so that when I choose "Yes" in the GameOver function, I want an if/else statement that says "if you came from this function, then you will go to that function", you see what I'm saying?
For example, let's say I am in the GameOver function and I came from a FightProcess function. I choose "Yes" then it will go to the Town function.
How would I code that?
First, a statement like this:
if (choice == "Yes" || "yes")
Is coded wrong, and will always evaluate as true. You need to use this instead:
if (choice == "Yes" || choice == "yes")
Or better, use a case-insensitive comparison function, like this:
if (strcmpi(choice.c_str(), "Yes") == 0)
Second, unless you add an input parameter, or use a global variable, GameOver() has no idea who is calling it. So what you want to do does not belong in GameOver() itself to begin with. It belongs in the calling function instead. GameOver() exits the game if the user chooses not to continue. That is all it should do. The calling function should decide how to retry if the game does not exit. For example:
void GameOver()
{
cout << "\nWelp, you died. Want to try again?" << endl;
cin >> choice;
//if (choice == "Yes" || choice == "yes")
if (strcmpi(choice.c_str(), "Yes") == 0)
return;
cout << "Are you sure? The game will start over when you open it back up." << endl;
cin >> choice;
//if (choice == "No" || choice == "no")
if (strcmpi(choice.c_str(), "No") == 0)
return;
cout << "Well, bye now!" << endl;
usleep(1000000);
exit (EXIT_FAILURE);
}
void FightProcess()
{
...
if (defeated)
{
GameOver();
Town();
return;
}
...
}
Or, if Town() is the function that called FightProcess():
void FightProcess()
{
...
if (defeated)
{
GameOver();
return;
}
...
}
void Town()
{
...
FightProcess();
...
}
Or, it might make more sense to have FightProcess() loop instead:
void FightProcess()
{
...
do
{
...
if (won)
break;
GameOver();
...
}
while (true);
...
}
See how things get more flexible when you don't put restrictive logic where it does not belong?
I would recommend using a parameter in the GameOver function. Then you could pass a different parameer each time you want to go somewhere else. For example, call GameOver(1) from function 1 and GameOver(2) from function 2.
This is assuming that returning from GameOver and executing different options in the calling function isn't an option.
Or you can choose to fire a event in FightProcess().
eg:-
void FightProcess(){
...
if( ...){
observer.send("FightProcess"); // or with more information.
//observer.send("FightProcess",Avatar::Killed);
GameOver();
}
}
And in the GameOver() you can query the observer to find what the last event was.