_getch() not detecting keystrokes first few times - c++

I'm writing my first actual program in C++, and I'm just wondering why _getch() takes a few times to actually detect that I pressed a key. It'll usually take 2 or 3 tries before it actually picks it up and does what it's supposed to, and the first few times it just acts like nothing's happened. Here's all the relevant code:
#include <iostream>
#include <conio.h>
int main()
{
using namespace std; // so i don't have to do 'std::cout' for every time I want to print, among other things
cout << "Bag's Example Program\n\n";
system("pause"); // waits for user input, with a "Press any key to continue" message
bool chosen = false;
while (chosen == false) {
system("cls"); // clears the screen
cout << "Enter a string: ";
string words;
cin >> words;
cout << "You entered: " << words << "\n\nIs this correct? (Y/[N]): ";
_getch(); // waits for user input
if ((_getch() != 121) || (_getch() != 89)) { // if user's keystroke was NOT the 'y' key
cout << "user selection was NO\n";
}
else { chosen = true; }
}
}

Related

C++ program stuck in an infinite loop

Please note that I am a complete beginner at C++. I'm trying to write a simple program for an ATM and I have to account for all errors. User may use only integers for input so I need to check if input value is indeed an integer, and my program (this one is shortened) works for the most part.
The problem arises when I try to input a string value instead of an integer while choosing an operation. It works with invalid value integers, but with strings it creates an infinite loop until it eventually stops (unless I add system("cls"), then it doesn't even stop), when it should output the same result as it does for invalid integers:
Invalid choice of operation.
Please select an operation:
1 - Balance inquiry
7 - Return card
Enter your choice and press return:
Here is my code:
#include <iostream>
#include <string>
using namespace std;
bool isNumber(string s) //function to determine if input value is int
{
for (int i = 0; i < s.length(); i++)
if (isdigit(s[i]) == false)
return false;
return true;
}
int ReturnCard() //function to determine whether to continue running or end program
{
string rtrn;
cout << "\nDo you wish to continue? \n1 - Yes \n2 - No, return card" << endl;
cin >> rtrn;
if (rtrn == "1" and isNumber(rtrn)) { return false; }
else if (rtrn == "2" and isNumber(rtrn)) { return true; }
else {cout << "Invalid choice." << endl; ReturnCard(); };
return 0;
}
int menu() //function for operation choice and execution
{
int choice;
do
{
cout << "\nPlease select an operation:\n" << endl
<< " 1 - Balance inquiry\n"
<< " 7 - Return card\n"
<< "\nEnter your choice and press return: ";
int balance = 512;
cin >> choice;
if (choice == 1 and isNumber(to_string(choice))) { cout << "Your balance is $" << balance; "\n\n"; }
else if (choice == 7 and isNumber(to_string(choice))) { cout << "Please wait...\nHave a good day." << endl; return 0; }
else { cout << "Invalid choice of operation."; menu(); }
} while (ReturnCard()==false);
cout << "Please wait...\nHave a good day." << endl;
return 0;
}
int main()
{
string choice;
cout << "Insert debit card to get started." << endl;
menu();
return 0;
}
I've tried every possible solution I know, but nothing seems to work.
***There is a different bug, which is that when I get to the "Do you wish to continue?" part and input any invalid value and follow it up with 2 (which is supposed to end the program) after it asks again, it outputs the result for 1 (continue running - menu etc.). I have already emailed my teacher about this and this is not my main question, but I would appreciate any help.
Thank you!
There are a few things mixed up in your code. Always try to compile your code with maximum warnings turned on, e.g., for GCC add at least the -Wall flag.
Then your compiler would warn you of some of the mistakes you made.
First, it seems like you are confusing string choice and int choice. Two different variables in different scopes. The string one is unused and completely redundant. You can delete it and nothing will change.
In menu, you say cin >> choice;, where choice is of type int. The stream operator >> works like this: It will try to read as many characters as it can, such that the characters match the requested type. So this will only read ints.
Then you convert your valid int into a string and call isNumber() - which will alway return true.
So if you wish to read any line of text and handle it, you can use getline():
string inp;
std::getline(std::cin, inp);
if (!isNumber(inp)) {
std::cout << "ERROR\n";
return 1;
}
int choice = std::stoi(inp); // May throw an exception if invalid range
See stoi
Your isNumber() implementation could look like this:
#include <algorithm>
bool is_number(const string &inp) {
return std::all_of(inp.cbegin(), inp.cend(),
[](unsigned char c){ return std::isdigit(c); });
}
If you are into that functional style, like I am ;)
EDIT:
Btw., another bug which the compiler warns about: cout << "Your balance is $" << balance; "\n\n"; - the newlines are separated by ;, so it's a new statement and this does nothing. You probably wanted the << operator instead.
Recursive call bug:
In { cout << "Invalid choice of operation."; menu(); } and same for ReturnCard(), the function calls itself (recursion).
This is not at all what you want! This will start the function over, but once that call has ended, you continue where that call happened.
What you want in menu() is to start the loop over. You can do that with the continue keyword.
You want the same for ReturnCard(). But you need a loop there.
And now, that I read that code, you don't even need to convert the input to an integer. All you do is compare it. So you can simply do:
string inp;
std::getline(std::cin, inp);
if (inp == "1" || inp == "2") {
// good
} else {
// Invalid
}
Unless that is part of your task.
It is always good to save console input in a string variable instead of another
type, e.g. int or double. This avoids trouble with input errors, e.g. if
characters instead of numbers are given by the program user. Afterwards the
string variable could by analyzed for further actions.
Therefore I changed the type of choice from int to string and adopted the
downstream code to it.
Please try the following program and consider my adaptations which are
written as comments starting with tag //CKE:. Thanks.
#include <iostream>
#include <string>
using namespace std;
bool isNumber(const string& s) //function to determine if input value is int
{
for (size_t i = 0; i < s.length(); i++) //CKE: keep same variable type, e.g. unsigned
if (isdigit(s[i]) == false)
return false;
return true;
}
bool ReturnCard() //function to determine whether to continue running or end program
{
string rtrn;
cout << "\nDo you wish to continue? \n1 - Yes \n2 - No, return card" << endl;
cin >> rtrn;
if (rtrn == "1" and isNumber(rtrn)) { return false; }
if (rtrn == "2" and isNumber(rtrn)) { return true; } //CKE: remove redundant else
cout << "Invalid choice." << endl; ReturnCard(); //CKE: remove redundant else + semicolon
return false;
}
int menu() //function for operation choice and execution
{
string choice; //CKE: change variable type here from int to string
do
{
cout << "\nPlease select an operation:\n" << endl
<< " 1 - Balance inquiry\n"
<< " 7 - Return card\n"
<< "\nEnter your choice and press return: ";
int balance = 512;
cin >> choice;
if (choice == "1" and isNumber(choice)) { cout << "Your balance is $" << balance << "\n\n"; } //CKE: semicolon replaced by output stream operator
else if (choice == "7" and isNumber(choice)) { cout << "Please wait...\nHave a good day." << endl; return 0; }
else { cout << "Invalid choice of operation."; } //CKE: remove recursion here as it isn't required
} while (!ReturnCard()); //CKE: negate result of ReturnCard function
cout << "Please wait...\nHave a good day." << endl;
return 0;
}
int main()
{
string choice;
cout << "Insert debit card to get started." << endl;
menu();
return 0;
}

