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);
Related
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;
}
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;
}
I've written a small program at https://github.com/lub094/Roulette. It simulates a roulette and calculates the times a sequence of same color sectors with length n, has been reached. So if you spin it 4 times and you get RED, BLACK, BLACK, BLACK that will give you 2 sequences with lengths 1, and 1 sequence of lengths 2 and 3.
The problem comes when I spin it more than a million times. Then the longest sequence reached is absolutely always 15. I've tried it with 500 000 000 000 spins and yet again, the longest sequence is 15. I've done the math, I've tried it on java and this seems to be an abnormal behavior. I've tried putting the seed srand() in the main, in the constructor of the Roulette class and in the method calling rand(), but there seems to be no difference.
This is how I'm currently seeding the rand:
#include <iostream>
#include "Roulette.cpp"
int main() {
srand(time(nullptr));
Roulette roulette;
roulette.spin(10000000);
return 0;
}
In the class Roulette, I have the method getRandomColor() where I call the rand() method:
SectorColor getRandomColor() {
long long randomNumber = rand();
if (randomNumber % 2 == 0) {
return SectorColor::RED;
} else {
return SectorColor::BLACK;
}
}
I'm running it on windows on MinGW's latest version as for this date. The IDE I'm using is Eclipse.
I can't find any place where there could be a mistake, so thanks in advance if you try to investigate :)
Your problem is right here:
if (randomNumber % 2 == 0) {
return SectorColor::RED;
} else {
return SectorColor::BLACK;
}
It's well known that many implementations of rand() have very poor randomness in the lower bits. Try something like:
return (randomNumber & 1024)? SectorColor::BLACK : SectorColor::RED;
which uses bit 10 instead of bit 0.
Moving to the C++ template-based PRNGs, such as Mersenne Twister, would be even better.
Side note, naming include files with a .cpp extension is very bad style.
Im trying to shuffle a deck of cards but random_shuffle produces the same result every time
void
Deck::shuffle() {
cout << "SHUFFLING CARDS!!!\n\n";
srand(time(0));
random_shuffle(cards.begin(), cards.end());
displayCards();
}
That's because you seed pseudo-random number generator to the same value each time:
srand(time(0));
The granularity of time are seconds, if I'm not mistaken. If you pause the execution for some time between calls to Deck::shuffle() you should see different results.
Remove that line from the function and call it once at the start of your program.
I think that the problem is because you are putting srand(...) inside of your function.
Try to move it outside (so that it will be executed only once)
You are reseeding the random number generator each time you call shuffle.
You should only seed the random number generator once per application (typically in your application initialization):
int main()
{
// other initialization
srand(time(NULL)); // seed the number generator
// ...
}
It is important to know that to be able to receive a "random" number you have to seed the generator. Also it should be seeded outside the function.
srand(time(NULL));
The use of the time function will help ensure that you will receive a random number.
time.h does need to be included for it to work. For more reference on srand, click here.
I'm not familiar with random_shuffle, but here's a function that does a perfect shuffle - in other words, each 52! permutations of the deck has to be equally likely.
This is from Gayle Laakmann's Cracking the Coding Interview (Question 20.2)
void Deck::shuffle() {
int temp, index;
for (int i = 0; i < cards.size(); i++){
index = (int) (rand() %(cards.size() - i)) + i;
temp = cards[i];
cards[i] = cards[index];
cards[index] = temp;
}
}
I'm doing a book exercise that says to write a program that generates psuedorandom numbers. I started off simple with.
#include "std_lib_facilities.h"
int randint()
{
int random = 0;
random = rand();
return random;
}
int main()
{
char input = 0;
cout << "Press any character and enter to generate a random number." << endl;
while (cin >> input)
cout << randint() << endl;
keep_window_open();
}
I noticed that each time the program was run, there would be the same "random" output. So I looked into random number generators and decided to try seeding by including this first in randint().
srand(5355);
Which just generated the same number over and over (I feel stupid now for implementing it.)
So I thought I'd be clever and implement the seed like this.
srand(rand());
This basically just did the same as the program did in the first place but outputted a different set of numbers (which makes sense since the first number generated by rand() is always 41.)
The only thing I could think of to make this more random is to:
Have the user input a number and set that as the seed (which would be easy to implement, but this is a last resort)
OR
Somehow have the seed be set to the computer clock or some other constantly changing number.
Am I in over my head and should I stop now? Is option 2 difficult to implement? Any other ideas?
Thanks in advance.
Option 2 isn't difficult, here you go:
srand(time(NULL));
you'll need to include stdlib.h for srand() and time.h for time().
srand() should only be used once:
int randint()
{
int random = rand();
return random;
}
int main()
{
// To get a unique sequence the random number generator should only be
// seeded once during the life of the application.
// As long as you don't try and start the application mulitple times a second
// you can use time() to get a ever changing seed point that only repeats every
// 60 or so years (assuming 32 bit clock).
srand(time(NULL));
// Comment the above line out if you need to debug with deterministic behavior.
char input = 0;
cout << "Press any character and enter to generate a random number." << endl;
while (cin >> input)
{
cout << randint() << endl;
}
keep_window_open();
}
It is common to seed the random number generator with the current time. Try:
srand(time(NULL));
The problem is that if you don't seed the generator it will seed itself with 0 (as if srand(0) were called). PRNGs are designed to generate the same sequence when seeded the same (due to the fact that PNRGs are not really random, they're deterministic algorithms and maybe a bit because it's quite useful for testing).
When you're trying to seed it with a random number using
srand(rand());
you're in effect doing:
srand(0);
x = rand(); // x will always be the same.
srand(x);
As FigBug mentioned, using the time to seed the generator is commonly used.
I think that the point of these articles is to have a go at implementing the algorithm that is in rand() not how to seed it effectively.
producing (pseudo) random numbers is non trivial and is worth investigating different techniques of generating them. I don't think that simply using rand() is what the authors had in mind.