Issues with rand and srand - c++

I'm making a program to get the average number of dice rolls to get a 6, but there seems to be an issue with the RNG. I suspect it's the seed, as while the number is different each time I compile and run the code, it doesn't change in each individual attempt, so the average doesn't change. Heres my code:
#include <iostream>
#include <cstdlib> // random numbers header file//
#include <ctime> // used to get date and time information
using namespace std;
int main()
{
int roll = 0; //declare a variable to keep store the random number
int i = 0;
int counter = 0;
int resume = 1;
int average = 0;
int totalrolls = 0;
srand(time(0)); //initialise random num generator using time
while (resume != 0) {
while (roll != 6) {
roll = rand() % 6 + 1; // generate a random number between 1 and 6
i++;
}
counter++;
totalrolls += i;
average = totalrolls / counter;
cout << "the average number of rolls to get a 6 is " << average << ", based on " << counter << " sixes." << endl;
cout << "do you wish to keep rolling? ";
cin >> resume;
cout << endl;
}
return 0;
}
Anyone got any idea what's going on?

Notice that roll only gets updated inside this loop:
while (roll != 6) {
...
}
This means that after that loop finishes running with roll set to 6, it will never run again, even if the outer loop executes another time.
To fix this, you could either
change this to be a do ... while loop so that it always executes at least once; or
manually reset roll to a value other than 6 on each iteration through the outer while loop; or
change where roll is defined so that it's local to the outer while loop and so you get a fresh copy of it per outer loop iteration, which is basically a better version of option (2).

Related

How can I stop C++ program?