cin.get() is taking input from previous cin.get()

I'm super new to this, and am trying to code a simple shop interface for a CLI adventure game.
The problem I'm having is in between uses of cin.get(). I've read another post but don't understand what's being said. Can someone explain like I'm 5?
I use cin.get() once in the MainMenu() to wait for Enter to continue. This punishes the player's health if they do anything other than press Enter.
I then move forwards to the Introduction(), where I'm trying to pull the same trick, but it carries the input from cin.get() from the MainMenu() function.
The other code in main() is just keeping track of the character's health and stopping the program if it reaches 0 by way of another function.
#include <iostream>
#include <ctime>
#include <string>
using namespace std;
int MainMenu()
{
cout << "\nPress the ENTER key\n";
char Input = cin.get();
if (Input == '\n')
{
return 0;
}
else if (Input != '\n')
{
cout << "I meant ONLY the ENTER key... Oh well its your health pool.\n";
CharHealth(-2);
cout << "You took 2 damage. \nYou now have " << CharHealth(0) << "Health.\n";
return 0;
}
}
int Introduction()
{
cout << "you awake in a puddle, walk to town. \nPress [ENTER]";
char Input = cin.get();
if (Input != '\n')
{
cout << "\nfor real?\nTake Another 2 Damage\nwhat did you think?... Idiot" ;
CharHealth(-2);
return 0;
}
else
{
return 0;
}
}
int main()
{
MainMenu();
Introduction();
while (CharHealth(0) > 0)
{
cout << "winner";
return 0;
}
cout << "\n You died. idiot.";
return 0;
}
Don't judge my story telling, everything is still placeholders right now.
My console just reads:
Press the ENTER key
asdf
I meant ONLY the ENTER key... Oh well its your health pool.
You took 2 damage.
You now have 1Health.
you awake in a puddle, walk to town.
Press [ENTER]
for real?
Take Another 2 Damage
what did you think?... Idiot
You died. idiot.
C:\Users\KR's\Documents\text Shop>
cin.get() reads 1 char at a time. So, for example, if the user types in asdf, then the next cin.get() will read and return a, leaving sdf in cin's input buffer. Then the next cin.get() will read and return s, leaving df in cin's input buffer. And so on. Your code is not taking that into account. There is only 1 input buffer in cin, there is no per-function input buffer, like you are expecting.
If the user does not type in what you want, use cin.ignore() to discard the unwanted input. For example:
...
#include <limits>
...
int MainMenu()
{
cout << "\nPress the ENTER key\n";
char Input = cin.get();
if (Input != '\n')
{
cin.ignore(numeric_limits<streamsize>::max(), '\n'); // <-- ADD THIS
cout << "I meant ONLY the ENTER key... Oh well its your health pool.\n";
CharHealth(-2);
cout << "You took 2 damage. \nYou now have " << CharHealth(0) << "Health.\n";
}
return 0;
}
int Introduction()
{
cout << "you awake in a puddle, walk to town. \nPress [ENTER]";
char Input = cin.get();
if (Input != '\n')
{
cin.ignore(numeric_limits<streamsize>::max(), '\n'); // <-- ADD THIS
cout << "\nfor real?\nTake Another 2 Damage\nwhat did you think?... Idiot" ;
CharHealth(-2);
}
return 0;
}
cin.get() reads only one character and leave other inputted things on the stream.
It seems you want to read until \n is read. It can be done like this:
int MainMenu()
{
cout << "\nPress the ENTER key\n";
int count = 0;
while (cin.get() != '\n') count++;
if (count == 0)
{
return 0;
}
else if (count != 0) // we won't need this if statement, but I respect you
{
cout << "I meant ONLY the ENTER key... Oh well its your health pool.\n";
CharHealth(-2);
cout << "You took 2 damage. \nYou now have " << CharHealth(0) << "Health.\n";
return 0;
}
}
(warning: This code will fail into an infinite loop if we get EOF before newline)

