Do-while loop displays 2 prompt at a time, please reply [duplicate] - c++

This question already has answers here:
Why does std::getline() skip input after a formatted extraction?
(5 answers)
Closed 2 years ago.
I'm new to programming and trying a program that You need to guess the name of a video game character, there are only 3 guesses if you ran out of guesses you will lose. I used a do-while loop here so I can do it again and again... The problem here is that every time The loop starts again It displays the prompt 2 times even though It's supposed to be 1 time prompt per guess but it displays 2 prompt. Can you please help me maybe I'm doing the algorithm wrong, Thanks!
#include <iostream>
using namespace std;
int main()
{
char rerun_option;
do {
string secretWord = "Arthur Morgan";
string guess;
int guessCount = 0;
int guessLimit = 3;
bool outofGuesses = false;
while (secretWord != guess && !outofGuesses) {
if (guessCount < guessLimit) {
cout << "Enter video game character name guess: ";
getline(cin, guess);
guessCount++;
}
else {
outofGuesses = true;
}
}
if (outofGuesses) {
cout << "You Lose!" << endl;
outofGuesses = false;
}
else {
cout << "You Win!" << endl;
}
cout << "Try Again?(Y/N) ";
cin >> rerun_option;
} while (rerun_option == 'Y' || rerun_option == 'y');
return 0;
}

EDIT: stackoverflow.com/a/21567292/4645334 is a good example of your problem, explains why you are experiencing it, and explains how you can solve it. I have provided a working example of your code below, as well as a link to more information on the use and description of cin.ignore().
#include <iostream>
using namespace std;
int main()
{
char rerun_option;
do {
string secretWord = "Arthur Morgan";
string guess;
int guessCount = 0;
int guessLimit = 3;
bool outofGuesses = false;
while (secretWord != guess && !outofGuesses) {
if (guessCount < guessLimit) {
cout << "Enter video game character name guess: ";
cin.ignore(); // <-- ADD THIS LINE RIGHT HERE
getline(cin, guess);
guessCount++;
}
else {
outofGuesses = true;
}
}
if (outofGuesses) {
cout << "You Lose!" << endl;
outofGuesses = false;
}
else {
cout << "You Win!" << endl;
}
cout << "Try Again?(Y/N) ";
cin >> rerun_option;
} while (rerun_option == 'Y' || rerun_option == 'y');
return 0;
}
https://www.tutorialspoint.com/what-is-the-use-of-cin-ignore-in-cplusplus

Related

Play again option in C++ not working for number guessing game

