Infinite do-while loop in c++ - c++

This function displayMenu() is being called in Main under the condition while(menuChoice != Q), but the function itself has an internal infinite loop.
Any help on why the loop in the display menu function is infinite would be great... I think it may be something to do with the do-while structure or the relational operator != working improperly.
FUNCTION DISPLAYMENU:
char displayMenu()
{
// can be useful info during development
cout << "Entered function displayMenu..." << endl;
char whatToDo = '?';
do {
//Display Menu Options
cout <<"Upload a regional sales data file \tU" <<endl;
cout <<"display details (All loaded data) \tA" <<endl;
cout <<"list details for specific Order number \tO" <<endl;
cout <<"display summary by Region \tR" <<endl;
cout <<"display summary by print method \tM" <<endl;
cout <<"Clear all data \tC" <<endl;
cout <<"Quit \tQ" <<endl;
cout <<"\nPlease Enter Your Menu Choice: " <<endl;
cin >> whatToDo;
} while (whatToDo != 'U' ||
whatToDo != 'A' ||
whatToDo != 'O' ||
whatToDo != 'R' ||
whatToDo != 'M' ||
whatToDo != 'C' ||
whatToDo != 'Q');
// can be useful info during development
cout << "Returning " << whatToDo << " from displayMenu..." << endl;
return whatToDo;
} // END function displayMenu()
FUNCTION MAIN
while (menuChoice != 'Q'){
menuChoice = displayMenu();
}

while (whatToDo != 'U' ||
whatToDo != 'A' ||
whatToDo != 'O' ||
whatToDo != 'R' ||
whatToDo != 'M' ||
whatToDo != 'C' ||
whatToDo != 'Q');
No matter what whatToDo is, at least 6 of those conditions are true so you get an infinite loop.
What you want is to keep looping until one of the conditions is false.
You should use something like this instead :
while (whatToDo != 'U' &&
whatToDo != 'A' &&
whatToDo != 'O' &&
whatToDo != 'R' &&
whatToDo != 'M' &&
whatToDo != 'C' &&
whatToDo != 'Q');

This condition can never result in "false", which of course results in an endless while-loop. And it is only part of your ORed condition.
whatToDo != 'U' || whatToDo != 'A'
It would require whatToDo to be at the same time identical to 'U' and to 'A'.
What you probably want is
whatToDo != 'U' && whatToDo != 'A'
"as long as whatToDo is neither A nor U ..." according to the equivalence of
!A && !B
and
!(A || B)
the latter being the more obvious phrasing for "NOR".

Related

why is else if function is not working in rock, paper, scissor?

I was asked to make a simple game of rock, paper, scissors in C++ but it turns out that my else if logic is not working. What do you think went wrong?
cout << "choose your pick..." << endl;
cout << "PRESS [ B ] if BATO(ROCK),[ G ] if GUNTING(SCISSOR) or [ P ] if PAPEL(PAPER) " << endl;
cin >> pick;
cin >> picke;
if ( (pick==picke) || (pick=='b' && picke=='B')
|| (pick=='B' && picke=='b') || (pick=='g' && picke=='G')
|| (pick=='G' && picke=='g') || (pick=='p' && picke=='P'))
{
cout << "SORRY TIE";
}
else if (pick=='p' || 'P' && pic­ke=='b' || 'B')
{
cout << "player 1 paper wins";
}
else if (pick=='b' || 'B' && pic­ke=='g' || 'G')
{
cout << "player 1 rocks wins";
}
else if (pick=='g' || 'G' && pic­ke=='p' || 'P')
{
cout << "player 1 scissor wins";
}
else if (pick=='b' || 'B' && pic­ke=='p' || 'P')
{
cout << "player 2 paper wins";
}
else if (pick=='g' || 'G' && pic­ke=='b' || 'B')
{
cout << "player 2 rocks wins";
}
else if (pick=='p' || 'P' && pic­ke=='g' || 'G')
{
cout << "player 2 scissor wins";
}
return 0;
Comparing like this: pick=='p' || 'P' && pic­ke=='b' || 'B' is pretty much useless. This is because the if statements condition will always be true. Why? Let me explain.
You cannot compare and check if pick contains either 'p' or 'P' like that. It sounds right in words but in C++ it is wrong. This is because in programming terms, it's like "is pick equal to 'p' OR is 'pick' equal to 'P'". You need to tell the compiler that you're checking if "is this equal to this". Not "is this equal to this and this" (like what you have right there).
If you have something like ... || 'p' && ..., it'll always be true, because the value of 'p' is not 0, meaning its true in boolean terms.
So to resolve this, we need to say "is pick equal to 'this'" every time we compare. So it may look like this,
//...
else if ((pick == 'p'|| pick == 'P') && (pic­ke == 'b'|| picke == 'B'))
{
cout << "player 1 paper wins";
}
else if ((pick == 'b'|| pick == 'B') && (pic­ke == 'g'|| picke == 'G'))
//...
Or else you can use tolower or toupper as #mch commented, to convert all the characters to a single case. It'll be easier and more efficient when comparing.
Note: It's better if you use brackets to segment the comparisons because it will not only will be easier to understand, it'll be correct logically too.