Detect blank input on integer type variable?

I am currently working on a text based adventure game as a project for class. I have mostly everything started and working fine. The only problem is when I ask the user which room they want to change to, if they enter a blank input, then a message should output saying "You must choose a room." For the life of me I cannot figure it out. Any help is much appreciated.
Code:
#include <iostream>
#include <cstdlib>
#include <ctime>
using namespace std;
int main() {
bool game_play = true;
bool game_start = true;
int room_change;
int room_current = 0;
while (game_play == true) {
if (game_start == true) {
srand((unsigned int)time(NULL));
room_change = rand() % 2 + 1;
game_start = false;
}
else {
for (bool check = false; check == false;) { // Check if input is invalid
cin >> room_change;
if (cin.fail()) {
cout << "Choose an existing room.";
cin.clear();
cin.ignore();
}
else if (room_change == room_current) {
cout << "You're already in that room.";
}
else {
check = true;
}
}
}
switch (room_change) {
case 1:
cout << "You are in room 1.";
room_current = 1;
break;
case 2:
cout << "You are in room 2.";
room_current = 2;
break;
case 3:
game_play = false;
break;
default:
cout << "That room doesn't exist.";
}
}
return 0;
}
I just ran your code and when you hit enter, it will keep waiting until you enter a number or something invalid such as a character or a string. I did find that if you change your code from
cin >> room_change;
to
cin >> noskipws >> room_change;
when the user inputs a blank, it will cause the cin.fail() to return true and then proceed to print "Choose an existing room."
In your situation, the while loop will keep getting called until we have valid input. The "Choose an existing room" does get repeated because room_change is an integer, so when we hit enter, the '\n' will be left in the buffer. The while loop on the next iteration then reads that '\n' and executes the cin.fail() before letting you input something else. One solution I found is to use more cin.ignore() statements.
for (bool check = false; check == false;) { // Check if input is invalid
cin >> noskipws >> room_change;
if (cin.fail()) {
cout << "Choose an existing room.";
cin.clear();
cin.ignore();
} else if (room_change == room_current) {
cout << "You're already in that room.";
cin.ignore();
} else {
check = true;
cin.ignore();
}
}
The reason is because we want to get rid of that '\n' so that the cin.fail() does not execute. However, I did find that when you input a character, it will print "Choose an existing room" twice. It will print the first time because a character is not an integer, and a second time because of that '\n'.
The only problem is when I ask the user which room they want to change to, if they enter a blank input, then a message should output saying "You must choose a room."
Using std::getline and then extracting the number from the line using a std::istringstream is a better strategy for that.
std::string line;
std::cout << "Choose an existing room. ";
while ( std::getline(std::cin, line) )
{
// Try to get the room_change using istringstream.
std::istringstream str(line);
if ( str >> room_change )
{
// Successfully read the room.
break;
}
// Problem reading room_change.
// Try again.
std::cout << "Choose an existing room. ";
}
#include <iostream>
using namespace std;
int main(){
int room_change=200;
cout<<"Enter Blank";
cin>>room_change;
if(room_change==NULL){
cout<<"There is NO-THING"<<endl;
}
if(room_change!=NULL){
cout<<"There is something and that is :"<<room_change<<endl;
}
return 0;
}
But a much simpler approach to this would be to use Strings. If this is a Homework of sort and you are limited to Integer variable only. Its much more complicated if you want to detect if an Buffer is empty or not. Regardless of homework limitation, the OS layer input is String based. How can I use cin.get() to detect an empty user input?