When the user inputs 'Y' to try again, the game runs but only gives the user 1 try instead of 3 tries. Program works fine the first time it runs with 3 tries. I'm guessing something is wrong with my loop that it does not reset the number of tries? Let me know if there's any other way I could write my code to make it cleaner/better. Thanks a bunch.
#include <iostream>
#include <cstdlib>
#include <time.h>
using namespace std;
int guessNum;
int randomNum;
int Tries = 0;
int startGame()
{
cout << "Number: ";
cin >> guessNum;
return guessNum, Tries;
}
int main(int a, int b)
{
while (true) {
a = guessNum;
b = Tries;
char ans;
// Random number
srand(time(NULL));
randomNum = rand() % 20 + 1;
// Introduction
cout << "Guess a number between 1 to 20. You have three attempts." << endl;
do
{
startGame();
if (guessNum < randomNum)
{
cout << "Wrong! It is too low." << endl;
}
else if (guessNum > randomNum)
{
cout << "Wrong! It is too high." << endl;
}
Tries++;
}
while (guessNum != randomNum && Tries < 3);
if (guessNum != randomNum) // Wrong answer & run out of tries
{
cout << "Oops.. All attempts used. The answer is " << randomNum << endl;
}
else if (guessNum == randomNum) // User guessed correct number
{
cout << "Yes! You are correct!" << endl;
}
cout << "Try again?";
cin >> ans;
cin.ignore();
if (ans == 'N')
{
cout << "Thanks for playing!";
break;
}
}
}
EDITED V1
#include <iostream>
#include <ctime>
using namespace std;
int guessNum;
int startGame()
{
cout << "Number: ";
cin >> guessNum;
return guessNum;
}
int main()
{
while (true) {
int randomNum;
int Tries = 0;
char ans;
// Random number
srand(time(NULL));
randomNum = rand() % 20 + 1;
// Introduction
cout << endl << "Guess a number between 1 to 20. You have three attempts." << endl;
do
{
startGame();
if (guessNum < randomNum)
{
cout << "Wrong! It is too low." << endl;
}
else if (guessNum > randomNum)
{
cout << "Wrong! It is too high." << endl;
}
Tries++;
}
while (guessNum != randomNum && Tries < 3);
if (guessNum != randomNum) // Wrong answer & run out of tries
{
cout << "Oops.. All attempts used. The answer is " << randomNum << endl;
}
else if (guessNum == randomNum) // User guessed correct number
{
cout << "Yes! You are correct!" << endl;
}
cout << "Try again? Y/N: ";
cin >> ans;
cin.ignore();
ans = toupper(ans);
if (ans == 'N')
{
cout << endl << "Thanks for playing!";
break;
}
else
{
Tries = 0;
}
}
}
Actually, your program has several defects.
Firstly, If you wonder why the game behaves unexpected way after the first one, You did not set back the Tries to 0 after playing the game.
And, int startgame() should return only one variable. You are trying to return guessnum and Tries at the same time. The only reason the first game is running as expected is that you are using global variables, which is also considered as a bad practice(Some company may fire you if you use it without any good reason).
Furthermore, you are getting two int function arguments from main call, which is not valid. (main function signature should be int main(void) or int main(int argc, char* argv[])). I am surprised that the compiler did not catch this error.
And the variables (int a, int b) are actually not used. When you find unused variables, it is usually a good practice to remove them for maintainability.
So int Tries = 0; is a global variable. It's set before main().
You basically have
int Tries = 0;
main()
{
while (true) {
do
{
Tries++;
} while(Tries < 3);
}
}
Do you see that for each iteration in while, the value of Tries from the previous iteration is used? You would need to reset it before iterating again.
But there is no reason to have "Tries" as a global variable since you only need to know about it in the while(true)-loop. This is generally the case for a variable - put it to the closest scope possible:
main()
{
while (true) {
int Tries = 0;
do
{
Tries++;
} while(Tries < 3);
}
}
Now it's correctly reset between loops, and it is clear it is only needed for the loop logic.
Try to do the same for you other variables.
Try:
if (ans == 'N')
{
cout << "Thanks for playing!";
break;
}
else
{
Tries = 0;
}

How to prompt user to re-loop the whole program?

