This question already has answers here:
Why does rand() yield the same sequence of numbers on every run?
(7 answers)
Closed 5 years ago.
I just finished coding a Minesweeper type game, and everything's good except for that each time I run the application, it generates the same number (I ran it 3 different times, saved the output to 3 text files and used the diff command in Linux, it didn't find any differences). It's seeded by time(NULL) so it should change every time, right?
Here's my code:
main.cpp
#include <iostream>
#include <cstdlib>
#include <time.h>
#include <string>
#include "Minesweeper/box.h"
#include <cstdio>
int main(int argc, char** argv){
using namespace std;
bool gameOver = false;
int x, y, score = 0;
const int HEIGHT = 10;
const int WIDTH = 10;
unsigned int Time = time(0);
cout << "Welcome to Minesweeper. " << endl;
//setup grid
Box grid[10][10];
for(int i = 0; i < WIDTH; i++)
for(int n = 0; n < HEIGHT; n++){
unsigned int value = rand() %100 + 1;
cout << value << endl;
if(value <= 38){
grid[i][n].setFill(MINE);
//cout << i << "," << n << " is mined." << endl;
}
else
grid[i][n].setFill(EMPTY);
}
for(int r = 0; r < WIDTH; r++)
for(int l = 0; l < HEIGHT; l++)
if(grid[r][l].getFill() == EMPTY)
cout << r << "," << l << " - EMPTY." << endl;
else if (grid[r][l].getFill() == MINE)
cout << r << "," << l << " - MINE." << endl;
while(!gameOver){
cout << "Enter coordinates (x,y): ";
scanf("%i,%i",&x,&y);
if(grid[x][y].getFill() == MINE)
gameOver = true;
else{
cout << "Good job! (You chose " << x << "," << y << ")" << endl;
score++;
}
}
cout << "You hit a mine! Game over!" << endl;
cout << "Final score: " << score << endl;
getchar();
return EXIT_SUCCESS;
}
It's seeded by time(NULL)
If it is, I can't see it. In fact, a search for it in your code returns nothing. The default behaviour, if you don't explicitly seed, is the same as if you had seeded it with the value 1.
You need to explicitly state something like:
srand (time (NULL));
at the start of main somewhere (and make sure you do this once and once only).
Though keep in mind this makes it dependent on the current time - if you start multiple jobs in the same second (or whatever your time resolution is), they'll start with the same seed.
From the C standard (on which C++ is based for these compatibility features):
The srand function uses the argument as a seed for a new sequence of pseudo-random numbers to be returned by subsequent calls to rand. If srand is then called with the same seed value, the sequence of pseudo-random numbers shall be repeated. If rand is called before any calls to srand have been made, the same sequence shall be generated as when srand is first called with a seed value of 1.
You need to seed randomizer. Call srand() at the beginning.
To add to the answers by others, you can use the Mersenne Twister Algorithm, which is a part of the C++11 library. Its fast becoming a standard in many common softwares to generate random numbers.
For example, this is the function I wrote, which I use often to generate random numbers in my other codes:
std::vector<double> mersennetwister(const int& My,const int& Mz,
const int& Ny,const int& Nz)
{
int ysize = (My + 2*Ny + 1);
int zsize = (Mz + 2*Nz + 1);
int matsize = ysize*zsize;
unsigned seed = std::chrono::system_clock::now().time_since_epoch().count();
// Seeding the generator with the system time
std::mt19937_64 generator (seed);
// Calling the Mersenne-Twister Generator in C++11
std::uniform_real_distribution<double> distribution(0,1);
// Specifying the type of distribution you want
std::vector<double> randarray(matsize,0);
// Saving random numbers to an array
for (int i=0;i<matsize;++i)
{
randarray[i] = distribution(generator); // Generates random numbers fitting the
// Distribution specified earlier
}
return(randarray);
}
Bottomline: C++11 has some excellent features for numerical operations and it would be a good idea to look into them. As for the Mersenne Twister, http://en.wikipedia.org/wiki/Mersenne_twister
Related
I basically need to make an array and put it in the private member section, and have it work the random number generator. Im not even sure if my teacher is asking for an array to hold the 1000 values, or if I need to make an array for each variable (zero, one, ....). The rubric states to use the private member array to hold the count of values returned from calls to the random generator.
3 hours of youtube videos.
class Gen
{
private:
int Numbergenerated;
public:
Gen();
void set_Numbergenerated(int);
int get_Numbergenerated();
void gener();
void display(int zero, int one, int two, int three, int four, int five, int six, int seven, int eight, int nine);
};
Gen::Gen()....
void Gen::set_Numbergenerated(int n)...
int Gen::get_Numbergenerated()...
void Gen::gener()
{
int result_of_gener;
result_of_gener = rand() % 10;
set_Numbergenerated(result_of_gener);
}
void display....
int main()
{
Gen g;
unsigned seed;
int zero = 0, one = 0, two = 0, three = 0, four = 0, five = 0, six = 0, seven = 0, eight = 0, nine = 0, count, num;
seed = time(0);
srand(seed);
cout << "Press Enter key to begin generating numbers" << endl;
cin.get();
for (count = 0; count <= 1000; count++)
{
g.gener();
num = g.get_Numbergenerated();
cout << "Generation " << "+" << count << ":\t" << "Number generated: " << num << endl;
switch (num)
{
case 0: zero++;
break;.....
g.display(zero, one, two, three,four,five, six, seven, eight, nine);
`````````````
*******spots with ...... placed to save space, probably unimportant parts.
Once you fill the array with 1000 elements, you can use the count function to determine the number of occurrences of a specific value in the array. Here is how.
So, assuming you are using C++ arrays, we can declare the array in the private section of your class:
// An array of ints, with 1000 elements.
std::array<int,1000> randomNumberArray;
We can assume your set_Numbergenerated function adds a new random number to the array, so, in main(), we can generate and insert 1000 random numbers:
/** Generate 1000 random numbers to fill the array. */
for (size_t i = 0; i < 1000; i++)
{
g.gener();
}
Since our array is a private member, and not directly accessible from main, we can add a public member function to Gen to access the array for us. We can also tell this method to count the number of occurrences of a specific value in the array (a great C++ algorithm):
// Return the number of occurrences of 'val' in the array.
int Gen::get_Occurrences(int val) {
return std::count(this->randomNumberArray.begin(), this->randomNumberArray.end(), val);
}
Finally, we can call this method for each number of interest (0 through 9), and give the result of each to the display method call in main:
g.display(g.get_Occurrences(0), g.get_Occurrences(1), g.get_Occurrences(2),
g.get_Occurrences(3), g.get_Occurrences(4), g.get_Occurrences(5),
g.get_Occurrences(6), g.get_Occurrences(7), g.get_Occurrences(8), g.get_Occurrences(9));
These and a few other minor edits produced the output:
Press Enter key to begin generating numbers
Occurrences of each number [0 - 9]: 95 87 106 112 107 96 109 104 100 84
The problem is a little ambiguous. I tried to keep as much of your code as I could, but I may have removed parts that were required to be in the assignment.
The numberGenerated is a confusing variable. It seems that the more important thing you are trying to track is the frequencies of each digit. To do this, I created a 10 element vector which is zeroed by the constructor.
Then, as each number is stored into the object, the corresponding bucket in the array is incremented.
Note that the constructor also calls the seed function for the random number generator.
#include <iostream>
#include <random>
#include <string>
#include <vector>
class Gen {
private:
int Numbergenerated;
unsigned seed;
std::vector<int> frequencies;
public:
Gen();
void set_Numbergenerated(int);
int get_Numbergenerated();
void generate_random_number();
void display();
};
Gen::Gen()
{
seed = time(0);
srand(seed);
for (int i = 0; i < 10; i++) {
frequencies
.push_back(0);// create and zero 10 buckets in our frequencies vector
}
}
void Gen::set_Numbergenerated(int n)
{
Numbergenerated = n;
frequencies[n] = frequencies[n] + 1;
}
int Gen::get_Numbergenerated()
{
return Numbergenerated;
}
void Gen::generate_random_number()
{
int result_of_generate;
result_of_generate = rand() % 10;
set_Numbergenerated(result_of_generate);
}
void Gen::display(){
int sum = 0;
for(int i = 0; i < 10; i++) {
std::cout << i << "'s: " << frequencies[i] << " ";
sum += frequencies[i];
}
std::cout << std::endl;
std::cout << "Total generated: " << sum << std::endl;
}
int main()
{
Gen g;
std::cout << "Press Enter key to begin generating numbers" << std::endl;
// std::cin.get();
for (int count = 0; count < 1000; count++) {
g.generate_random_number();
int num = g.get_Numbergenerated();
std::cout << "Generation " << "+" << count << ":\t" << "Number generated: "
<< num << std::endl;
}
g.display();
}
For example, I'm making a guessing game. If the computer guesses too low, I want to send it to this function
int player1::guessLow(int g)
{
return rand() % guess + 1;
}
So that it guesses any number ABOVE what it just guessed. I also want to do the same for when it's too high
int player1::guessHigh(int g)
{
return rand() % guess - 1;
}
Obviously this isn't the correct code but how would I do this? The < and > operators don't work between in front of guess. I'm trying to come up with any random number and help the computer remember so it keeps guessing below or above that number. How would I accomplish this? Is there an algorithm or template that I can use?
UPDATE:
Here is the code
bool checkForWin(int guess, int answer)
{
cout << "You guessed " << guess << ". ";
if (answer == guess)
{
cout << "You're right! You win!" << endl;
return true;
}
else if (answer < guess)
cout << "Your guess is too high." << endl;
else
cout << "Your guess is too low." << endl;
return false;
}
void play(Player &player1, Player &player2)
{
int answer = 0, guess = 0;
answer = rand() % 100;
bool win = false;
while (!win)
{
cout << "Player 1's turn to guess." << endl;
guess = player1.getGuess();
win = checkForWin(guess, answer);
if (win) return;
cout << "Player 2's turn to guess." << endl;
guess = player2.getGuess();
win = checkForWin(guess, answer);
}
}
There are many examples of generating a random number in a given range using the standard C++ facilities. Here is a little thread-safe function to get you a number in a range:
#include <chrono>
#include <iostream>
#include <random>
long random( long min, long max )
{
// Create and initialize our PRNG
thread_local auto seed = std::chrono::system_clock::now().time_since_epoch().count();
thread_local std::ranlux48 prng( seed );
return std::uniform_int_distribution <long> ( min, max )( prng );
}
(If you are only single-threaded, you can replace thread_local with static.)
To get a range only bounded by minimum or maximum, use numeric_limits<> to find the lowest/highest value to bound with:
#include <limits>
int main()
{
std::cout << "Maximum value of 12: " << random( std::numeric_limits <long> ::min(), 12 ) << "\n";
}
Hope this helps.
rand() is part of C++ (at least for now) and is fine for a simple guessing game.
In some cases srand may not be appropriate, for example I might want repetitive behavior and predictability for testing purposes.
For this problem you may wish to use srand otherwise the guessing game gets boring.
You should completely avoid rand in many applications such as cryptography.
But here the issue is more basic. You don't need to keep track of all the numbers which you have guessed. You just have to keep track of minimum and maximum range. Example:
#include <iostream>
#include <ctime>
#include <cstdlib>
using std::cout;
int main()
{
srand((unsigned int)time(NULL));
int guess = rand();
int min = 0;
int max = RAND_MAX;
while(true)
{
int n = min + rand() % (max - min);
//(n goes up to max, not including max)
if(n < guess)
{
min = n + 1;
cout << n << " too low\n";
}
else if (n > guess)
{
max = n;
cout << n << " too high\n";
}
if(min == max)
n = min;
if(n == guess)
{
cout << n << " success\n";
break;
}
}
return 0;
}
Or use this function as suggested in comment, to find a number within a range.
int rand_rang(int min, int max)
{
if(min == max)
return min;
return min + (int)((double)rand() / ((double)RAND_MAX + 1) * (max - min));
}
These are all pseudo random numbers. If you are designing this game for a lottery corporation, then use a secure random number generator which is more difficult to crack. If distribution is very important (physics simulation etc.) then again you want to avoid rand
Doing an exercise to find the mean and mode of a list of numbers input by a user. I have written the program and it works, but I'm wondering if my function 'calcMode' is too large for this program. I've just started looking into functions which is a first attempt. Would it be better to write smaller functions? and if so what parts can I split? Im pretty new to C++ and also looking if I can improve this code. Is there any changes I can make to make this run more efficient?
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
int calcMean(vector<int> numberList)
{
int originNumber = numberList[0];
int nextNumber;
int count = 0;
int highestCount = 0;
int mean = 0;
for (unsigned int i = 0; i <= numberList.size() - 1; i++)
{
nextNumber = numberList[i];
if (nextNumber == originNumber)
count++;
else
{
cout << "The Number " << originNumber << " appears " << count << " times." << endl;
count = 1;
originNumber = nextNumber;
}
}
if (count > highestCount)
{
highestCount = count;
mean = originNumber;
}
cout << "The Number " << originNumber << " appears " << count << " times." << endl;
return mean;
}
int main()
{
vector<int> v;
int userNumber;
cout << "Please type a list of numbers so we can arrange them and find the mean: "<<endl;
while (cin >> userNumber) v.push_back(userNumber);
sort(v.begin(), v.end());
for (int x : v) cout << x << " | ";
cout << endl;
cout<<calcMean(v)<<" is the mean"<<endl;
return 0;
}
One thing to watch out for is copying vectors when you don't need to.
The function signature
int calcMode(vector<int> numberList)
means the numberList will get copied.
int calcMode(const & vector<int> numberList)
will avoid the copy. Scott Meyer's Effective C++ talks about this.
As an aside, calling is a numberList is misleading - it isn't a list.
There are a couple of points that are worth being aware of in the for loop:
for (unsigned int i = 0; i <= numberList.size()-1; i++)
First, this might calculate the size() every time. An optimiser might get rid of this for you, but some people will write
for (unsigned int i = 0, size=numberList.size(); i <= size-1; i++)
The size is found once this way, instead of potentially each time.
They might even change the i++ to ++i. There used to a potential overhead here, since the post-increment might involve an extra temporary value
One question - are you *sure this gives the right answer?
The comparison nextNumber == originNumber is looking at the first number to begin with.
Try it with 1, 2, 2.
One final point. If this is general purpose, what happens if the list is empty?
Would it be better to write smaller functions?
Yes, you can make do the same job using std::map<>; which could be
a much appropriate way to count the repetition of the array elements.
Secondly, it would be much safer to know, what is the size of the
array. Therefore I suggest the following:
std::cout << "Enter the size of the array: " << std::endl;
std::cin >> arraySize;
In the calcMode(), you can easily const reference, so that array
will not be copied to the function.
Here is the updated code with above mentioned manner which you can refer:
#include <iostream>
#include <algorithm>
#include <map>
int calcMode(const std::map<int,int>& Map)
{
int currentRepetition = 0;
int mode = 0;
for(const auto& number: Map)
{
std::cout << "The Number " << number.first << " appears " << number.second << " times." << std::endl;
if(currentRepetition < number.second )
{
mode = number.first; // the number
currentRepetition = number.second; // the repetition of the that number
}
}
return mode;
}
int main()
{
int arraySize;
int userNumber;
std::map<int,int> Map;
std::cout << "Enter the size of the array: " << std::endl;
std::cin >> arraySize;
std::cout << "Please type a list of numbers so we can arrange them and find the mean: " << std::endl;
while (arraySize--)
{
std::cin >> userNumber;
Map[userNumber]++;
}
std::cout << calcMode(Map)<<" is the mode" << std::endl;
return 0;
}
Update: After posting this answer, I have found that you have edited your function with mean instead of mode. I really didn't get it.
Regarding mean & mode: I recommend you to read more. Because in general, a data set can have multiple modes and only one mean.
I personally wouldn't split this code up in smaller blocks, only if i'd want to reuse some code in other methods. But just for this method it's more readable like this.
The order of excecution is aroun O(n) for calc which is quite oke if you ask me
For some reason the code I'm about to post below is not purely random... And I have used srand(), to attempt to make it random.. I don't know why it's acting weird...
#include<vector>
#include "../Header Files/SinglePlayer.h"
SinglePlayer::SinglePlayer()
{
}
int myRand(int low, int high)
{
srand(time(NULL));
return rand() % (high - low + 1) + low;
}
void SinglePlayer::startGame()
{
cout << "Starting Single Player........." << endl;
cout << "Starting out with two cards...." << endl;
int randomCardStarterOnePlayer = myRand(0,10);
int randomCardStarterTwoPlayer = myRand(0,10);
int randomCardStarterOneAI = myRand(0,10);
int randomCardStarterTwoAI = myRand(0,10);
this -> calculateRandomStarter(randomCardStarterOnePlayer,
randomCardStarterTwoPlayer,
randomCardStarterOneAI,
randomCardStarterTwoAI);
cout << "You Start out with " << amountPlayer << endl;
cout << "Computer Starts out with " << amountAI << endl;
}
void SinglePlayer::calculateRandomStarter(int randomOnePlayer, int randomTwoPlayer, int randomOneAI, int randomTwoAI)
{
amountPlayer = amountPlayer + randomOnePlayer + randomTwoPlayer;
playerCards.push_back(randomOnePlayer);
playerCards.push_back(randomTwoPlayer);
amountAI = amountAI + randomOneAI + randomTwoAI;
AICards.push_back(randomOneAI);
AICards.push_back(randomTwoAI);
}
SinglePlayer::~SinglePlayer()
{
}
Outcome:
~~~~~~~~~~BLACKJACK~~~~~~~~~~~
Do you want to play single player, or multiplayer? (Enter 0 for single
player, 1 for multiplayer)
0
Starting Single Player.........
Starting out with two cards....
You Start out with 2
Computer Starts out with 2
You can see the player and computer starts with same number.. and that always happens for some reason... I cant seem to spot the problem, please help.
time(NULL) returns time in seconds, and because you set new seed every time you are generating new number you probably (in most cases) set same number as seed every time.
Move:
srand(NULL)
to start of main or somewhere where it will be called only once.
It sounds like time(NULL) in your code returns something that is constant and does not call std::time(NULL) as you may expect. If it did, you would have a random number properly generated from rand().
Try to print the output of time(NULL) and check if you actually get the number of seconds elasped since the epoch. If not, make sure you include <ctime> and call fully qualified srand(std::time(NULL)).
This question already has answers here:
How to generate different random numbers in a loop in C++?
(13 answers)
Closed 7 years ago.
I'm having trouble with a random generator.
I'm trying to print out random values and I'm getting almost the same value every single time.
This is what I have:
void Deck::shuffle() {
StackNode<Card>* top = stack->top;
for (int i = 0; i < stack->numNodes - 1; i++) {
int x = random(i);
StackNode<Card>* temp = findCard(x);
//cout << "Random index was: " << random(i) << endl;
//cout << "Face value of random was: " << temp->data.getFaceVal() << endl;
cout << "Top: " << top->data.getFaceVal() << endl;
cout << "Temp: " << temp->data.getFaceVal() << endl;
swapX(top,temp);
}
}
Here's my random generator function:
int random(int index) {
int r;
srand(time(NULL));
cout << "Index: " << index << endl;
r = rand() % 50;
cout << "Random value: " << r << endl;
return r;
}
I think you can use std::shuffle here for your problem. Like this:
#include <vector>
#include <algorithm>
void Deck::shuffle() {
StackNode<Card>* top = stack->top;
std::vector<StackNode<Card>*> cards;
for (int i = 0; i < stack->numNodes - 1; i++) {
cards.push_back(findCard(i))
}
std::shuffle(cards.begin(), cards.end());
for (auto card : cards) {
std::cout << card->data.getFaceVal() << std::endl;
}
}
By the way, I would recommend you to call srand only once in your code.
rand() is a pseudo random number generator. The numbers it generates appear to be random, but they are generated by a completely deterministic function. The seed that you give it with sand() determines the starting point for the function. If you give it the same seed it will generate the same sequence of random numbers. You can try this and see for your self by seeding with a literal, like srand(200) and running the program several times, you will get the exact same results.
If you want different results each time you have to seed with something that will be different each time the program runs, so time is often used as a seed. In your case you are in a very tight loop so many of the calls in a row use the same time value.
If you call srand() once, before your loop this problem will go away.