I made a program that prompts the user to guess numbers (which I have programmed to produce a random number)ranging from 1-10, if the user guesses the number successfully which is the same as the random number generated it prints "congratulation", else it prompts the user to try again. but I want to stop the user from answering after a certain amount of time(like Game Over). But the prompt keeps coming, I tried using the break in my while loop but it doesn't work, I also tried using the exit function, which actually stopped the program from running but it stopped it after answering 2 times which is not what I want.
#include <iostream>
#include <cmath>
#include <cstdlib>
#include <ctime>
using namespace std;
int main() {
int a,b,c,d,e,f;
// generate a random number, prompt the user for any number if the users guess is in line with the random number generated the user wins else try again
//generate a random number between 1 - 10 store it in a variable
cout << "Random Number Generator \n \n";
srand(time(0));
for(int i = 1; i == 1; i++){
a = 1+(rand() % 10);
cout << a << endl;
}
//prompt the user for numbers ranging from 1 - 10
cout << "type in a number from (1 - 10)\n";
cin >> b;
c++;
//check if the number is the same as the random number
//this checks to see if the user gets the question, else it continues running till he gets it
while(a != b){
cout << "You're incorrect!\n";
cout << "type in a number from (1 - 10)\n";
cin >> b;
while(b <= 3){
exit(3);
}
}
//print result
if(a == b){
cout << "congratulations";
}
return 0;
}
how can I make this work?
You could count the number of times the user answers and stop when it has executed for the number of times you want.
//prompt the user for numbers ranging from 1 - 10
cout << "type in a number from (1 - 10)\n";
cin >> b;
int answer_count = 1; // variable to count answers (there is already 1 answer here)
const int max_attempts = 10; // number of attempts the user has
//check if the number is the same has the random number
//this checks to see if the user gets the question, else it continues running till he gets it
while(a != b){
cout << "You're incorrect!\n";
cout << "type in a number from (1 - 10)\n";
cin >> b;
answer_count++; // count this new answer
if (answer_count >= max_attempts){ // check if the count reached the "certain amount of time"
break; // exit from this loop
}
}
Alternatively, you could also give the user a certain amount of time to guess. For example, 10 seconds. This can easily be achieved using the C++ chrono library:
#include <chrono>
#include <iostream>
#include <random>
int main(int argc, char **argv)
{
const int max_time = 10; // seconds
const int min_secret = 1;
const int max_secret = 10;
// This generates a random number between min_secret and max_secret using the STL random library
std::random_device r;
std::default_random_engine e(r());
std::uniform_int_distribution<int> uniform_dist(min_secret, max_secret);
int secret = uniform_dist(e);
auto start = std::chrono::system_clock::now();
int guess;
do {
std::cout << "Type a number from (1 - 10)\n";
std::cin >> guess;
if (guess == secret)
break;
std::cout << "Your guess is incorrect!\n";
// See if the time elapsed since the start is within max_time
auto now = std::chrono::system_clock::now();
auto elapsed_time = std::chrono::duration_cast<std::chrono::seconds>(now - start);
if (elapsed_time.count() > max_time) {
std::cout << "You ran out of time.\n";
exit(0);
} else {
std::cout << "You still have " << max_time - elapsed_time.count() << " seconds left\n";
}
} while (guess != secret);
std::cout << "Your guess was correct, congratulations!";
}
Note that the time check is only performed after the user tried to guess, so if the time limit is 10 seconds and the user waits 30 to type, it will still allow. To kill the program entirely with a timer in C++, you could use the thread library to spawn a second thread that handles the elapsed time, or even use an interruption based scheme (see https://stackoverflow.com/a/4001261/15284149 for an example of timer).
Also, note that the user input is not sanitized, and if the user writes anything other than a number your program has undefined behavior.
You need to fix up several things in your code:
The variable c is kept uninitialized and incremented later to use nowhere. Remove this. Note that d, e, f are unused as well.
In the loop:
for(int i = 1; i == 1; i++) {
a = 1 + (rand() % 10);
cout << a << endl;
}
You have told the compiler to iterate until i == 1, increment it by one, it is only done once – and that you might not want to do but i < 10.
Also, You are not using an array to store those 10 random numbers, but the last one. You need to make an array of 10 rooms and assign it to each of them:
int a[10];
// Since the array index begins at zero
for (int i = 0; i < 10; i++) {
a[i] = (rand() % 10) + 1;
cout << a[i] << endl;
}
After the successful assignment, it's time to introduce a randomly chosen index as the right answer (it should be put before the while loop):
// To choose the random index
int shuffle = a[rand() % 10];
Also, replace the congratulating statement:
// It was a == b previously
if (shuffle == b)
cout << "congratulations";
Lastly, to quit after three incorrect attempts, replace the while loop:
int count = 0;
while (shuffle != b) {
count++;
cout << "You're incorrect!\n";
cout << "type in a number from (1 - 10)\n";
cin >> b;
if (count == 2) {
cout << "Game Over" << endl;
exit(0);
}
}

c++ srand(time(0)) doesn't work in guessing game

I need to make a guessing game in C++, and everything works except that srand(time(0)) doesn't reset the number after the user wants to play again. I also can't use std libraries.
Nothing I have done has worked so far. Am I doing the while loops wrong?
#include <iostream>
#include <ctime>
using namespace std;
int main()
{
//Initialize variables
int input = 0;
int playing = 1;
char yninput[2];
int count = 1;
//While the player is playing the game
while (playing == 1) {
srand(time(0));
int num = rand() % 101;
//While the player hasn't guessed the number
while (input != num) {
//Prompt the player
cout << "Enter your guess" << endl;
cout << num << endl;
cin >> input;
//If the guess is greater than the number
if (input > num) {
cout << " Your guess is too high!" << endl;
count++;
}
//If the guess is less than the number
else if (input < num) {
cout << " Your guess is too low!" << endl;
count++;
}
//If the player guesses the correct number
else {
cout << " You have guessed the number! It took you " << count << "
guess(es)! Would you like to play again?" << endl;
//Ask the play if they want to play again
cin >> yninput[2];
//If the player doesn't want to play again quit the program
if (yninput[2] == 'n') {
playing = 0;
input = num;
}
//If the player wants to play again restart the program and
randomize the number
else if (yninput[2] == 'y') {
input = 0;
count = 1;
}
}
}
}
}
As #user4581301 has pointed out, you shouldn't call srand(time(0)) more than once, as it will reset the random seed according to the current system time. If srand(time(0)) is called in rapid succession, the very big number that it will take as a seed (which I believe is the current epoch time) will be sufficiently close to the previous call that you might not observe significant difference in your RNG.
Simply moving the srand(time(0)); line out of the while loop should do the trick.
How do I get it so that when the user presses 'y' and the game resets that the random number also changes?
You get the next number in the pseudo random sequence by calling rand without calling srand in between. If you set the random sequence to start from the current timestamp on every iteration, then you get the same number which changes once a second.
I also can't use std libraries.
srand, rand, time, cout and cin are all from the standard library.
I think #Mathis has already pointed out the solution.
I am just sharing some insight as to how srand and rand are related. Consider the below code snippet:
#include <iostream>
#include <ctime>
int main()
{
int i = 0;
// Uncomment below line to generate new set of random numbers
// on every execution.
// srand(time(0));
while (i < 5)
{
std::cout<< rand() % 10 <<std::endl;
}
}
Let's say the program generates numbers - 5, 7, 3, 0 and 4 on 1st run. If you run the program again, you will see the same set of numbers, i.e, 5, 7, 3, 0 and 4. So, although they are random (pseudo random to be precise), but on every program execution, the order of numbers will be same.
This is the reason we use srand to specify some seed value. Seed is any value which is different on each execution. When we use time(0) as parameter to srand, we make sure that on every program execution, we are providing a new and unique seed. This will make sure that we get truly random set of numbers.

c++ sqrt() calculation assistance

So I'm studying c++ from the book ((C++ without fear)). and there's a code I didn't understand. I need to know how the code works. my problem is in the loop, I understand how it works, but I didn't understand how would it work with adding 1 to i. (EVEN WITH COMMENTS).
#include <iostream>
#include <cmath>
using namespace std;
int main() {
int n = 0; // Number to test for prime-ness
int i = 2; // Loop counter
bool is_prime = true; // Boolean flag...
// Assume true for now.
// Get a number from the keyboard.
cout << "Enter a number and press ENTER: ";
cin >> n;
// Test for prime by checking for divisibility
// by all whole numbers from 2 to sqrt(n).
while (i <= sqrt(n)) {
if (n % i == 0) { // If i divides n,
is_prime = false; // n is not prime.
}
++i; // Add 1 to i.
}
// Print results
if (is_prime) {
cout << "Number is prime." << endl;
}
else
{
cout << "Number is not prime." << endl;
}
return 0;
}
Adding 1 to i is simply to move on to test the next number the next time round the loop to test if it divides n. ++i is simply the prefix increment operator being invoked. Postfix i++; could be used here for the same effect, as could i = i + 1;, but since there exist some cases where prefix increment is faster than the alternatives (not the case here) it's usually a good habit to use prefix increment always unless you have a specific reason not to do so.

C++ "While" Loop

I'm struggling to apply a "While" loop to the following problem: Design the logic for a program that allows a user to enter a number. Display the sum of every number from one through the entered number.
Start
int userNumber;
Declarations
int number = 1
while number <= userNumber
++number
endwhile
output number
Stop
I know my code isn't correct as it is just adding one to the initial value until the user's number is reached, thus making the output the user's number. How would I go about adding each subsequent value without writing them out e.g. user's number is 10, so the program would add 1+2+3+4+5+6+7+8+9+10 and output the total of 55?
Thank you!
Here's a tip. You'll want to start at the users number and count down to 0. Like this:
int finalNum = 0;
int userNum;
//This is where you need to get the user's number....
while(userNum > 0)
{
finalNum += userNum;
userNum--;
}
//Do whatever you need to finalNum....
EDIT: It appears you've posted pseudocode; usually a big no-no here unless stated otherwise. It's better to post the actual code as it's easier to tell what exactly is going on.
The function you need could look like this for c++:
#include <iostream>
using namespace std;
void calc(unsigned x)
{
unsigned t = 0; // Assume the result to be 0 (zero)
for (i = 1; i <= x; i++) // Continue until i is greater than x
{
t += i; // Accumulate, i.e. t = t +i
}
cout << "sum=" << t << endl; // Print the result
}
int main()
{
calc(10);
return 0;
}
An alternative is:
#include <iostream>
using namespace std;
void calc(unsigned x)
{
cout << "sum=" << (x*(x+1)/2) << endl; // Print the result
}
int main()
{
calc(10);
return 0;
}
This works because the sum of all integers from 1 to n is n*(n+1)/2

c++ time and random function

I'm trying to create a procedural that draws cards from a deck at random. The problem was that I needed to make the draw procedure actually random, as each draw is the same when using srand and rand when no other factors change. Thus I attached it to time_t seconds and was able to make the draw semi/ random. This is because I have to wait for a second to go by for the parameter of time_t seconds to change. The reason this is a problem is that my program is made to draw again if it draws the same card twice (which it's known to do). Thus if it does draw the same card twice it will be forced to draw around fifteen more times (or more or less) until the time_t second parameter changes. Is there a way to measure milliseconds or an otherwise smaller unit of time for time so I don't have this issue?
Here is the code, though the checking for match and organizing proceedures are not attached (those only occur after the initial draw anyway.)
int allow = 0;
string cards[] =
{"02hearts", "03hearts", "04hearts", "05hearts", "06hearts", "07hearts", "08hearts","09hearts", "10hearts", "11hearts", "12hearts", "13hearts", "14hearts",
"02clubs", "03clubs", "04clubs", "05clubs", "06clubs", "07clubs", "08clubs", "09clubs", "10clubs", "11clubs", "12clubs","13clubs", "14clubs","14clubs",
"02spades", "03spades", "04spades", "05spades", "06spades", "07spades", "08spades", "09spades", "10spades", "11spades", "12spades", "13spades", "14spades",
"02diamonds", "03diamonds", "04diamonds", "05diamonds", "06diamonds", "07diamonds", "08diamonds", "09diamonds", "10diamonds", "11diamonds", "12diamonds", "13diamonds", "14diamonds"};
string cardHand [5];
string cardnumbers [5];
int cardInts [5];
string handSuites [5];
char handSuitesChar [5];
//check deck
while(allow == 0)
{
//set clock
time_t seconds;
time(&seconds);
srand((unsigned int) seconds);
int type;
//initiate counters
int n = 0;
int n1 = 0;
int n2 = 0;
int n3 = 0;
int n4 = 0;
//draw cards
while(n < 5)
{
type = rand() % 52;
cardHand[n] = cards[type];
cout << cardHand[n] << ", ";
n++;
}
cout << endl;
//pull numbers from cards
while(n1 < 5)
{
string character2;
cardnumbers[n1] = cardHand[n1].at(0);
character2 = cardHand[n1].at(1);
cardnumbers[n1].append(character2);
cout << cardnumbers[n1] << ", ";
n1++;
}
cout << endl;
cout << endl;
//convert numbers to ints
while(n2 < 5)
{
stringstream convert(cardnumbers[n2]);
if( !(convert >> cardInts[n2]))
cardInts[n2] = 0;
cout << cardInts[n2] + 100 << ", ";
n2++;
}
cout << endl;
//pull out first letters for suites
while (n3 < 5)
{
handSuites[n3] = cardHand[n3].at(2);
cout << handSuites[n3]<< endl;
n3++;
}
//convert letters to chars
while (n4 < 5)
{
stringstream convert(handSuites[n4]);
if( !(convert >> handSuitesChar[n4]))
handSuitesChar[n4] = 0;
cout << handSuitesChar[n4] + 100 << ", ";
n4++;
}
Don't call srand() inside the loop. Call it once at the start of your program, and then just use rand() whenever you need a random number. That'll give you a fairly long pseudorandom sequence.
As Rob pointed out, the problem isn't with rand(), but with
the way you are drawing the cards. There's no reason to every
draw the same card twice. You can use Rob's suggestion, and
shuffle the deck, or you can pick a random card from an
unshuffled deck, and then remove it from the deck (swap with the
end, then pop_back), so that it can't be drawn again.
And of course, never seed the generator more than once in a
single process.