Trying to figure out how to properly break these nested loops - c++

It's a simple game, where there are 23 sticks and you and the computer can remove 1, 2, or 3 and whoever removes the last one loses. It's, as you likely imagined, a project for a class.
The full code is here.
#include <iostream>
#include <cstdlib>
using namespace std;
int main()
{
char playAgain = 'Y';
int totalSticks = 23;
int humanStickChoice = 1;
cout<<"**************************** RULES: Remove 1, 2, or 3 sticks per turn.\n";
cout<<"*Welcome to our Game of 23!* The player who removes the very last stick\n";
cout<<"**************************** loses. Good luck!\n";
cout<<endl;
while (totalSticks > 0 && playAgain == 'Y' || playAgain == 'y')
{
cout<<"There are "<<totalSticks<<" sticks left. How many sticks would you like to remove?:\n";
cin>>humanStickChoice;
cout<<endl;
if(totalSticks >= 3){
if(humanStickChoice != 1 && humanStickChoice != 2 && humanStickChoice != 3){
while(humanStickChoice != 1 && humanStickChoice != 2 && humanStickChoice != 3){
cout<<"Invalid choice; you can remove 1, 2, or 3 sticks. Choose again:\n";
cin>>humanStickChoice;
}
}
totalSticks=totalSticks-humanStickChoice;
cout<<"Player removes "<<humanStickChoice<<" sticks.\n";
}
else if(totalSticks == 3){
if(humanStickChoice != 1 && humanStickChoice != 2){
while(humanStickChoice != 1 && humanStickChoice != 2){
cout<<"Invalid choice; you can remove 1 or 2 sticks. Choose again:\n";
cin>>humanStickChoice;
}
}
}
else if(totalSticks == 2){
if(humanStickChoice != 1){
while(humanStickChoice != 1){
cout<<"Invalid choice; as there are 2 sticks remaining, you can remove only one.\n";
cin>>humanStickChoice;
}
}
totalSticks=totalSticks-humanStickChoice;
cout<<"Player removes "<<humanStickChoice<<" sticks.\n";
}
else if(totalSticks == 1){
if(humanStickChoice != 1){
while(humanStickChoice != 1){
cout<<"Invalid choice; as there is 1 stick remaining, you can remove only one.\n";
cin>>humanStickChoice;
}
}
int humanStickChoice = 1;
cout<<"Player removes "<<humanStickChoice<<" stick.\n";
totalSticks=totalSticks-humanStickChoice;
cout<<"*************************************************\n";
cout<<"Player removed the last stick! Computer wins!";
if(totalSticks == 0){
cout<<endl<<"Would you like to play again? If so, input Y and hit return.\n";
cin>>playAgain;
totalSticks = 23;
}
}
//This block above is where the logic error is occurring; instead of going back to the
//beginning of the "main" while loop and starting over with the human player starting,
//the totalSticks count is merely replenished and the program continues to go on with the
//computer making the first move; the human is supposed to make the first move every game.
if(totalSticks > 4){
int computerStickChoice = (4-humanStickChoice);
cout<<"Computer removes "<<computerStickChoice<<" sticks.\n";
totalSticks=totalSticks-computerStickChoice;
}
else if(totalSticks == 4){
int computerStickChoice = 3;
cout<<"Computer removes "<<computerStickChoice<<" sticks.\n";
totalSticks=totalSticks-computerStickChoice;
}
else if(totalSticks == 3){
int computerStickChoice = 2;
cout<<"Computer removes "<<computerStickChoice<<" sticks.\n";
totalSticks=totalSticks-computerStickChoice;
}
else if(totalSticks == 2){
int computerStickChoice = 1;
cout<<"Computer removes "<<computerStickChoice<<" stick.\n";
totalSticks=totalSticks-computerStickChoice;
}
else if(totalSticks == 1){
int computerStickChoice = 1;
cout<<"Computer removes "<<computerStickChoice<<" stick.\n";
totalSticks=totalSticks-computerStickChoice;
cout<<"*************************************************\n";
cout<<"Computer removed the last stick! You win!";
if(totalSticks == 0){
cout<<endl<<"Would you like to play again? If so, input Y and hit return.\n";
cin>>playAgain;
totalSticks = 23;
}
}
}
return 0;
}
The section causing the error:
else if(totalSticks == 1){
if(humanStickChoice != 1){
while(humanStickChoice != 1){
cout<<"Invalid choice; as there is 1 stick remaining, you can ";
"remove only one.\n";
cin>>humanStickChoice;
}
}
int humanStickChoice = 1;
cout<<"Player removes "<<humanStickChoice<<" stick.\n";
totalSticks=totalSticks-humanStickChoice;
cout<<"*************************************************\n";
cout<<"Player removed the last stick! Computer wins!";
if(totalSticks == 0){
cout<<endl<<"Would you like to play again? If so, input Y and hit
return.\n";
cin>>playAgain;
totalSticks = 23;
}
}
I've debugged every scenario (I think) where these nested loops could break except for one which I can't figure out.
I've added comment lines above it to explain but I'll explain here as well; when the player loses in the last else-if block, the # of sticks are replenished and there is a cin-input to ask the user if they want to play another game. It's supposed to start over and have them play the first move, but, it's just continuing down the code and having the computer make the first move.
How do I have the human make the first move again?
I tried using break; and messing with the "main" while loop requirements but I can't get it right.