How can I better check whether two char variables are in some set of values?

Recently, our professor has requested that we use two char variables (day) to receive the input from the user.
The code below works fine as a check to ensure that either Mo, Tu, We, Th, Fr, Sa, Su are the only two characters which are entered together as a pair. If anything else is received as input, it'll loop and ask the user for valid input.
The input should be case-insensitive, meaning that, for example, "mO" and "tu" are acceptable. It seems like there is a lot of repetition that is happening. Is there a way to clean this up?
cout << "Please enter the day of the week did you made the long distance call (Mo Tu We Th Fr Sa Su): ";
cin >> dayOne >> dayTwo;
while ((dayOne != 'M' && dayOne != 'm' || dayTwo != 'O' && dayTwo != 'o') &&
(dayOne != 'T' && dayOne != 't' || dayTwo != 'U' && dayTwo != 'u') &&
(dayOne != 'W' && dayOne != 'w' || dayTwo != 'e' && dayTwo != 'E') &&
(dayOne != 'T' && dayOne != 't' || dayOne != 'H' && dayTwo != 'h') &&
(dayOne != 'F' && dayOne != 'f' || dayTwo != 'R' && dayTwo != 'r') &&
(dayOne != 'S' && dayOne != 's' || dayTwo != 'A' && dayTwo != 'a') &&
(dayOne != 'S' && dayOne != 's' || dayTwo != 'U' && dayTwo != 'u'))
{
cin.clear();
cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
cout << endl << "You have entered an invalid day. Please re-enter a day in the correct format (Mo Tu We Th Fr Sa Su): ";
cin >> dayOne >> dayTwo;
}
You could write a fold-expression that compares 2 characters to a string:
template<typename ...Days>
bool any_of(char a, char b, Days ...days)
{
return (... || (a == days[0] && b == days[1]));
}
and then use it like this:
while (! any_of(std::tolower(dayOne), std::tolower(dayTwo), "mo", "tu", "we", "th", "fr", "sa", "su"))
// keep asking for input
Here's a demo.
This should satisfy the requirement of using 2 char inputs.
You typically use tolower or toupper to convert your char variable to the correct case first. I like using tolower - it looks marginally better.
dayOne = tolower(dayOne);
dayTwo = tolower(dayTwo);
while (
(dayOne != 'm' || dayTwo != 'o') &&
(dayOne != 't' || dayTwo != 'u') &&
(dayOne != 'w' || dayTwo != 'e') &&
(dayOne != 't' || dayTwo != 'h') &&
(dayOne != 'f' || dayTwo != 'r') &&
(dayOne != 's' || dayTwo != 'a') &&
(dayOne != 's' || dayTwo != 'u'))
{
...
}
You can further change it by using memcmp to compare both characters at once, but I am not sure it would simplify the code.
Another approach that might be worth mention is to organize your data, so that you can use std functions against it (std::find)
// Example program
#include <algorithm>
#include <string>
#include <vector>
#include <iostream>
int main()
{
const std::vector<std::string> days = {
"mo", "tu", "we", "th", "fr", "sa", "su"
};
bool found = false;
while (found == false) {
char dayOne, dayTwo;
std::cout << "Please enter the first letter of the day" << std::endl;
std::cin >> dayOne;
std::cout << "Please enter the second letter of the day" << std::endl;
std::cin >> dayTwo;
std::string fullDay;
fullDay += std::tolower(dayOne);
fullDay += std::tolower(dayTwo);
found = std::find(days.begin(), days.end(), fullDay) != days.end();
std::cout << (found ? "correct day " : "invalid day, please try again ")
<< fullDay
<< std::endl;
}
}
run it here
How about
switch (256 * tolower(dayOne) + tolower(dayTwo))
{
case 256 * 'm' + 'o':
// Monday
case 256 * 't' + 'u':
// Tuesday
}
and so on?
Don't know if you're using/allowed regexes, but I'd solve it like this:
bool isDayOfTheWeek(char a, char b)
{
std::string day({a, b});
std::regex pattern("Mo|Tu|We|Th|Fr|Sa|Su", std::regex_constants::icase);
return std::regex_search(day, pattern);
}
Then simply:
cout << "Please enter the day of the week did you made the long distance call (Mo Tu We Th Fr Sa Su): ";
cin >> dayOne >> dayTwo;
while (!isDayOfTheWeek(dayOne, dayTwo))
{
cin.clear();
cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
cout << endl << "You have entered an invalid day. Please re-enter a day in the correct format (Mo Tu We Th Fr Sa Su): ";
cin >> dayOne >> dayTwo;
}
I would first convert inputs to lowercase, which cuts on the amount of possible combinations. Then I would solve it with a single if-statement per day:
// returns 0-6 for valid days, -1 for invalid ones
int dayOfWeek(char a, char b) {
a = tolower(a); // requires #include <cctype>
b = tolower(b);
if (a == 'm' && b == 'o') return 0;
// 5 more here
if (a == 's' && b == 'u') return 6;
return -1; // date was invalid
}
And then I would use it as #PaulEvans suggested:
cout << "Please enter the day of the week did you made the long distance call (Mo Tu We Th Fr Sa Su): ";
cin >> dayOne >> dayTwo;
int day = -1;
while ((day = dayOfWeek(dayOne, dayTwo)) == -1)
{
cin.clear();
cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
cout << endl << "You have entered an invalid day. Please re-enter a day in the correct format (Mo Tu We Th Fr Sa Su): ";
cin >> dayOne >> dayTwo;
}
// day is 0 for monday, ... 6 for sunday

