Unexpected loop behaviour in c++ - c++

// cai.cpp (Computer Assisted Instruction)
// This program uses random number generation to assist students learn multiplication
#include <iostream>
#include <iomanip>
#include <cstdlib> // contains prototypes for srand and rand
#include <ctime>
#include <cctype>
using namespace std;
int main() {
int question();
string status;
int score{0};
cout << "\nThis program will present you with 10 multiplication problems\n"
<< "enter the correct answer after the prompt\n"
<< "Enter Y for YES and N for NO\n"
<< "Do you want to try a game?";
cin >> status;
while(status == "Y" || status == "y") {
for(int x{0}; x < 11; x++) {
question();
score = score + question();
}
// report total score
cout << "\nTotal score is " << score << " out of 10";
cout << "\nWould you like to play again?";
cin >> status;
if(status == "n" || status == "N") {
break;
}
}
cout << endl;
}
int question() {
string responses();
// use srand to generate the random nmber for the various problems
srand(static_cast<unsigned int> (time(0)));
int number1 = 1 + rand() % 12; // initialize random number
int number2 = 1 + rand() % 12; // initialize random number
int total = number1 * number2;
int response;
int score{0};
cout << "\nWhat is " << number1 << + " times " << + number2 << + " ?";
cin >> response;
while (response != total) { // while answer is wrong, repeat question and wait for response
cout << " \nThat is incorrect, try again: ";
cin >> response;
}
if ( response == total) {
cout << responses();
score++; // increment score after each correct answer
}
return score;
}
string responses() {
string res1 = "Well done, that is correct!\n";
string res2 = "Congratulations, that is very accurate!\n";
string res3 = "Wow!, I'm impressed\n";
string res4 = "You're doing great! Keep up the good work.\n";
srand(static_cast<unsigned int> (time(0)));
int select{1 + rand() % 4};
switch(select) {
case 1: return res1;
break;
case 2: return res2;
break;
case 3: return res3;
break;
case 4: return res4;
break;
default: return " ";
}
}
When I compile and run this program, I expect it to loop only 10 times but it loops more than 10 times, I'm thinking it has to do with the switch statement in the responses function but I do not understand why it should be causing a problem. Any explanation would be greatly appreciated. I have modified the while loop condition in the main function to loop different times but it always loops to display all the possible responses in the switch statement. Screen shot of results attached, I modified the while statement to loop only twice but I still had all my responses showing so it ended up looping 4 times.

expect it to loop only 10 times but it loops more than 10 times
In your loop:
for(int x{0}; x < 11; x++)
x goes from 0 to 10, so it loops 11 times.

A few things to note. Your for loop goes up to < 11, meaning 10. So x from 0 to 10 (inclusive) is actually 11 times. You need to change the condition to < 10, or change x to start at 1.
Second issue, inside the for loop, you are actually calling the question function twice; with the first call's result being ignored. This is why you are getting 4 questions, each answered correctly, but only a score of 2.
Third, not so much an issue, but a bit redundant. At the end of the while loop, you check status == "n" || status == "N", however, this is unnecessary, since the while loop's condition checks for y and Y already.
I've cleaned up your while loop a bit here:
while(status == "Y" || status == "y") {
for(int x = 0; x < 10; ++x) {
score += question();
}
// report total score
cout << "\nTotal score is " << score << " out of 10";
cout << "\nWould you like to play again?";
cin >> status;
}
Unrelated thing to also clean up. You don't need to call srand in the question() function, instead just call it once in main. Also, since this is C++, you can use newer random generators from the <random> header.

Related

C++ program to calculate the factorial of even numbers between 5 and 15