Use continue to skip the rest of the loop body and go immediately to the next iteration.
Use break to exit the loop completely. So the final test should be:
if(totalSticks == 0){
cout<<endl<<"Would you like to play again? If so, input Y and hit
return.\n";
cin>>playAgain;
if (playAgain == 'y' || playAgain == 'Y') {
totalSticks = 23;
continue;
} else {
break;
}
}
With this change, there's also no need to test playAgain in the while condition. The test here handles it completely.

Im short on time so not the most ideal way to do it but here's the code:
humanFirstMove = false;
cout << "There are " << totalSticks << " sticks left. How many sticks would you like to remove?:\n";
cin >> humanStickChoice;
cout << endl;
And
if (totalSticks == 0) {
cout << endl << "Would you like to play again? If
so, input Y and hit return.\n";
cin >> playAgain;
totalSticks = 23;
humanFirstMove = true;
}
Finally
//This block above is where the logic error is
occurring;instead of going back to the
//beginning of the "main" while loop and starting over with the human player starting,
//the totalSticks count is merely replenished and the program continues to go on with the
//computer making the first move; the human is supposed to make the first move every game.
if (!humanFirstMove) {
if (totalSticks > 4) {
int computerStickChoice = (4 - humanStickChoice);
cout << "Computer removes " << computerStickChoice << " sticks.\n";
totalSticks = totalSticks - computerStickChoice;
}
Pretty much just added a boolean

Related

Returning to the loop c++

I'm trying to do a simple game Guess Number and created a while condition to do that, but I want to insert a question to play again if the player type "Y" on the queue or close the window if the player type "N". My way is not working and I didn't find a solution for this problem.
int main()
{
int guess, number;
char again;
srand(time(0));
number = rand() % 1000 + 1;
while (guess != number)
{
std::cout << "Enter the number guess between 1 and 1000: ";
std::cin >> guess;
if (guess < number)
{
std::cout << "Is more than this" << std::endl;
}
else if (guess > number)
{
std::cout << "Is less than this" << std::endl;
}
else if (guess < 1)
{
std::cout << "The value to guess is between 1 and 1000" << std::endl;
}
else if (guess > 1000)
{
std::cout << "The value to guess is between 1 and 1000" << std::endl;
}
else
{
std::cout << "This is the number" << std::endl;
std::cout << "Do want play again? [Y/N ]" << std::endl;
std::cin >> again;
if (again == 'N' || again == 'n')
{
break;
}
else if (again == 'Y' || again == 'y')
{
continue;
}
}
}
When you correctly guess the number, your while condition becomes false and hence the loop exits (i.e. guess becomes equal to number, and hence the condition guess != number is false). Try changing to condition of the while loop.
char again = 'Y';
while (again == 'Y' || again == 'y') { ... }
Starting with some presumably yet unrecognised problem: You won't reach all of your if branches:
if (guess < number)
{ }
else if (guess > number)
{ }
// now if you really get to the following else, guess was neither
// smaller nor greater than number, i. e. is EQUAL!
else if (guess < 1)
{ /* won't ever be entered as number(!) is never < 1 (be aware: guess == number) */ }
else if (guess > 1000)
{ /* won't ever be entered as number is never > 1000 */ }
else
{ }
You can solve in two variants, by moving the unreachable checks either in front of the initial ones:
if (guess < 1)
{ }
else if (guess > 1000)
{ }
else if (guess < number)
{ }
else if (guess > number)
{ }
else
{ }
or into them:
if (guess < number)
{
if (guess < 1)
{ }
else
{ }
}
else if (guess > number)
{
if (guess > 1000)
{ }
else
{ }
}
else
{ }
Now to the actual problem, let's consider the else:
// be aware that guess == number now!
if (again == 'N' || again == 'n')
{
break; // fine so far...
}
else if (again == 'Y' || again == 'y')
{
continue;
// re-enters the loop - be aware that the condition is still checked!!!
}
// and if none of all was entered???
// as is, we'd just go on with the loop body - as this was the last statement,
// though, the loop will be re-entered by checking the condition; i. e. if
// getting here, we do effectively exactly the same as in the second if check
// above...
OK, so you (implicitly) defined a default of 'y'. You then could just simply remove the second if (else if == y) and nothing would change.
However, the loop condition is not true any more (guess == number still applies!). Easiest now: just make an endless loop of:
for(;;)
{
if(again == 'n')
break;
// obsolete, just drop it:
//if(again == 'y')
// continue;
}
I personally, though, would rather have the 'n' as default (so typing 'x', 'q', 'a' all result in exiting as well), so I'd rather have:
for(;;)
{
if(again != 'y' && again != 'Y')
break;
}

Trouble with guessing game

I need to do a Guessing game where the program generates a random number and the user has to guess the number. If the user guesses the number in less than 10 guesses the program congratulates them and lets them know they were under 10 guesses. If they were above 10 guesses then it lets them know it was above 10, etc.
The problem I'm facing is if, for example, the user guesses the number in 3 tries and then decides to play again with a whole new other number, and this time guesses it in 8 tries, instead of still congratulating them because it was under 10 tries, it counts the 3 tries from the previous game. This then leads the program to tell them they were over 10 tries, even though they were not. I don't know how to fix this. The code I've done so far is as follows:
int main()
{
srand(time(0));
int guess;
int number;
char selection = 'y';
int numberOfGuesses=0;
while(selection == 'y' || selection == 'Y')
{
number = rand() % 1000 + 1;
cout << "I have a number between 1 and 1000.\nCan you guess my number?\nPlease type your first guess: ";
cin >>guess;
do
{
if(number > guess)
{
cout << "Too low. Try again: " << endl;
cin >> guess;
numberOfGuesses++;
}
if (number < guess)
{
cout << "Too high. Try again: " << endl;
cin >> guess;
numberOfGuesses++;
}
}
while(number != guess);
if(numberOfGuesses < 9)
{
cout << "You guessed the number in less than 10 guesses!\n Would you like to play again (y or n)?";
cin >> selection;
}
else if(numberOfGuesses > 9)
{
cout << "You guessed the number\n Would you like to play again (y or n)?";
cin >> selection;
}
else if(numberOfGuesses == 9)
{
cout << "You guessed the number.\n Would you like to play again (y or n)?";
cin >> selection;
}
}
return 0;
}
The problem is that you are not resetting the counter.
Just put int numberOfGuesses=0; within the while loop:
while(selection == 'y' || selection == 'Y')
{
int numberOfGuesses=0;
....
}
You need to set numberOfGuesses to 0 before every game. Your program only sets it once when the program first launched.
You are not resetting numberOfGuesses to zero after each round. You can solve the problem using one of couple of methods.
Reset the value of numberOfGuesses to zero at the end of the first while loop.
while(selection == 'y' || selection == 'Y')
{
...
numberOfGuesses = 0;
}
Don't define the variable until the start of that while loop. Define it as the first statement and initialize it zero.
while(selection == 'y' || selection == 'Y')
{
int numberOfGuesses = 0;
...
}

Getline() always takes input

I am capturing video from my webcam and if the user hits the Enter key I take a picture. Then I ask "Is the picture okay?" to user and wait for an input. If he says "No", I keep doing the same thing, until he says "Yes".
But if he says "No", and in the meantime I type something in the terminal, getline() function writes whatever I type into its buffer, and when I ask the question again it goes directly to "invalid input" state.
How do I prevent this?
I have read a lot of questions regarding this and I tried to use cin.ignore() and cin.clear() before/after after I call getline(), but they didn't help.
// Do capturing here
string choice;
int choiceIsOkay = 0;
while (choiceIsOkay == 0)
{
cout << "Is the picture okay? (Y/N): ";
getline(cin, choice);
if ((choice == "Y") || (choice == "y"))
{
choiceIsOkay = 2;
}
else if ((choice == "N") || (choice == "n"))
{
choiceIsOkay = 1;
}
else
{
cout << "\nInvalid input\n";
choiceIsOkay = 0;
}
}
if (choiceIsOkay == 2)
{
runAlgorithm = 1;
break;
}
else choiceIsOkay = 0;
If I understand your issue, if user enters Some Random Text In, your program always jump in "Invalid input" and never stops to wait for users input. Following code should resolve your issue.
#include <iostream>
#include <string>
using namespace std;
int main()
{
int runAlgorithm;
// Do capturing here
int i = 0;
while (i++ < 3)
{
int choiceIsOkay = 0;
string choice;
while (choiceIsOkay == 0)
{
cout << "Is the picture okay? (Y/N): ";
getline(cin, choice);
if ((choice == "Y") || (choice == "y"))
{
choiceIsOkay = 2;
}
else if ((choice == "N") || (choice == "n"))
{
choiceIsOkay = 1;
}
else
{
cout << "nInvalid inputn";
choiceIsOkay = 0;
}
// Ignore to the end of line
cin.clear();
}
}
return 0;
}

C++ Tic Tac Toe Game: My code is doubling my outcome from my loop. What is wrong?

#include <iostream>
#include <cctype>
#include <ctime>
#include "Console.h"
using namespace System;
using namespace std;
int main()
{
// Console::SetCursorPosition(10,10 );
const int Rows = 3, Cols = 3;
char gameBoard[Rows][Cols]{
};
do
{
Console::Clear();
for (size_t row = 0; row < Rows; row++)
{
Console::SetCursorPosition(30, 10 + row);
for (size_t col = 0; col < Cols; col++)
{
cout << "|" << gameBoard[row][col];
}
cout << '|';
cout << "\n";
}
int rowInput;
int colInput;
Console::SetCursorPosition(28, 15);
cout << "Row (0 -> 2): ";
cin >> rowInput;
if (cin.fail() == true)
{
cin.clear();
cin.ignore(INT_MAX, '\n');
}
else if (rowInput <= 0 || rowInput >= 3)
break;
Console::SetCursorPosition(28, 16);
cout << "Col (0 -> 2): ";
cin >> colInput;
do
{
if (gameBoard[rowInput][colInput] == 'X' || gameBoard[rowInput][colInput] == 'O'){
cout << "That is already taken";
cin.clear();
cin.ignore(INT_MAX, '\n');
}
else {
break;
}
} while (true);
gameBoard[rowInput][colInput] = 'X';
// system("pause");
// return 0;
cout << "\n";
} while (true);
system("pause");
return 0;
}
The code that is outputting twice is :
do
{
if (gameBoard[rowInput][colInput] == 'X' || gameBoard[rowInput][colInput] == 'O'){
cout << "That is already taken";
cin.clear();
cin.ignore(INT_MAX, '\n');
}
else {
break;
}
} while (true);
This is part of my Tic Tac Toe game, but I am not sure why it prints out "This is already taken" twice. Any help is appreciated. Also another tip I am looking to receive if anyone can show me is how to make the game pick a random spot for the AI to choose.
You can follow the code through here quite easily. Singlestepping through windows debug should do the trick.
So, we enter our row and column values. Because you don't do cin.ignore after doing cin >> colInput there's still a \n on the input stream.
We check if that part of the board is already filled. Lets assume it is.
We output our message (without a newline at the end, I note)
We clear cin by ignoring everything up until the last \n. cin is now empty.
We reach while (true)
We check to see if that part of the board is already filled. It still is! We haven't changed our location yet!
We output our message (without a newline at the end, I note)
We clear cin by ignoring everything up until the last \n. Because cin is empty, this causes the program to wait until enter is returned.
As you can see, you've got yourself stuck in an infinite loop. That do...while loop needs to be rethought.
do
{
/* 2 and 6 */ if (gameBoard[rowInput][colInput] == 'X' || gameBoard[rowInput][colInput] == 'O'){
/* 3 and 7 */ cout << "That is already taken";
/* 4 and 8 */ cin.clear();
cin.ignore(INT_MAX, '\n');
}
else {
break;
}
/* 5 */ } while (true);
Your loop has several problems, the code:
do
{
if (gameBoard[rowInput][colInput] == 'X' || gameBoard[rowInput][colInput] == 'O'){
cout << "That is already taken";
cin.clear();
cin.ignore(INT_MAX, '\n');
}
else {
break;
}
} while (true);
is equivalent to:
while (gameBoard[rowInput][colInput] == 'X' || gameBoard[rowInput][colInput] == 'O'){
cout << "That is already taken";
cin.clear();
cin.ignore(INT_MAX, '\n');
};
and if you pay attention, the condition gameBoard[rowInput][colInput] == 'X' || gameBoard[rowInput][colInput] == 'O' don't change its status, due to the variables rowInput and colInput are never modified inside the loop.
By the way, I think you don't need that loop at all. Just the code inside:
if (gameBoard[rowInput][colInput] == 'X' || gameBoard[rowInput][colInput] == 'O'){
cout << "That is already taken";
cin.clear();
cin.ignore(INT_MAX, '\n');
}

I can not find the error that causes my array to get corrupted after running the case twice and exiting

Hello everyone i am getting a Run-Time Check Failure #2 - Stack around the variable 'barray2' was corrupted. this happens when i loop twice or more the same case and right when i decide to break the while loop with a e for exit. here is the sample of my code. do i have to clear the array when ever i am done? i try and add a barray[16]={0}; inside the case after it prints but i get a expression error, i got no clue :(
#include<iostream>
#include<iomanip>
#include<array>
using namespace std;
int main()
{
int num(0),k(0);
int barray[16]={0};
int num2(0),k2(0);
int barray2[16]={0};
int choice(2);
int choice2;
char option;
while(choice != -1)
{
cout << "enter a choice from B, O, or e(exit)" <<endl;
cin >> option;
if (option == 'B' || option == 'b')
choice2 = 1;
else if (option == 'O' || option == 'o')
choice2 = 2;
else if (option == 'e')
choice2 = -1;
else
choice2 = 0;
switch(choice2)
{
case 1:
cout<<"please enter integer number to be converted to binary (lessthan 65536) "<<endl;
cin>>num;
while ((num !=0) && (k<=15))
{
barray[k]=num%2;
num=num/2;
k++;
}
for (k=15;k>=0;k--)
{
cout<<barray[k];
if ((k%4)==0)
cout<<" ";
}
cout<<endl;
break;
case 2:
cout<<"please enter integer number to be converted to octal (lessthan 65536) "<<endl;
cin>>num2;
while ((num2 !=0) && (k2<=15))
{
barray2[k2]= num2 % 8;
num2 = num2 / 8;
k2++;
}
for (k2=15; k2>=0; k2--)
{
cout<<barray2[k2];
if ((k2%4)==0)
cout<<" ";
}
cout<<endl;
break;
case -1:
cout << "you entered " << choice2 << endl;
choice = -1;
break;
default:
cout << "try again " << endl;
}
}
}
You do not re-initialize your counters k and k2.
The loops quoted below leave k and k2 set to -1 after they complete. So, on the second pass of your while loop, you write to one index before the array:
for (k=15;k>=0;k--)
{
}
for (k2=15; k2>=0; k2--)
{
//...
}
For clarity, I would initialize k/k2 explicitly before each while loop that uses it:
k = 0;
while ((num !=0) && (k<=15))
{
//...
}
(and likewise for the other loop with k2.)