Do-while Loop Conditional Statement Negation Equivalence

New to the community and programming. I was curious as to why these two logical statements are equivalent in my program. I can't seem to wrap my head around this specific logic at the moment, and I wanted to understand why it works this way.
Initially, I had written the following:
char c;
do {
cin >> c;
cout << "You entered: " << c << "\n";
} while (c != 'Y' || c != 'y' || c != 'N' || c || 'n');
return 0;
}
However, this does not seem to work unless I use &&.
Later, I found out that using or does work, but my negation must be on the outside. These are the two conditionals that confuse me. Why are they logically equivalent?
while (!(c == 'Y' || c == 'y' || c == 'N' || c || 'n')); // Will run until c is the following
while (c !='Y' && c != 'y' && c != 'N' && c != 'n'); // Will also run but without being negated.
These logical expressions in the do-while loops
while (!(c == 'Y' || c == 'y' || c == 'N' || c || 'n')); // Will run until c is the following
while (c == 'Y' && c == 'y' && c == 'N' && c == 'n'); // Will also run but without being negated.
are not equivalent.
The expression
while (!(c == 'Y' || c == 'y' || c == 'N' || c || 'n'));
is equivalent to
while ( c != 'Y' && c != 'y' && c != 'N' && !c && !'n' );
if you have an expression like for example
a == b || c == d
then its negation
!( a == b || c == d )
is equivalent to
!( a == b ) && !( c == d )
and at last to
a != b && c != d
Pay attention to that this do-while loop
char c;
do {
cin >> c;
cout << "You entered: " << c << "\n";
} while (c != 'Y' || c != 'y' || c != 'N' || c || 'n');
does not make sense. For example if the user entered 'N' nevertheless the loop continues its iteration because the first subexpression c != 'Y' evalautes to true.