When I run the program for an even number less than 5, It prints out the error message but it also gives me the factorial. I don't want the factorial. Here's the code, how do I correct it?
#include <iostream>
using namespace std;
int main()
{
int number, factorial = 1;
cout << "Enter an even number between 5 & 15 to find it's factorial: ";
cin >> number;
if(number % 2 == 0) {
while(number < 5) {
cout << "Error! Enter an even number greater than five: ";
break;
}
while(number > 15) {
cout << "Error! Enter an even number less than fifteen: ";
break;
}
for(int a = 1; a <= number; a++) {
factorial = factorial * a;
}
cout << "factorial of " << number << " is " << factorial;
}
else {
cout << "Error!Enter an even number between 5 & 15 to find it's "
"factorial: ";
}
return 0;
}
This answer shows some corrections to be in your code and provide a working piece of code.
Corrections:
Not a very good idea to write everything in the main function. Try to follow SOLID principles where S stands for single responsibility. Which tells that functions must be small and do exactly one thing. And in your code, you have defined a very big function which does a lot of things.
Avoid nested loops. In your example, you have an if , inside which you have while, while and inside while you have for. This looks messy and is not readable.
Try to be clear in your expression of code, such that when a person reads they understand the flow of data.
Break is something that comes out of a while loop, but it does not mean it will exit the function. So in your example,
while(number<5){
std::cout<<"Error! Enter an even number greater than five: ";
break;
}
After it comes out of this loop, it will go to the next line which is another while loop and then goes on to calculate the function.
Try to use uniform initialization. Instead of int i = 0 use int i{0}. You can read more about uniform initialization on google.
Try not to use "using namespace std or anything else". Very bad practice.
Working piece of code:
bool check_value(int number){
int range = (number < 5 || number > 15) ? false : true;
int even = (number % 2 == 0) ? true : false;
if(range & even){
return true;
}
else{
std::cout << "Error! Please input even number between 5 & 15\n";
return false;
}}
int main(){
int number,factorial=1;
std::cout<<"Enter an even number between 5 & 15 to find it's factorial: \n";
std::cin >> number;
if(check_value(number)){
for (size_t a{1}; a <= number; a++){
factorial = factorial*a;
}
std::cout<<"factorial of " << number <<" is " << factorial << "\n";
}
return 0;
}
As Karl pointed out in the comments, the break statement will break out of exactly one loop, in this case a while loop, and the code outside of the loop will continue to execute.
Also, as Damien pointed out, you need to use a long long int to compute the factorial since the result can exceed the max size of the int datatype.
You could also reformulate your code to make it more readable, something like this:
#include <iostream>
/* Checks if number is valid and can throw error msg */
bool isValidNumber(int num) {
if(num % 2 != 0 || num < 5 || num > 15) {
std::cout << "Error! The number entered is not valid." << std::endl;
return false;
}
return true;
}
/* Calculates factorial and prints its value */
void calculateFactorial(int num) {
long long int factorial = 1;
for(int a = 1; a <= num; a++) {
factorial = factorial * a;
}
std::cout << "factorial of " << num << " is " << factorial << std::endl;
}
int main()
{
int number;
bool isValid;
do {
std::cout << "Enter an even number between 5 & 15 to find it's factorial: ";
std::cin >> number;
isValid = isValidNumber(number);
if(isValid) {
calculateFactorial(number);
}
} while(!isValid);
return 0;
}
Note: Using using namespace std; is considered bad practice because of the possibility of method collisions between a method or methods in the std namespace and methods of some other nanmespace you might create down the road.

Nested While Loop Runs Once More Than Expected

