I am making a small text-based game in c++ called "House Evolution" for fun. The game consists of 'searching under the couch cushions' to gain credits. When you search, the game is supposed to generate a random number anywhere from creditRate-5 to creditRate+5. How would I go about doing this using the rand() function, no matter what number creditRate is? Here is example code:
#include <iostream>
#include <unistd.h>
#include <string>
#include <cstdlib>
#include <math.h>
int main()
{
int creditRate = 30; // Just for example.
int credits;
int searching;
while (1) {
// Yes, I know, infinite loop...
std::cout << "Credits: " << credits << std::endl;
std::cout << "Type any key to search for credits: " << std::endl;
std::cout << "Searching...\n";
usleep(10000000); // Wait 10 seconds
searching = rand(?????????); // Searching should be creditRate-5 to creditRate+5
std::cout << "You found " << searching<< " credits\n";
credits += searching;
}
}
The way I would go about it is using rand % 11, to get a range of 11 numbers and then adding it to credit rate -5 to cover the range from creditrate-5 to creditrate+5.
So:
searching = rand() % 11 + creditRate - 5;
Try:
searching = rand() % 11 + creditRate-5; That's because your range is 11 (remember, there are 11 numbers from -5 to 5, for example) and the lower limit is creditRate-5.
Use the <random> header instead of rand(), because <random> provides facilities to generate these distributions correctly instead of making you do it yourself.
#include <iostream>
#include <thread>
#include <random>
int main()
{
int creditRate = 30; // Just for example.
// Searching should be creditRate-5 to creditRate+5
std::uniform_int_distribution<> random_credit_amount(creditRate - 5, creditRate + 5);
int credits = 0;
// arrange a source of randomness
std::random_device r;
std::seed_seq seed{r(),r(),r(),r(),r(),r()};
std::mt19937 pRNG(seed);
while (true) {
// Yes, I know, infinite loop...
std::cout << "Credits: " << credits << '\n';
std::cout << "Type any key to search for credits: " << '\n';
std::cout << "Searching...\n";
std::this_thread::sleep_for(std::chrono::seconds(10)); // Wait 10 seconds
int searching = random_credit_amount(pRNG);
std::cout << "You found " << searching<< " credits\n";
credits += searching;
}
}
<random> even provides more advanced options than the typical uniform distribution. For example, instead of having every values from creditRate - 5 to creditRate + 5 be equally likely, you could have values closer to creditRate be more likely than values further away, using a 'normal' (a.k.a. 'bell curve') distribution:
// credits found should be near creditRate
std::normal_distribution<> random_credit_amount(creditRate, 5);
and then in the loop:
int searching = std::round(random_credit_amount(eng));
(You don't have to change the code in the loop at all, but it skews the distribution a bit. Performing proper rounding avoids the skew.)
Notice another change I made, replacing the non-standard usleep with the standard this_thread::sleep_for. Notice that this code makes the comment entirely redundant:
std::this_thread::sleep_for(std::chrono::seconds(10)); // Wait 10 seconds
And one can just as easily ask for sleep durations of microseconds or hours
std::this_thread::sleep_for(std::chrono::hours(2));
std::this_thread::sleep_for(std::chrono::microseconds(50));
Related
This question already has answers here:
Random numbers based on a probability
(3 answers)
Closed last month.
I wonder how one would go about coding weighted random in C++—having a random outcome but where you can control the outcome percentage of each result. I have searched the web but have yet to find anything but the Javascript version.
I want to program a question game, which I have programmed in python previously without being able to controll the percentages. Still, I want to transfer the program to C++ as there is more controllability. The program would have a list of questions; currently, the python version has just multiplication table questions, but I would like to have other genres of questions once I get this weighted random figured out. So far, I have been able to get the python code to stop asking a question that was correctly answered. Still, I would like it to slightly lessen the chance of it appearing as a question instead of it just not appearing after correctly answered once. If someone can explain how to get a weighted random in C++, I can transfer the rest of the code to C++ without issue.
Have a look at std::discrete_distribution:
#include <iostream>
#include <iomanip>
#include <map>
#include <random>
int main()
{
std::random_device rd;
std::mt19937 gen(rd());
std::discrete_distribution<> d({40, 10, 10, 40});
std::map<int, int> map;
for(int n=0; n<10000; ++n) {
++map[d(gen)];
}
for(const auto& [num, count] : map) {
std::cout << num << " generated " << std::setw(4) << count << " times\n";
}
}
Besides correct and simple other answer I can suggest my own version which explicitly does all math computation from scratch. For educational purpose only.
Try it online!
#include <cstdint>
#include <vector>
#include <random>
#include <iostream>
#include <iomanip>
int main() {
std::vector<double> const weights = {9.0, 7.8, 1.2, 3.4, 5.6};
std::vector<double> sum = {0};
for (auto w: weights)
sum.push_back(sum.back() + w);
for (auto & s: sum)
s /= sum.back();
std::mt19937_64 rng{std::random_device{}()};
auto Gen = [&]{
auto x = double(rng()) / double(uint64_t(-1));
for (size_t i = 0; i < sum.size() - 1; ++i)
if (x < sum[i + 1])
return i;
return sum.size() - 2;
};
std::vector<size_t> counts(weights.size());
for (size_t i = 0; i < (1 << 12); ++i)
++counts[Gen()];
for (size_t i = 0; i < counts.size(); ++i)
std::cout << std::setw(2) << i << " was generated "
<< std::setw(4) << counts[i] << " times" << std::endl;
}
Console output:
0 was generated 1404 times
1 was generated 1165 times
2 was generated 166 times
3 was generated 524 times
4 was generated 837 times
I am teaching myself programming, and as a challenge I tried making a simple text battle system in c++. I used the function rand() to generate pseudo-random numbers. The problem is, they were the same every time you ran the program. e.g. If num1 was in the first turn 1, on the second 0, then 0, 1, 0, 1, 1, 1 etc, if you closed the program and reopened it, it would always be 1, 0, 0, 1, 0, 1, 1, 1...
I then looked up how to measure time. I wanted to take an integer expressing exactly how long it took the player to enter a certain string. I followed the tutorials precisely (except I named the variables differently). It did not work. Can anyone please help me and explain how the syntax of this works? I put together a simple program representing exactly what I did, so that you don't have to go through the long, irrelevant code of the entire battle system. I looked up questions like this but nothing worked yet.
#include <iostream>
#include <chrono>
using namespace std;
int main()
{
auto time1 = std::chrono::high_resolution_clock::now();
cout << "enter a character:" << endl;
char blob;
cin >> blob;
auto time2 = std::chrono::high_resolution_clock::now();
std::chrono::duration<double, std::milli> time = timer2 - timer1;
cout << time;
return 0;
}
if you wont to use rand() function you need first to call srand with "seed"
this is an example:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main () {
int i, n;
time_t t;
n = 5;
/* Intializes random number generator */
srand((unsigned) time(&t));
/* Print 5 random numbers from 0 to 50 */
for( i = 0 ; i < n ; i++ ) {
printf("%d\n", rand() % 50);
}
return(0);
}
but like people wrote in the comment is c style code not CPP
this is use with CPP
#include <random>
#include <iostream>
int main()
{
std::random_device dev;
std::mt19937 rng(dev());
std::uniform_int_distribution<std::mt19937::result_type> dist6(1,6); // distribution in range [1, 6]
std::cout << dist6(rng) << std::endl;
}
How to generate a random number in C++?
Your code does not work as you expected due to 3 reasons:
Typo in variable names: change timer1 and timer2 to time1 and time2 respectively.
Use duration_cast instead of duration.
Use count() method.
count() returns the number of ticks of the type on which you invoke
it.
Here is the finished code:
#include <iostream>
#include <chrono>
using namespace std;
int main()
{
// meausure time at the begining.
auto time1 = chrono::high_resolution_clock::now();
cout << "enter a character:" << endl;
char blob;
// wait for user input.
cin >> blob;
// meausure time at the ending.
auto time2 = chrono::high_resolution_clock::now();
// evaluate and print the difference.
auto time = chrono::duration_cast<chrono::milliseconds>(time2 - time1);
cout << time.count();
return 0;
}
But, as #yaodav suggested, there are other better ways to generate random numbers in C++.
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)).
I'm trying to produce do some processing on a random permutation of the alphabet, however each permutation produces the same result despite using srand(myseed)
I have included the <algorithm> header.
string create_permutation(unsigned seed)
{
srand(seed);
string permutation = ALPHABET;
random_shuffle(permutation.begin(), permutation.end());
return permutation;
}
cout << create_permutation(2) << endl; // or 3, 4, 5 etc
// continuously returns 'XQACKHSLOJ,TRBZNGV.W FIUEYDMP
Any help would be greatly appreciated.
EDIT: Minimal, Complete, and Verifiable example
EDIT 2: adjustment to mcve
#include <iostream>
#include <algorithm>
using namespace std;
const string ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZ.,' ";
string create_permutation(unsigned seed)
{
srand(seed);
string permutation = ALPHABET;
random_shuffle(permutation.begin(), permutation.end());
return permutation;
}
int main(){
cout << create_permutation(2) << endl; // or 3, 4, 5 etc
// continuously returns 'XQACKHSLOJ,TRBZNGV.W FIUEYDMP
return 0;
}
The problem
The shuffles aren't random because shuffle_random is using the same seed for the random number generator each time it is called.
srand does not seed the random_shuffle function, it seeds rand and random_shuffle usually calls rand, but does not have to.
random_shuffle has two forms:
One that takes 2 arguments (begin/end iterators)
One that takes 3 (begin/end iterator and a random generator).
You have demonstrated that you know how to use the first form, but the problem with the first form is that it is implemented differently on different platforms and with different compilers. It may not use rand() at all, which is the function that srand seeds.
You should use the 3 argument form and provide the random number generator as a parameter to the function.
You can follow this detailed answer to learn how to make your own random number generator, or you can provide rand() to the random_shuffle function as the random number generator.
When you seed the random number generator, you set the starting point for an algorithm that will provide a sequence of psuedorandom numbers. If you always use the same seed, the algorithm will always have the same starting point and always generate the same sequence of numbers.
Every time you call srand, you reset the seed and reset the starting point for the algorithm.
A common bug here is to repeatedly call srand. Unless you have a very good reason not to (and if you do, you probably shouldn't use rand and srand at all. Look to the <random> library) you should call srand once at the beginning of the program to seed the generator once and ever after use that seed.
srand is also quite expensive. From a performance standpoint, you don't want to call it often.
So: since every call to create_permutation calls srand with the seed parameter and create_permutation is always called with the same seed value, for a given implementation of the random number generator, create_permutation will always use the same random number sequence and thus generate the same permutation.
A quick example that will generate different permutations, so long as the program is not run more often than once per second is
#include <iostream>
#include <string>
#include <algorithm>
#include <ctime>
const std::string ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZ.,' ";
std::string create_permutation()
{
std::string permutation = ALPHABET;
std::random_shuffle(permutation.begin(), permutation.end());
return permutation;
}
int main(){
srand(time(NULL)); // caveat: time's minimum resolution is 1 second.
// multiple executions of this program within 1
// second will get the same time and use the same seed.
std::cout << create_permutation() << std::endl;
std::cout << create_permutation() << std::endl;
std::cout << create_permutation() << std::endl;
std::cout << create_permutation() << std::endl;
std::cout << create_permutation() << std::endl;
return 0;
}
A more modern approach:
#include <random>
#include <algorithm>
#include <iostream>
#include<string>
const std::string ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZ.,' ";
std::random_device rd; // Warning: implementation of this is allowed to be stupid and
// return the same value every time. Does not work in mingw 4.8
// Can't speak for 4.9 or greater
std::mt19937 randomizer(rd());
std::string create_permutation()
{
std::string permutation = ALPHABET;
std::shuffle(permutation.begin(), permutation.end(), randomizer);
return permutation;
}
int main()
{
std::cout << create_permutation() << std::endl;
std::cout << create_permutation() << std::endl;
std::cout << create_permutation() << std::endl;
std::cout << create_permutation() << std::endl;
std::cout << create_permutation() << std::endl;
}
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