How to check for a tie game beginner C++ [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
This question appears to be off-topic because it lacks sufficient information to diagnose the problem. Describe your problem in more detail or include a minimal example in the question itself.
Closed 8 years ago.
Improve this question
I am creating a tic-tac-toe program and cannot get the game to accurately check if there is a tie. The tie should be declared when all numbers on the board are filled with 'X' or 'O' & there is no winner.
With the code I have now, every time I run the program it declares there is a tie. Am I placing the function wrong? I think something is wrong INSIDE of the tieGame() boolean.
using namespace std;
char board[9] { //array of characters with number placeholders for chars X and O
'1', '2', '3', '4', '5', '6', '7', '8', '9'
};
bool checkWinner(void) {
bool winner = false;
if // Check for possible winning solutions for X
((board[0] == 'X' && board[1] == 'X' && board[2] == 'X')
||
(board[3] == 'X' && board[4] == 'X' && board[5] == 'X')
||
(board[6] == 'X' && board[7] == 'X' && board[8] == 'X')
||
(board[0] == 'X' && board[4] == 'X' && board[8] == 'X')
||
(board[2] == 'X' && board[4] == 'X' && board[6] == 'X')
||
(board[0] == 'X' && board[3] == 'X' && board[6] == 'X')
||
(board[1] == 'X' && board[4] == 'X' && board[7] == 'X')
||
(board[2] == 'X' && board[5] == 'X' && board[8] == 'X'))
{
winner = 1; // Winner is true if conditions are met
cout << "Player 1 Wins!" << endl;
}
else if // Check for possible winning solutions for O
((board[0] == 'O' && board[1] == 'O' && board[2] == 'O')
||
(board[3] == 'O' && board[4] == 'O' && board[5] == 'O')
||
(board[6] == 'O' && board[7] == 'O' && board[8] == 'O')
||
(board[0] == 'O' && board[4] == 'O' && board[8] == 'O')
||
(board[2] == 'O' && board[4] == 'O' && board[6] == 'O')
||
(board[0] == 'O' && board[3] == 'O' && board[6] == 'O')
||
(board[1] == 'O' && board[4] == 'O' && board[7] == 'O')
||
(board[2] == 'O' && board[5] == 'O' && board[8] == 'O'))
{
winner = 1; // winner is True if conditions are met
cout << "Player 2 Wins!" << endl;
}
return winner; // Is there a winner?
}
bool tieGame() {
bool tiegame = false;
if // check for tie
((board[0] == 'X' || 'O') && (board[1] == 'X' || 'O') && (board[2] == 'X' || 'O')
&&
(board[3] == 'X' || 'O') && (board[4] == 'X' || 'O') && (board[5] == 'X' || 'O')
&&
(board[6] == 'X' || 'O') && (board[7] == 'X' || 'O') && (board[8] == 'X' || 'O'))
{
tiegame = 1;
cout << "The game is a tie! Play again!" << endl;
}
else {
tiegame = 0;
}
return tiegame; // Is the game a tie?
}
void displayBoard(void) { //Displays the game board
int index; // used to access the array
index = 0;
cout << endl;
cout << board[index] << "|" << board[index+1] << "|" << board[index+2] << endl;
cout << "-----" << endl;
cout << board[index+3] << "|" << board[index+4] << "|" << board[index+5] << endl;
cout << "-----" << endl;
cout << board[index+6] << "|" << board[index+7] << "|" << board[index+8] << endl;
}
void tictactoe(void) { //Main function; displays board and inputs player moves
int movePosition; // used to track user input and replace array indexes with the user input
cout << "Player 1 is X, player 2 is O" << endl;
for (int i=0; i < 5; i++) {
if (tieGame() ) {
cout << "Tie game!" << endl;
return;
}
displayBoard(); // Display game board with updated characters
if (checkWinner() ) //if winner is TRUE, return "Winner" and exit game.
{
cout << "Good Game!" << endl;
return;
}
cout << "Player 1, Enter the space number where you would like to place X" << endl;
cin >> movePosition; // Retrieve user input & call it 'movePosition'
while ((board[movePosition - 1] == 'X' || board[movePosition - 1] == 'O')) { //Check to make sure a user has not
cout << "This space is already taken. Please choose an open space." << endl; // attempted to enter a
cin >> movePosition; // value that has already been entered
}
board[movePosition - 1] = 'X';
displayBoard(); // Display game board with updated characters
if (checkWinner() ) //if winner is TRUE, return "Winner" and exit game.
{
cout << "Good Game!" << endl;
return;
}
cout << "Player 2, Enter the space number where you would like to place O" << endl;
cin >> movePosition;
while ((board[movePosition - 1] == 'X' || board[movePosition - 1] == 'O')) {
cout << "This space is already taken. Please choose an open space." << endl;
cin >> movePosition;
}
board[movePosition - 1] = 'O';
}
}
int main (int argc, char *argv[]) {
tictactoe();
}
The conditions like the following are wrong:
(board[0] == 'X' || 'O')
Because of C++ operator precedence and evaluation rules, the compiler understands it as:
(board[0] == 'X') || ('O' != 0)
The second part is, of course, always true, so it always succeeds for every field and therefore for the whole board.
You would need to write it explicitly in two comparisons like this:
(board[0] == 'X' || board[0] == 'O')
For the future, a better solution than a bunch of conditions would be a loop, for example:
bool tieGame()
{
for (int i = 0; i < 9; i++) {
if (board[i] != 'X' && board[i] != 'O') {
// Some field is empty, not a tie
return false;
}
}
// All fields are either 'X' or 'O'
cout << "The game is a tie! Play again!" << endl;
return true;
}
And even more better, as Nenad wrote in his answer, just count the number of free spaces left (or the used fields) -- that's just one variable comparison instead of going through the whole board each time.
You can check if it's a tie by having a counter
int freeSpaces = 9;
Which you will decrement each time players fills an empty slot on board.
Then check
if (freeSpaces == 0 && !winner) tieGame = true;
else tieGame = false;
The expressions of the form (board[0] == 'X' || 'O') always evaluate to true since 'O' is a non-zero value (79 to be exact). As a result, all your checks for tieGame are true. What you want is (board[0] == 'X' || board[0] == 'O').

Input validation not functioning

I am trying to parse input from a file to represent a standard deck of cards (i.e. 2C represents the two of clubs). However, my solution is not working as expected, and is declaring all inputs to be invalid. I can't see any logical errors in my code, so I wanted to get a second opinion. The code is below:
/*
* Determines if the input string is valid.
*
* A string is considered valid if it begins with either a number (2-10)
* or a letter (J/j, Q/q, K/k) to deetermine rank, followed by a letter to
* determine suit (C/c, D/d, H/h, S/s).
*/
bool inputValidator(string cardData)
{
if (cardData.length() == 2) //Input string is two characters long
{
if (cardData[0] < '2' || cardData[0] > '9'
|| cardData[0] != 'J' || cardData[0] != 'j'
|| cardData[0] != 'Q' || cardData[0] != 'q'
|| cardData[0] != 'K' || cardData[0] != 'k'
|| cardData[0] != 'A' || cardData[0] != 'a')
{
cout << "Card with data " << cardData << " has an invalid rank." << endl;
return false;
}
if (cardData[1] != 'C' || cardData[1] != 'c' //Parse suit
|| cardData[1] != 'D' || cardData[1] != 'd'
|| cardData[1] != 'H' || cardData[1] != 'h'
|| cardData[1] != 'S' || cardData[1] != 's')
{
cout << "Card with data " << cardData << " has an invalid suit." << endl;
return false;
}
return true;
}
else if (cardData.length() == 3) //Input string is three characters long
//This occurs only if the number is 10.
{
if (cardData[0] != '1' || cardData[1] != '0') //Parse rank
{
cout << "Card with data " << cardData << " has an invalid rank." << endl;
return false;
}
if (cardData[2] != 'C' || cardData[2] != 'c' //Parse suit
|| cardData[2] != 'D' || cardData[2] != 'd'
|| cardData[2] != 'H' || cardData[2] != 'h'
|| cardData[2] != 'S' || cardData[2] != 's')
{
cout << "Card with data " << cardData << " has an invalid suit." << endl;
return false;
}
return true;
}
return false;
}
If there are any logical flaws (or an inherently better way to do this), I would appreciate being told. Thanks.
You're writing clauses like this:
cardData[2] != 'D' || cardData[2] != 'd'
Which will always be true, as the variable being tested can't be both values at the same time. You probably meant to use && rather than ||.
You could certainly simplify the logic, for example by converting the input to lower or upper case before comparing it.
The problem seems to be in the way you combine your conditions. If I understand your expectation correctly, what you want for the first conditions is this:
if (!(cardData[0] > '2' && cardData[0] < '9')
&& cardData[0] != 'J' && cardData[0] != 'j'
&& cardData[0] != 'Q' && cardData[0] != 'q'
&& cardData[0] != 'K' && cardData[0] != 'k'
&& cardData[0] != 'A' && cardData[0] != 'a')
And what you want for the second condition is this:
if (cardData[1] != 'C' && cardData[1] != 'c' //Parse suit
&& cardData[1] != 'D' && cardData[1] != 'd'
&& cardData[1] != 'H' && cardData[1] != 'h'
&& cardData[1] != 'S' && cardData[1] != 's')
You can simplify the conditions a bit:
And your conditions must be changed to do what you want.
bool inputValidator(string cardData)
{
if (cardData.length() == 2) //Input string is two characters long
{
if (!((cardData[0] >= '2' && cardData[0] <= '9')
|| (cardData[0]|32) == 'j'
|| (cardData[0]|32) == 'q'
|| (cardData[0]|32) == 'k'
|| (cardData[0]|32) == 'a'))
{
cout << "Card with data " << cardData << " has an invalid rank." << endl;
return false;
}
if (!((cardData[1]|32) == 'c' //Parse suit
|| (cardData[1]|32) == 'd'
|| (cardData[1]|32) == 'h'
|| (cardData[1]|32) == 's'))
{
cout << "Card with data " << cardData << " has an invalid suit." << endl;
return false;
}
return true;
}
else if (cardData.length() == 3) //Input string is three characters long
//This occurs only if the number is 10.
{
if (!(cardData[0] == '1' || cardData[1] == '0')) //Parse rank
{
cout << "Card with data " << cardData << " has an invalid rank." << endl;
return false;
}
if (!((cardData[2]|32) == 'C' //Parse suit
|| (cardData[2]|32) == 'd'
|| (cardData[2]|32) == 'h'
|| (cardData[2]|32) == 's'))
{
cout << "Card with data " << cardData << " has an invalid suit." << endl;
return false;
}
return true;
}
return false;
}
The code duplication for the second / third character should also be refactored.
Your logic expression isn't correct, also you are duplicating code, try to simply them to functions.
bool inputValidator(string cardData)
{
if (cardData.length() == 2 && IsValidCard(cardData[0])) //Input string is two characters long
{
return IsValidSuite(cardData[1]);
}
else if(cardData.length() == 3)
{
if (isValidRank(cardData[0]))
{
return IsValidSuite(cardData[2]);
}
}
return false;
}
bool isValidRank(char c)
{
if (c =='0' || c=='1')[
{
return true;
}
return false;
}
bool IsValidCard(char c)
{
if (c > '2' && c < '9')
{
return true;
}
switch(c)
{
case 'J':
case 'j':
case 'Q':
case 'q':
case 'K':
case 'k':
case 'A':
case 'a':
return true;
}
return false;
}
bool IsValidSuite(char c)
{
switch(c)
{
case 'C':
case 'c':
case 'D':
case 'd':
case 'H':
case 'h':
case 'S':
case 's':
return true;
}
return false;
}