I want the user to choose between playing the game again or ending the program, however when prompted, if they press 'y' the same thing gets repeated over and over instead of the whole program from the very beginning. I've tried while loops, do/while loops, if statements, rearranging the code, but nothing has worked. Any advice?
#include <iostream>
#include <string>
using namespace std;
int main(){
string animal = "fish";
string guess;
char choose = 'Y' ;
int count = 0;//keeps a running total of how many times the user
has guessed an answer.
int limit = 5;//allows user to guess only 5 times, otherwise
they loose the game.
bool out_of_guesses = false;//to check whether the user has run
out of guesses.
cout << "I am thinking of an animal.\n" << endl;
do{
while(animal != guess && !out_of_guesses){//Nested while
loop inside main loop to keep track of how many tries the user has
attempted and to validate their answers.
if(count < limit){
cout << "Can you guess what animal I am thinking of?: ";
getline(cin, guess);
count++;
if(animal != guess){
cout << "\nHmm, nope. That's not the animal I'm
thinking of." << endl;
if(count > 2 && count <5){
cout << "I'll give you a hint. It lives in
water." << endl;
}
}
}
else{
out_of_guesses = true;
}
}//End nested while loop
if(out_of_guesses){
cout << "\nI'm sorry, but you are out of guesses." <<
endl;
}
else{
cout << "\n*** Good job! You guessed the correct animal!
***" << endl;
cout << "\t\t><)))º> ❤ <º)))><\t\t" << endl;
}
//The do-while loop is there to ask the user if they wish to
play the game again.
cout << "Would you like to try again?(y/n): ";
cin >> choose;
if(choose == 'N' || choose == 'n')
break;
}while(choose == 'Y' || choose == 'y');
return 0;
}
The bool out_of_guesses = false; must be in-between while(true) and while(animal != guess && !out_of_guesses), and not outside the first while loop. Because our while loop condition is always false, and then it does enter it.
You should also reset your guess variable in-between those 2 loops, else same thing could happen (false while loop) in case of the answer is found.
Here the code with some refactoring/review, which I used the guess as upper case to handle any typography of the answer. I also removed the out of guess variable to use the count and limit one instead.
#include <iostream>
#include <string>
#include <cctype>
int main()
{
const std::string animal = "FISH";
const int limit = 5;
do
{
std::cout << "I am thinking of an animal.\n";
int count = 0;
std::string guess;
while(animal.compare(std::toupper(guess)) != 0 && count < limit)
{
std::cout << "Can you guess what animal I am thinking of?: \n";
std::cin >> guess;
count++;
if(animal.compare(std::toupper(guess)) != 0)
{
std::cout << "\nHmm, nope. That's not the animal I'm thinking of.\n";
if(count > 2)
{
std::cout << "I'll give you a hint. It lives in water.\n";
}
}
}
}//End nested while loop
if(count >= limit)
{
std::cout << "\nI'm sorry, but you are out of guesses.\n";
}
else
{
std::cout << "\n*** Good job! You guessed the correct animal! ***\n";
std::cout << "\t\t><)))º> ❤ <º)))><\t\t\n";
}
char choose = 'Y' ;
std::cout << "Would you like to try again?(y/n): ";
std::cin >> choose;
if(std::toupper(choose) == 'N') break;
} while(true);
return 0;
}

How can I clean this code up by using a loop?

Basically, this program allows a user to enter a sentence and depending on the users selection, it will show the middle character of the sentence, display it uppercase or lowercase, or backwards. Simple program, but I am new to programming so that may be the problem. I would like to figure out how to use loops instead of a ton of if statements. When I try to make some loops it breaks certain parts of the code but I am sure that is because I don't properly understand them. If you have any criticism or any advice on the code, I'd be happy to hear it. Thanks in advance!
#include "stdafx.h"
#include <iostream>
#include <string>
using namespace std;
int main()
{
int sel;
string sent;
bool validinput;
int i;
int x;
int j;
int a;
cout << "Welcome to my program. Enter a sentence and select one of the options below.\n";
cout << "Enter -999 to exit the program." << endl;
cout << "============================================================================" << endl;
cout << endl;
cout << "1. Display the middle character if there is one." << endl;
cout << "2. Convert to uppercase." << endl;
cout << "3. Convert to lowercase." << endl;
cout << "4. Display backwards." << endl;
cout << "Enter a sentence: ";
getline (cin, sent);
cout << "Selection: ";
cin >> sel;
if (sel < 1 && sel > 4)
{
cout << "Invalid input. Try again. Selection: ";
cin >> sel;
validinput = false;
}
else (sel >= 1 && sel <= 4);
{
validinput = true;
}
if (validinput == true)
{
if (sel == 1)
{
j = sent.length() / 2;
cout << "The middle character is: " << sent.at(j) << endl;
}
if (sel == 2)
{
for (int i = 0; i < sent.length(); i++)
{
if (sent.at(i) >= 'a' && sent.at(i) <= 'z')
{
sent.at(i) = sent.at(i) - 'a' + 'A';
}
}
cout << "Uppercase: " << sent << endl;
}
if (sel == 3)
{
for (int x = 0; x < sent.length(); x++)
{
if (sent.at(x) >= 'A' && sent.at(x) <= 'Z')
{
sent.at(x) = sent.at(x) - 'A' + 'a';
}
}
cout << "Lowercase: " << sent << endl;
}
if (sel == 4)
{
for (a = sent.length() - 1; a >= 0; a--)
{
cout << sent.at(a);
}
}
}
system("pause");
return 0;
}
Personally I would use the switch selection statement. I roughly did this just to explain a bit on how it can make your code more friendly and understandable.
int sel;
bool validInput = false;
switch(sel)
{
case 1:
//display middle char if there's one
case 2:
//convert to uppercase
case 3:
//convert to lowercase
case 4:
//display backwards
validInput = true;
break;
default: //if number does not meat 1, 2, 3 or 4
validInput = false;
break;
}
As you may notice, for case 1, case 2, case 3 and case 4, there's a break just to say that if the number is between 1 to 4; validInput is true.
Reference: Switch Selection Statement
i suggest using a switch. It will organize your code better. From looking at your code you seem to have used for and if wisely. But I suggest the if statements checking for the input be replaced with switch.