If the user enter "q", program quits

I have this C++ code and I am trying to do the following:
Prompt the user to enter "p" to play or "q" to quit, if the user enters anything "p" the program will continue, if the user enters "q" program would just terminate and if they entered an invalid input, it would also terminate. How do I do that?.
Thank you,
Here is the code:
#include <iostream>
#include <cstdio>
#include <cmath>
using namespace std;
int Umain = 0;
double Atemp = 0;
double Utemp = 0;
double Working = 0;
double Total = 0;
char Answer = 'x';
void displayOverview ();
void playOrQuit();
void promptNumber();
int main(){
displayOverview();
playOrQuit();
promptNumber();
return 0;
}
void displayOverview(){
}
void playOrQuit(){
string playOrNot;
cout << "If you want to play please press 'p' for play, and 'q' if you wish to quit\n";
cin >> playOrNot;
if(playOrNot == "p"){
cout << "Awesome, lets start playing !!! \n";
}if(playOrNot == "q"){
cout << "Alright then, see you soon !!\n";
}
}
void promptNumber(){
do{
cout << "Please Enter numbers between 1 and 12: ";
cin >> Umain;
cout << "\n";
for (Utemp = Umain; Utemp > 0; Utemp--)
{
cout << "Please enter a number: ";
cin >> Atemp;
Working = (Working + Atemp);
}
}while (Answer == 'y');
}
Just add a call to exit after you detect 'q' was pressed:
}if(playOrNot == "q"){
cout << "Alright then, see you soon !!\n";
exit(0); // <=== Add this here
Exiting with a 0 traditionally means the program exited in an expected fashion and without any errors.
The usual way to do this kind of thing is to have PlayOrQuit return a bool with true meaning "keep on playing" and false meaning "quit". Use that function to control a loop:
while (PlayOrQuit()) {
// game logic goes here
}
That way you can put any appropriate cleanup code after the game loop instead of having a brute-force exit from down inside the function.
There are a couple of ways you can achieve this.
But I suggest you include the stdlib.h library and use system("exit") right inside your else statements that is meant to exit the program.
Add end(), return 0 or exit(0).
Use u brain like, if you need this then i will remember nearest possible thing you spot from past.
So you never made these kind of mistake.
}if(playOrNot == "q"){
cout << "Alright then, see you soon !!\n";
exit(0);
}

