The situation
Hey guys, so I'm working on a project right now. Basically I need to make a traditional slot machine, or fruit machine, or "one-armed bandit". It's a 3 x 1 x 3 character grid that changes whenever the user "pulls the lever"
I've done all of the code by myself from the top of my head as of right now, but I'm at an impasse and I wondered if you guys could possibly help.
I use the word "chamber", but think of that as being the word "Wheel" and only three of the values on the wheel are ever shown on the screen at any given time, so I called these "Blocks".
I'm trying to have a single chamber display output such as:
2
3
4
where I generated the random number of 3, and outputted 4 and 2 because they are adjacent on the chamber. This would be the start position of the chamber, which I can then manipulate.
Obviously, to get the random number converted and displayed on screen, I need to convert that integer to a char* which I'll need in the future for icons, which isn't great as I need to make a constant char.
I have two issues.
1) The first is, I call my spinChamer() method 3 times (because I have 3 chambers) but the random number generator in the method don't seem to make any difference to the output of the method, almost like there is a constant somewhere.
srand(time(NULL));
//generate start position for central block. use this to find upper and lower block.
int startpoint = rand() % 7 + 1;
2) The second is, to draw a string to a co-ordinate on the screen I have to convert to a char*. This involves converting my random int variable to a char* variable, which seems easy, however, when I try to add this converted value to the vector alongside it's upper and lower elements on the wheel, all 3 positions are the same value, when they shouldn't be, again, it seems like there is a constant somewhere that I'm missing.
for (int i = 0; i < 3; i++){
convert = std::to_string(startpoint + assigner);
temporarystore = (char*)convert.c_str();
blocks.push_back(temporarystore);
assigner++;
}
//spin around twice for visual effect.
for (int counter = 0; counter < 2; counter++){
Draw_String(drawY, drawX - 1, blocks.at(0));
Draw_String(drawY, drawX, blocks.at(1));
Draw_String(drawY, drawX + 1, blocks.at(2));
}
Any help would be greatly appreciated.
Note:
Draw_String() just draws the string to the screen, I won't edit that method due to dependencies elsewhere.
First issue: do not call srand(time(NULL)); inside the function that generates random numbers. Move it outside the function! srand() must be called only once during your program execution.
Second issue: It's not clear what you are trying to accomplish and why.
If you can use C++11 in your program, there is a new bunch of functions related to randomness.
#include <random>
#include <iostream>
namespace
{
std::random_device rd;
std::mt19937 mt(rd()); // seed the random number generator once
}
int GetRandomNumber(const int lowBound, const int highBound)
{
std::uniform_int_distribution<int> dist(lowBound, highBound);
return dist(mt);
}
int main()
{
const auto diceResult = GetRandomNumber(1, 6);
std::cout << diceResult << std::endl;
return 0;
}
Related
I have made a program that generates a random array of numbers. I am aware that if I make a for structure to place random numbers, there might be a chance that I will have values that will repeat. For that I made a separate recursive function that keeps looking for duplicates and replace them with other values until there will be only distinct numbers:
#include <iostream>
#include <stdlib.h>
#include <time.h>
using namespace std;
int n, m, k, row[100];
int verif(int v[100], int k)
{
for(int i=0; i<k-1; i++)
for(int j=i+1; j<k; j++)
if(v[i]==v[j])
{
cout<<".";
srand(time(NULL));
v[i]=rand()%100+1;
return verif(v, k);
}
return 1;
}
int main()
{
k=10, n=10;
srand(time(NULL));
row[0]=rand()%n+1;
srand(row[0]);
for(int i=1; i<k; i++)
{
srand(row[i-1]);
row[i]=rand()%n+1;
}
verif(row, k);
for(int i=0; i<k; i++)
cout<<row[i]<<" ";
return 0;
}
I hope you can explain me why does a simple cout inside verif makes my program to work and why without it nothing works.
This is a result of calling a function recursively for an extended period of time, likely triggering a stack overflow on your machine.
This expression
srand(time(NULL));
seeds the random number generator for rand() to the value of the present number of seconds since the epoch. Naturally this number changes only once per second. Reseeding the rand generator will get you the same sequence as last time, so the result of rand()%100 + 1 on the following line will remain the same until the result of time(NULL) changes.
Now that you've ensured that v[i]==v[j] will be true until at least a second has passed since the initial assignment, you recursively call this function again, (and again (and again...)) until you get a new value from your "random" number generating procedure (at least a second has passed) or you run out of space on the stack. (you crash)
You can clearly see this happening much more clearly by using a function which holds up execution for longer than is taken by the cout statement, for instance
std::this_thread::sleep_for(std::chrono::milliseconds{500});
You can see such an effect here on coliru
With the sleeping function (which holds the execution up for 500 milliseconds every recursion) you get ~13 recursions.
Without it you get ~2846000 recursions. That's quite a difference.
There are better ways to get a set of non-repeating random numbers in a range, as shown in the answers to this question. I'm partial to Darklighter's answer myself. For that answer if you want, say, 10 elements out of 100, generate the vector with 100 elements, shuffle and then resize it to include only the first 10.
The cout solves the problem because it takes time to print something on the console. All the rest of the code takes roughly 0 time, thus each time you do
srand(time(NULL));
v[i]=rand()%100+1;
You will get exactly the same number, as you always use the same seed. Then I am not 100% sure what happens, it might be a stackoverflow because you keep calling the function recursively forever, or it might be something else. Actually it doesnt really matter, because the real problem is your seed.
Only with the cout you will eventually get a differnt seed and also a different random number.
You should seed the rng only once. And btw if you want random numbers you should use the rngs from <random> and not rand (actually it should be deprecated because of its low quality).
I am C++ student and I am working on creating a random number generator.
Infact I should say my algorithm selects a number within a defined range.
I am writing this just because of my curiosity.
I am not challenging existing library functions.
I always use library functions when writing applications based on randomness but I am again stating that I just want to make it because of my curiosity.
I would also like to know if there is something wrong with my algorithm or with my approach.
Because i googled how PRNGs work and on some sites they said that a mathematical algorithm is there and a predefined series of numbers and a seed just sets the pointer in a different point in the series and after some intervals the sequence repeats itself.
My algorithm just starts moving to and fro in the array of possible values and the seed breaks the loop with different values each time. I don't i this approach is wrong. I got answers suggesting a different algorithm but they didn't explain What's wrong with my current algorithm?
Yes,there was a problem with my seed as it was not precise and made results little predictable as here:-
cout<
<
rn(50,100);
The results in running four times are 74,93,56,79.
See the pattern of "increasing order".
And for large ranges patterns could be seen easily.I got an answer on getting good seeds but that too recommended a new algorithm(but didn't say why?).
An alternative way could be to shuffle my array randomly generating a new sequence every time.And the pattern of increasing order will go off.Any help with that rearranging too will also be good.Here is the code below.And if my function is not possible please notify me.
Thanking you in anticipation.
int rn(int lowerlt, int upperlt)
{
/* Over short ranges, results are satisfactory.
* I want to make it effective for big ranges.
*/
const int size = upperlt - lowerlt; // Constant size of the integer array.
int ar[size]; // Array to store all possible values within defined range.
int i, x, ret; // Variables to control loops and return value.
long pointer = 0; //pointer variable. The one which breaks the main loop.
// Loop to initialize the array with possible values..
for (i=0, x=lowerlt; x <= upperlt; i++, x++)
ar[i]=x;
long seed = time(0);
//Main loop . To find the random number.
for (i=0; pointer <= seed; i++, pointer++)
{
ret = ar[i];
if (i == size-1)
{
// Reverse loop.
for (; i >= 0; i--)
{
ret=ar[i];
}
}
}
return ret;
}
Caveat: From your post, aside from your random generator algorithm, one of your problems is getting a good seed value, so I'll address that part of it.
You could use /dev/random to get a seed value. That would be a great place to start [and would be sufficient on its own], but might be considered "cheating" from some perspective.
So, here are some other sources of "entropy":
Use a higher resolution time of day clock source: gettimeofday or clock_gettime(CLOCK_REALTIME,...) call it "cur_time". Use only the microsecond or nanosecond portion respectively, call it "cur_nano". Note that cur_nano is usually pretty random all by itself.
Do a getpid(2). This has a few unpredictable bits because between invocations other programs are starting and we don't know how many.
Create a new temp file and get the file's inode number [then delete it]. This varies slowly over time. It may be the same on each invocation [or not]
Get the high resolution value for the system's time of day clock when the system was booted, call it "sysboot".
Get the high resolution value for the start time of your "session": When your program's parent shell was started, call it "shell_start".
If you were using Linux, you could compute a checksum of /proc/interrupts as that's always changing. For other systems, get some hash of the number of interrupts of various types [should be available from some type of syscall].
Now, create some hash of all of the above (e.g.):
dev_random * cur_nano * (cur_time - sysboot) * (cur_time - shell_start) *
getpid * inode_number * interrupt_count
That's a simple equation. You could enhance it with some XOR and/or sum operations. Experiment until you get one that works for you.
Note: This only gives you the seed value for your PRNG. You'll have to create your PRNG from something else (e.g. earl's linear algorithm)
unsigned int Random::next() {
s = (1664525 * s + 1013904223);
return s;
}
's' is growing with every call of that function.
Correct is
unsigned int Random::next() {
s = (1664525 * s + 1013904223) % xxxxxx;
return s;
}
Maybe use this function
long long Factor = 279470273LL, Divisor = 4294967291LL;
long long seed;
next()
{
seed = (seed * Factor) % Divisor;
}
I have been trying to create a "1D shooter game" with prints in c++. My problem is I am trying to spawn enemies from a list at random moments and I also want to make it random where the enemy spawns (left or right of the screen).
This does not seem to fully work, as I seem to get a stream of contiguous enemies from one side, and only after all those enemies coming from the left side are killed, enemies from the right might appear.
I never seem to get a couple coming from the left and a couple coming from the right at similar times. Its always either one or the other.
In addition to this, once an enemy is spawned, the rest seem to spawn almost all at once, and suddenly there is no spawning whatsoever. The pattern seems predictable and wrong.
Here is my method that is called every time in the game loop (the game loop takes care of calling srand(time(NULL)) on every iteration, and after that calls this function.
void Enemy::spawnEnemy()
{
if (enemList.size() < 5)
{
if (!(rand() % 3))
{
if (!(rand() % 2))
{
Enemy * newEnemy = new Enemy(worldWidth, 'l');
enemList.push_front(newEnemy);
}
else
{
Enemy * newEnemy = new Enemy(0, 'r');
enemList.push_front(newEnemy);
}
}
}
}
Thank you very much in advance. I really hope someone can solve this problem, because I have been struggling to find an answer for it!
Don't call srand every loop. You should only seed it once and then call rand() to get a randomized number.
Since you tagged C++11 you should use the new <random> header to generate randomized numbers:
#include <random>
std::random_device rd;
std::mt19937 gen(rd()); // seed the random_device, only do this _once_
...
//generating a random integer:
std::uniform_real_distribution<> distribution(1, 3); // create a distribution to pick from ( 1 - 3)
int random = distribution(gen);
I have a c++ program that uses a random generator to create a cube. To create the cube I have this:
void generateSquare() {
int num = 0;
srand(time(NULL));
for (int r = 0; r < MSQUARE; r++) {
for (int c = 0; c < MSQUARE; c++) {
do {
num = (rand() % (MSQUARE * MSQUARE)) + 1;
} while (!checkUnique(num));
cube[r][c] = num;
}
}
}
It only allows a number to be generated one. This function is then wrapped in a do..while loop so that if the square doesn't meet a specific condition a new square will be generated until the one that does meet the condition is generated.
The problem is that it continually is generating the same square over and over again. I thought that the srand(time(NULL)) would seed the rand() function so that it would generate different random numbers each time to create a new unique square every time it is called but it looks like that is not happening.
void checkSquare() {
do {
generateSquare();
} while (!perfect);
}
This is not the actual do...while loop but gives you an idea of how it's being called.
How do I make sure the seed is unique each time?
You should call srand only once, at the beginning of your program. The reason why your seed is always the same is because time returns a number of seconds. Since you're calling it in a loop it always has the same value (until a second goes by).
Also if you can use C++11 or later you should look at the pseudo-random number generation in the standard library
srand sets the seed of the rand function. If you set it to a specific number it will always return you the same sequence of numbers. You will use this if you want to test a program, otherwise you use rand() without srand().
http://www.cplusplus.com/reference/cstdlib/srand/
I happen to notice that in C++ the first random number being called with the std rand() method is most of the time significant smaller than the second one. Concerning the Qt implementation the first one is nearly always several magnitudes smaller.
qsrand(QTime::currentTime().msec());
qDebug() << "qt1: " << qrand();
qDebug() << "qt2: " << qrand();
srand((unsigned int) time(0));
std::cout << "std1: " << rand() << std::endl;
std::cout << "std2: " << rand() << std::endl;
output:
qt1: 7109361
qt2: 1375429742
std1: 871649082
std2: 1820164987
Is this intended, due to error in seeding or a bug?
Also while the qrand() output varies strongly the first rand() output seems to change linearly with time. Just wonder why.
I'm not sure that could be classified as a bug, but it has an explanation. Let's examine the situation:
Look at rand's implementation. You'll see it's just a calculation using the last generated value.
You're seeding using QTime::currentTime().msec(), which is by nature bounded by the small range of values 0..999, but qsrand accepts an uint variable, on the range 0..4294967295.
By combining those two factors, you have a pattern.
Just out of curiosity: try seeding with QTime::currentTime().msec() + 100000000
Now the first value will probably be bigger than the second most of the time.
I wouldn't worry too much. This "pattern" seems to happen only on the first two generated values. After that, everything seems to go back to normal.
EDIT:
To make things more clear, try running the code below. It'll compare the first two generated values to see which one is smaller, using all possible millisecond values (range: 0..999) as the seed:
int totalCalls, leftIsSmaller = 0;
for (totalCalls = 0; totalCalls < 1000; totalCalls++)
{
qsrand(totalCalls);
if (qrand() < qrand())
leftIsSmaller++;
}
qDebug() << (100.0 * leftIsSmaller) / totalCalls;
It will print 94.8, which means 94.8% of the time the first value will be smaller than the second.
Conclusion: when using the current millisecond to seed, you'll see that pattern for the first two values. I did some tests here and the pattern seems to disappear after the second value is generated. My advice: find a "good" value to call qsrand (which should obviously be called only once, at the beginning of your program). A good value should span the whole range of the uint class. Take a look at this other question for some ideas:
Recommended way to initialize srand?
Also, take a look at this:
PCG: A Family of Better Random Number Generators
Neither current Qt nor C standard run-time have a quality randomizer and your test shows. Qt seems to use C run-time for that (this is easy to check but why). If C++ 11 is available in your project, use much better and way more reliable method:
#include <random>
#include <chrono>
auto seed = std::chrono::system_clock::now().time_since_epoch().count();
std::default_random_engine generator(seed);
std::uniform_int_distribution<uint> distribution;
uint randomUint = distribution(generator);
There is good video that covers the topic. As noted by commenter user2357112 we can apply different random engines and then different distributions but for my specific use the above worked really well.
Keeping in mind that making judgments about a statistical phenomena based on a small number of samples might be misleading, I decided to run a small experiment. I run the following code:
int main()
{
int i = 0;
int j = 0;
while (i < RAND_MAX)
{
srand(time(NULL));
int r1 = rand();
int r2 = rand();
if (r1 < r2)
++j;
++i;
if (i%10000 == 0) {
printf("%g\n", (float)j / (float)i);
}
}
}
which basically printed the percentage of times the first generated number was smaller than the second. Below you see the plot of that ratio:
and as you can see it actually approaches 0.5 after less than 50 actual new seeds.
As suggested in the comment, we could modify the code to use consecutive seeds every iteration and speed up the convergence:
int main()
{
int i = 0;
int j = 0;
int t = time(NULL);
while (i < RAND_MAX)
{
srand(t);
int r1 = rand();
int r2 = rand();
if (r1 < r2)
++j;
++i;
if (i%10000 == 0) {
printf("%g\n", (float)j / (float)i);
}
++t;
}
}
This gives us:
which stays pretty close to 0.5 as well.
While rand is certainly not the best pseudo random number generator, the claim that it often generates a smaller number during the first run does not seem to be warranted.