Creating a menu using vectors, strings and arrays while reading from 2 text files

Alright, I been trying to do this for a couple of hours but I'm not getting anywhere. First of
all, I have 2 text files that I need to read from a different function which is simple enough. Then for one of the text files, mainly the college.txt, I have to add it to a vector of strings; for the other text file(states.txt), I have to add the states to parallel arrays of strings.
The problem(This is related to the college.txt file) I have is how do I compare the strings the user inputs to the strings inside the vector since I have to validate whether or not the colleges/universities that the user inputs are on the list(and of course repeat it until the user decides to quit but that's also simple enough to do with a while loop).
Note1: Before you ask, The else/if with empty statements are empty because I want to focus on this problem first and then I will continue on with the program.
Note2: The IDE that I'm using is CodeBlocks
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <cstdlib>
using namespace std;
bool DoesStringEqualVector(vector<string> total, string name)
{
for (unsigned int i=0; i < total.size(); ++i)
{
if (name == total[i])
return true;
}
return false;
}
void collegesUniversities(string)
{
ifstream campuses;
campuses.open("colleges.txt");
string schools;
vector<string> schoolVector;
if(!campuses)
cerr << "Error opening file. ";
else
{
while(campuses.good())
{
getline(campuses,schools, '\n');
schoolVector.push_back(schools);
cout << schools << endl;
}
}
DoesStringEqualVector(schoolVector, schools);
campuses.close();
}
int main()
{
char response;
string comparison;
int choice;
string userInput;
cout << "\nWelcome to my college and university search program.\n";
cout << "\nPress any button to continue.\n ";
system("pause>nul");
do
{
cout << "\nPress 1 to enter possible colleges and universities.";
cout << "\nPress 2 to find out how many colleges and universities";
cout << " appear in your state.\n";
cout << "Press 3 to find the total amount of colleges and";
cout << " universities in our list. ";
cout << "\nPress 4 to quit. ";
cin >> choice;
if(choice == 1)
{
do
{
cout << "\nEnter the name of your college/university. ";
cin >> userInput;
collegesUniversities(comparison);
if(userInput != comparison)
cout << "\nThis institution isn't on out list.\n ";
else
cout << "\nThis institution is on the list.\n";
cout << "\nWould you like to return to the menu?[Y/N] ";
cin >> response;
while(response != 'Y' && response != 'y' && response != 'N' &&
response != 'n')
{
cerr << "\nError, Invalid Input.";
cin >> response;
}
}
while(response != 'N' && response != 'n');
}
else if(choice == 2)
{
}
else if(choice == 3)
{
}
else if(choice == 4)
{
cout << "\nThank you for using my program. ";
cout << "Have a great day.\n ";
}
else
{
cerr << "\nError, Invalid input. ";
cout << "Only integers from 1 through 4 are allowed.\n";
}
}
while(choice != 4);
}
Wrap it all up in a method that checks through the vector:
bool IsStringInVector(vector <string> collection, string item)
{
for (int i=0; i < collection.size(); ++i)
{
if (item == collection[i])
return true;
}
return false;
}
You have to scan through the collection to see if it's in there.

C++ Function being called when it isn't supposed to

I'm nearly finished working on a small guessing game, but i have run into a problem I don't know how to work around.
The problem is with the check_guess function that is checking to make sure the guess being input is a number between 1 and 100.
When running the program the first time, everything works fine.
http://i.imgur.com/pprunDT.png (I would post images if my reputation weren't so low)
But every time after, where yes to play again is chosen, the program runs through the check_guess function and displays "Invalid Input" when it shouldn't
http://i.imgur.com/8OSnSJt.png
I'm not sure why the program is behaving this way.
The code for the entire program is here:
#include <iostream>
#include <cstdlib> //for rand
#include <ctime> //for time
#include <string>
#include <sstream> //for conversions from string to int
using namespace std;
int check_guess(int tries) { //function for limiting the input of guess
string guess = "";
int result = 0;
do {
getline (cin, guess);
istringstream convert(guess);
if ( !(convert >> result) || (result < 1 || result > 100) ) {
result = 0;
cout << "Invalid Input.\n" << endl;
cout << "You have " << tries << " tries: ";
}
} while (result == 0);
return result;
}
bool play_again() { //function for limiting the input of mode
bool quit;
string yn;
do {
cin >> yn;
if ( yn == "y" || yn == "yes" ) {
quit = false;
}
else if ( yn == "n" || yn == "no" ) {
quit = true;
}
else {
yn = "invalid";
cout << "Invalid input.\n\nEnter 'y' or 'n': ";
}
} while ( yn == "invalid" );
return quit;
}
int main()
{
srand(time(0)); //sets seed to be random
int mystery = 0; //defines mystery number
int guess = 0; //defines guess
int tries = 5; //defines trys
bool quit = false; //defines replay or quit
cout << "----------------------------------\n";
do { //while mode is not set to quit, keep playing
tries = 5; //resets tries each new game
mystery = rand() % 100 + 1; //sets mystery number to be random
guess = 0;
cout << "Pick a number between 1 and 100.\n\nYou have 5 tries: ";
while (tries != 0) { //loops until you have no tries left
guess = check_guess(tries);
if (guess == mystery) { tries = 0; } //if you guess right it ends the loop
else { tries--; } //guessing wrong lowers tries by 1
if ( tries != 0 && guess > mystery) {
cout << guess << " is too high.\n" << endl;
cout << "You have " << tries << " tries: ";
}
if ( tries != 0 && guess < mystery) {
cout << guess << " is too low.\n" << endl;
cout << "You have " << tries << " tries: ";
}
}
if (guess == mystery) { //if guess == mystery by time loop ends you win
cout << "Got it! You Win!\n" << endl;
}
else { //if not, you lose
cout << "You Lose! The number was: " << mystery << ".\n" <<endl;
}
cout << "-------------------\n";
cout << "Play Again?(y/n): "; //ask user to play again
quit = play_again();
cout << "-------------------\n";
if (quit == false)
cout << endl;
} while (quit == false);
cout << "----------------------------------" << endl;
return 0;
}
I'm not sure how to fix this.
this line:
cin >> yn;
only reads the 'y' but not the end of line. As a result, the next execution of this instruction
getline (cin, guess);
initializes guess to an empty string.
On line 19, import the code "cin.ignore();" without quotations.
So your code reads as
`int check_guess(int tries) { //function for limiting the input of guess
string guess = "";
int result = 0;
do {
getline (cin, guess);
istringstream convert(guess);
if ( !(convert >> result) || (result < 1 || result > 100) ) {
result = 0;
cin.ignore();
cout << "Invalid Input.\n" << endl;
cout << "You have " << tries << " tries: ";
}
} while (result == 0);
return result;
}
`
and so on. This stops input into the console briefly. You're code is reading the 'y' to try again as the input for the number when you restart as well. Putting in the little line cin.ignore(), stops it from inputting y twice.
Change play_again() to:
bool play_again() { //function for limiting the input of mode
bool quit;
string yn;
do {
getline (cin, yn);
if ( yn == "y" || yn == "yes" ) {
quit = false;
}
else if ( yn == "n" || yn == "no" ) {
quit = true;
}
else {
yn = "invalid";
cout << "Invalid input.\n\nEnter 'y' or 'n': ";
}
} while ( yn == "invalid" );
return quit;
}