Safe [Y/N]; [1/2/3/etc.] function

I tried to make a an introduction to a "game", and in its functions I made some Yes/No, 1/2/3, situations.
Im new to this however it wasn't that difficult, worked perfectly. The problem appeared when handling with invalid inputs. So this is what the code looks like by now:
#include "Introduction.h"
#include "GameConstants.h"
#include "PlayerCharacter.h"
#include <iostream>
#include <windows.h>
using namespace std;
Introduction::Introduction()
{
}
/////////Function N.1///////////
void Introduction::presentation()
{
char confirm;
string enteredName;
cout << constants.line() << "Welcome traveler! What is the name?" << endl;
getline(cin,enteredName);// Gets the WHOLE LINE as the name.
while (confirm != 'Y') //If the player doesn't confirm the name with 'Y' in will run again until it does.
{
cout << constants.xline() << "Your name is " << enteredName << " right? (Y/N)" << endl;
cin >> confirm; //The player's answer
cin.sync(); //Only takes the first character
confirm = toupper(confirm); //Turns player message into CAPS for easier detection in the "if" statements
if (confirm == 'N'){ //If not the correct name, gives another chance
cout << constants.xline() << "Please, tell me your name again..." << endl;
cin >> enteredName;
cin.sync();}
if ((confirm != 'Y')&&(confirm != 'N')){ //If an invalid input is entered, gives another chance. And insults you.
cout << constants.xline() << "Fool Go ahead, just enter your name again." << endl;
cin >> enteredName;
cin.sync();}
}
if (confirm == 'Y'){ //When the answer is yes ('Y') /* Uneeded line */
PC.setName(enteredName); //Saves the name
cout << constants.xline() << "Excellent! I have a few more questions for you " << PC.name() << "..." << endl;
}
}
//////////Function N.2///////////
void Introduction::difSelection(){
int selectedDif = 0; //Variable to store selected difficulty whitin this function.
Sleep(2500);
cout << constants.xline() << "What kind of adventure do you want to take part in?" << endl;
Sleep(2500); //Wait 2,5 s
cout << "\n1= Easy\n2= Normal\n3= Hard" << endl;
while(selectedDif != 1&&2&&3){ //Selected option must be 1/2/3 or will run again
cin >> selectedDif; //Sets the user selected difficulty
cin.sync(); //Gets only first character
if((selectedDif != 1||2||3)&&(!(selectedDif))){ //If the input isn't 1/2/3 AND is an invalid character, this will run. And it'll start again
cout << constants.xline() << "Criminal scum. Go again." << endl;
cin.clear();
cin.ignore();
}
if(selectedDif != 1&&2&&3){ //If selected option isn't 1/2/3, this will run and will loop again. However I know this conflicts with the previous statement since this will run anyways.
cout << constants.xline() << "Wrong input, please try again." << endl;
}
else if(selectedDif == 1){
constants.setDiff(1);
constants.setStatPoints(15);
} else if(selectedDif == 2){
constants.setDiff(2);
constants.setStatPoints(10);
} else if (selectedDif == 3){
constants.setDiff(3);
constants.setStatPoints(5);}
}
}
The first function works perfectly you can type "aaa" or "a a a" and will work. However I'd like to know if there's a simpler way to do it. (Understandable for a beginner, just started 3 days ago lol; if it includes some advanced or less known code prefer to stay like this by now).
Now, the second one, I really have no idea how to fix it. I need something that if the user's input was an invalid character type, throw certain message, and if it's an int type, but out of the range, another message. And of course, run again if it fails. Did a lot of search and couldn't find anything that meet this requirements.
To check if the user input is an int, you could use the good() function.
int val;
cin >> val;
if( cin.good() ) {
// user input was a valid int
} else {
// otherwise
}
As for the range check, the syntax is a bit different.
This returns true if the number is not equal to 1 nor 2 nor 3:
selectedDif != 1 && selectedDif != 2 && selectedDif != 3
Another shorter way would be to use:
selectedDif < 1 || selectedDif > 3
Another thing, in c++, there are two keywords break and continue which will allow to reduce the code in the loops.