I am new to C++ (have been using it for around 2 weeks), and right now I am trying to write a program that will roll a dice and give a random number between 1 and 6, then count how many rolls it takes to get a 6. After that, it will ask user if they want to continue with a positive and exit with 0.
If the input here is 0, then show the average rolls to get a 6 and the number of 6 occurrences that the average was based on, and all of this using do-while and/or while loops.
The problem is, whenever I press 0, the program seems to run the inner loop one more time before exiting and showing the averages.
#include <iostream>
#include <ctime>
#include <cstdlib>
using namespace std;
int main()
{
float number_rolls, number_sixes;
int x;
number_rolls = 0; // store the number of rolls made
number_sixes = 0; // store the number of sixes
x = 0;
srand(time(0));//initialise random num generator using time
int roll = 0;//declare a variable to keep store the random number
do
{
cout << "possitive to continue, 0 to exit" << endl;
cin >> x;
do
{
roll = rand() % 6 + 1; //generate a random number between 1 and 6
number_rolls = number_rolls++; // add the rolls to a counter
cout << roll << endl; // out put the roll values
} while (roll != 6);
number_sixes = number_sixes++; // adds the sixes to a counter
} while (x != 0);
cout << "average rolls to get a six: " << number_rolls / number_sixes << " you took; " << number_rolls << "rolls and got: " << number_sixes << " sixes" << endl;
Can somebody please help point me in the right direction?
After reading the value of x, you can compare it to 0 and break out of the loop immediately:
do {
cout << "possitive to continue, 0 to exit" << endl;
cin >> x;
// Add this check
if (x == 0)
break; // if this is reached, the inner `do-while` is not executed
do {
// ...
} while (roll != 6);
number_sixes = number_sixes++; // adds the sixes to a counter
} while (x != 0);
Now this makes the check in the outer while is unnecessary, and you can convert the do-while to a while loop with a true condition:
while (true) {
cout << "possitive to continue, 0 to exit" << endl;
cin >> x;
if (x == 0)
break; // if this is reached, the inner `do-while` is not executed
do {
// ...
} while (roll != 6);
number_sixes = number_sixes++; // adds the sixes to a counter
}

Guessing game where computer generates random number

I am implementing a Guessing game where computer generates random number with the following code:
int main()
{
srand(time(NULL));
while (true){
int num = rand() % 10, guess, tries = 0;
while (true){
cout << "Enter number 1 to 10:";
cin >> guess;
if (tries > 2)
{
break;
}
if (guess > num)
{
cout << "Too High ! Try again"<<endl;
}
if (guess > 10)
{
cout << "Error ReEnter 1 to 10\n";
}
else if (guess < num)
{
cout << "Too Low! Try again"<<endl;
}
else
{
break;
}
tries++;
}
if (tries > 2)
{
cout <<"\nYou ran out of tries!\n";
cout << "\nThe answer is:" << num << endl;
}
else
{
cout << "\nCONGRATZ!! You guess correctly!\n";
}
return 0;
}
}
One of the problems is: yet when user attempt 3 times, the program shows "ran out of tries" even though the user input is correct on 3rd try.
Questions:
1.How do I inform user that their input exceeds 10 and show an error message to user to enter values from 1 to 10 ?
2.How to correct the aforementioned problem?
instead of writing the program for you here is some pseudo code.
get a random number rand()%10+1 1..10 call it R
loop
get user input N
if N == R then show OK and break loop
if N < R show too low
else show too high
increment tries
if tries == 3 then break loop
end loop
You have too many if else conditions that make your code unnecessarily complex, to answer your second question specifically the unwanted behaviour is caused from the:
if (tries > 2)
{
break;
}
which exits the loop regardless of the guess, as it is dependant only on the number of tries. Regarding your first question, I decided to provide you with more simple implementation that includes an answer to it as well.
You could replace your while loop with a do-while loop, terminated when the random number is guessed, i.e.:
int main(){
// initialize random seed
srand (time(NULL));
// generate a random number within [1,10]
int secretRandom = rand() % 10 + 1;
// initialize
int yourGuess = 11;
// input loop
string promptMessage = "Type a a number from 1 to 10."
do{
cout << promptMessage << '\n';
// read input
cin >> yourGuess >> endl;
// guessed number relatively to the randomly generated
if (secretRandom < yourGuess) cout << "The secret number is lower\n";
else if (secretRandom > yourGuess) cout << "The secret number is higher\n";
}while(yourGuess != secretRandom)
// if you guess the random number exit the loop and display success message
cout << "You guessed right!\n";
return 0;
}
To reduce the amount of guesses to specific number you can enclose the do-while loop and the success message in a for loop, for example:
int numberOfGuesses = 3;
for (int i = 0; i <= numberOfGuesses; ++i){
//...
}
If you want to enforce the user to input a number in the range from 1 to 10, you could do it by:
int yourGuess = 11;
int lowerBound = 0;
int upperBound = 10;
do{
cin >> yourGuess;
// not type safe
}while(yourGuess < lowerBound || yourGuess > upperBound);

"Prime or not" program

I am stuck on this really simple program in C++, where I let the user know the number she/he have entered is prime or not, but, because of some reason, everything works fine during the first loop but things go fishy during the second. I would be more than happy if anyone could help ?
#include <iostream>
using namespace std;
int main(int argc, const char* argv[])
{
int number1 = 5;
int number;
int a = 0;
while (number1 == 5)
{
int b = 1;
cout << "Enter your number and we'll tell you if it's prime or not: ";
cin >> number;
while (a <= number)
{
a++;
if (number % a == 0)
b++;
}
if (b == 3)
cout << "Your number is prime" << endl;
else
cout << "Your number is not prime" << endl;
}
}
The are several problems with your program.
The first one is that the loop starting with statement
while (number1 == 5)
is infinite because number1 is not changed within the loop.
The second one is that you must always initialize variable a to zero within the loop. And it should be defined also within the loop because it is not used outside the loop. The same is valid for variable number.
Take into account that a number is prime if it is divisble by 1 and itself (except number 1). So I would initially set variable b to zero and compare it with 2. It is more clear than to compare it with 3.
The program can look the following way
#include <iostream>
int main()
{
while ( true )
{
std::cout << "Enter your number and we'll tell you if it's prime or not (0-exit): ";
unsigned int number = 0;
std::cin >> number;
if ( number == 0 ) break;
unsigned int n = 0;
unsigned int divisor = 0;
while ( divisor++ < number )
{
if ( number % divisor == 0 ) n++;
}
if ( n == 2 )
std::cout << "Your number is prime" << std::endl;
else
std::cout << "Your number is not prime" << std::endl;
}
}
You missed to reinit a to 0 before the inner while.
This makes it work. However, I suggest you take time to learn to code. It does not look educated.
Also your program won't exit. Not sure what your intention is, but you could omit the number1 variable and simply use while(1) (considering your code stands as is; probably you are at the beginning of your development though, so it depends).
#include <iostream>
using namespace std;
int main(int argc, const char* argv[])
{
int number1 = 5;
int number;
int a = 0;
while (number1 == 5)
{
int b = 1;
cout << "Enter your number and we'll tell you if it's prime or not: ";
cin >> number;
a = 0; <-- Reset to 0 would make it work
while (a <= number)
{
a++;
if (number % a == 0)
b++;
}
if (b == 3)
cout << "Your number is prime" << endl;
else
cout << "Your number is not prime" << endl;
}
}
P.S.: You are new to StackOverflow. So you likely take the answer and get away. Please consider accepting the answer. It's a respectful practice when it solved your issue.

while loop acting up... not doing what it should for some reason

I have this code for a simple Dice throwing program with betting units and everything... you bet, if you get it right you get the amount u bet times the amount of dice you chose... if you're wrong but by a little (in the range of the number you picked +- the number of dice u picked) you don't lose anything, and if you're really off you lose...
I have a while loop that basically keeps 2 things in mind: as long as the user either has BUs or if they didn't type "no" or "No" for the try again... but for some reason it just doesn't work... lol. any ideas why? the betting system works, it recognizes that betting.currentBU == 0, but the while loop just won't react lol.
#include <iostream>
#include <string>
#include <cstdlib>
#include <time.h>
#include <limits>
using namespace std;
struct Dices{ // structure containing all the dice related integers
int dice;
int total;
int choice;
} Dices = {0,0,0};
struct betting{ // structure containing all the betting integers
int currentBU;
int bettedBU;
} betting = {100, 0};
int DiceThrow(int dicechoice, int totalnum){ // a method for the dice being rolled
for(int i=1; i <= dicechoice;i++){
totalnum = totalnum + (rand() % 6 + 1); //total number, repeated by the loop for every dice
}
return totalnum;
}
int winningbet(int dicea, int cBU, int bBU){ // in case the user guesses it right
std::cout << "Congratulations, you got it right! \n";
cBU = cBU + (dicea * bBU); // give him money...
return(cBU);
}
int losingbet(int dicen, int totaln, int choicen, int cBU2, int bBU2){ //in case the user guesses wrong
if(choicen > (totaln+dicen) || choicen < (totaln+dicen)) // checks how wrong he is, if he's too off, he loses BUs
cBU2 = cBU2-bBU2;
else
std::cout << "you we're so close, you don't lose any BUs! \n"; //if he was really close, just let him know he was close
return(cBU2);
}
int main(){
string decision; // decision if they want to keep playing or not
srand ( (unsigned int)time(NULL) );
while(decision != "no" || decision != "No" || betting.currentBU != 0) // makes sure of the decision AND that he still has BUs
{
Dices.total = 0;
std::cout << "how many dice would you like to use? ";
std::cin >> Dices.dice;
std::cout << "how many How many BUs are you betting?(" << betting.currentBU << " BUs left) ";
std::cin >> betting.bettedBU;
if(betting.bettedBU > betting.currentBU){ // if he doesn't have enough BUs
std::cout << "Sorry, you don't have that many BUs...";
std::cout << "Want to try again with a different amount?(Yes/No) ";
std::cin >> decision;
}
else{
std::cout << "guess what number was thrown: ";
std::cin >> Dices.choice;
Dices.total = DiceThrow(Dices.dice, Dices.total);
if(Dices.choice == Dices.total){
betting.currentBU = winningbet(Dices.dice, betting.currentBU, betting.bettedBU);
std::cout << "Want to try again?(Yes/No) ";
std::cin >> decision;
} else{
std::cout << "Sorry, the number was " << Dices.total << "... better luck next time \n" ;
betting.currentBU = losingbet(Dices.dice, Dices.total, Dices.choice, betting.currentBU, betting.bettedBU);
if(betting.currentBU > 0){
std::cout << "Want to try again?(Yes/No) ";
std::cin >> decision;
}
}
}
}
if(betting.currentBU == 0){
std:cout << "sorry, you ran out of BUs...";
std::cin.ignore( std::numeric_limits<std::streamsize>::max(), '\n' );
}
else{
std::cout << "your final BU count is: " << betting.currentBU << "\n";
std::cout << "Thanks for playing, see you next time! (Press ENTER to terminate...)";
std::cin.ignore( std::numeric_limits<std::streamsize>::max(), '\n' );
}
return 0;
}
isn't it supposed to be:
while(decision != "no" && decision != "No" && betting.currentBU != 0)
We need to check if decision not equal to "no" AND not equal to "No" AND the currentBU not equal to 0
Your test is while (A || B || C), which will loop as long as ANY of those three things are true. Since decision can't be equal to both "no" and "No" at the same time, at least one of those two not-equals tests will always be true, so the loop will loop forever...