Skip to main content
GameDev.net gamedev.net
🔒 Locked

problems with random numbers

Started by Sceletor Mar 29, 2008 at 7:32 PM 15 replies 2.8k views
Original Post
Sceletor
Sceletor
Im currently trying to build a random number generator for my game, and before I did it, I read a little about rand(). One of the first things I found out was that I need to call srand() with time(null) in order to pass a seed to rand(), so it doesnt return always the same order of values. After reading this, I tried to build my random number generator, but there seems to be an important point I missed, and so I wanted to ask you people here whats going wrong. My idea was to call srand() right in the main method of my game (actually as the first thing I do at all) and then have a generate_random_number(int lowerbound, int upper_bound) function in my FrameWork class. The strange thing is now, that if I call rand() in my main.cpp right after calling srand(), it returns numbers, but rather simply increasing ones, not randomly small or big.. If I call rand() now in my function in the framework class, it simply returns always the same order of random numbers, just like I never called srand(). I already searched my code for other occurences of srand(), but there are none. Code in main.cpp:

#include <string>
#include <cstdlib>
#include <cstdio>
#include <ctime>

int main (int argc, char *argv[])
{
    std::cout << "[Main]time is: " << (unsigned int) time(NULL) << std::endl;
    printf ("First number: %d\n", rand() );
    printf ("Second number: %d\n", rand());
    srand((unsigned int) (time(NULL)));
    printf ("random number: %d\n", rand());
}

output:
Quote:
[Main]time is: 1206836264 First number: 41 Second number: 18467 random number: 12108 //this is maybe 12132 the next time I run my game
Code in framework.cpp:

Uint32 Framework::random_generator(Uint32 lower_bound, Uint32 upper_bound)
{
	unsigned int random_number = (unsigned int) std::rand();
	printf ("[FrameWork]random number: %d\n", random_number);
	Uint32 dest_range = upper_bound - lower_bound;
	
	Uint32 return_value = Uint32 (lower_bound + ((Uint32) random_number % dest_range));
}

output:
Quote:
[FrameWork]random number: 41 [FrameWork]random number: 18467
Notice that 41 and 18467 are the first numbers rand() returns without seed or seed 1... And I shortened the code and the output, so dont try to correct syntax errors, pls.
Rydinare
Rydinare
I'm assuming framework.cpp is called from another main() without seeding the random # generator before calling, which is why the two values match the two pre-seeded values in the other main().

At the risk of stating the obvious, have you tried searching Google for some freely available random number generator already developed?

Check out Boost.Random: Boost.Random

P.S.: It appears Boost 1.35 was just released. Woohoo! [smile]
F1N1TY
F1N1TY
This one is recommended in Game Coding Complete. Not suggesting you use it (as that's entirely up to you). But, the source code to it might be an aid for your own code. Let us know what you end up with :-)

Cheers!

"I'd rather know one thing, no matter how ordinary, than discourse endlessly on great issues." -- Galileo
CProgrammer
CProgrammer
Hm, you stated that you are calling rand in the Framework class soIm assuming this is called in some way in the same main function that called srand. Everything should thus be working, maybe, however, and I have no idea whether this is the cause, could it be that by calling std::rand in your Framwrok class the compiler is actually using a different rand() function in the main function. Possibly a version not located in the std namespace?
zach297
zach297
In case your interested here is a sample random number generator.
int Random(int seed, int min, int max){    int x = (seed << 13) ^ seed;    float y = ((x * (x * x * PRIME0 + PRIME1) + PRIME2) & 7fffffff) / 47483648.0f)       return (int)(y * (max - min)) + min;}
Its very simple; just replace PRIME0, PRIME1, and PRIME2 with some random prime numbers that are all different. For best results use high numbers. Use the results of y times the maximum integer for the next seed for this function.
Happy Deving,
zach297
Sceletor
Sceletor
Quote:
Original post by Rydinare
I'm assuming framework.cpp is called from another main() without seeding the random # generator before calling, which is why the two values match the two pre-seeded values in the other main().

At the risk of stating the obvious, have you tried searching Google for some freely available random number generator already developed?

Check out Boost.Random: Boost.Random

P.S.: It appears Boost 1.35 was just released. Woohoo! [smile]


Ahem... another main()? In case I get you right, there is only one main() in my project, which does seed the random generator.
The two quotes in my frist post were both parts of the same stdout.txt file.

@CProgrammer: I used now std::rand() and std::srand(), and I cannot see why two different kinds of rand() should be called, although my output is suggesting that. I hoped anyone here could give me an explanation for this behaviour.

Oh, and one more thing: the framework class is a singleton class, maybe there are some issues with rand() in singletons??

@others: Ill check out boost::random and the other proposals after I tried to get rand() working correctly for, lets say, a day or so.
Your proposals are really good, but I dont like switching over to something else as soon as I encounter a problem while programming.

F1N1TY
F1N1TY
srand() just sets the seed value for future calls (within your program) to the rand() function to use. The "randomness" is actually based off of an algorithm, that calculates a number. That's why the same seed, will return the same random number. We'll have to see more of your main function, and how it's using your framework class to see exactly what's going on here. We're assuming your later creating an instance of the framework class somewhere in your main.

Let us know.

EDIT: Basically, you could roll your own "random number" generator that just did this:

setSeed(8);
int n = random(14);

cout << "Random = " << n << endl;

If the random function did this:

int random(int n)
{
return (n + seed);
}

Then we'd get this output:
Random = 22;

Of course, a good RNG would be much more complicated in it's algorithm.
"I'd rather know one thing, no matter how ordinary, than discourse endlessly on great issues." -- Galileo
Rydinare
Rydinare
Quote:
Original post by Sceletor
Quote:
Original post by Rydinare
I'm assuming framework.cpp is called from another main() without seeding the random # generator before calling, which is why the two values match the two pre-seeded values in the other main().

At the risk of stating the obvious, have you tried searching Google for some freely available random number generator already developed?

Check out Boost.Random: Boost.Random

P.S.: It appears Boost 1.35 was just released. Woohoo! [smile]


Ahem... another main()? In case I get you right, there is only one main() in my project, which does seed the random generator.
The two quotes in my frist post were both parts of the same stdout.txt file.


The reason why I ask if you have a different main() is because it isn't obvious that your Framework class is ever called anywhere. You can have different projects with different main() functions; I don't know how you set things up. The main() you posted, seems extremely trivial. As such, I naturally assumed something was missing.
Sceletor
Sceletor
After reading a little about random number generators and seeing that rand() is absolutely not useful for my needs, I decided to switch to boost::random, since I already have some experience with boost and am quite satisfied with it( except for the documentation, of course).

@Ridynare: Theres just one project in my workspace, with only one main(), so theres no risk..

@F1N1TY: My game consist of (very) roughly estimated 50 classes, and I dont think it would help to post all the code here, so please apologize that I made a selection of what I regarded neccessary to see my problem.

@ALL: I wil shift to boost::random, and so there is no need for all you nice guys to think about my problem with rand() anymore. But many thanks for all your help and suggestions!!!
NotAYakk
NotAYakk
BTW, if you want the ability to repeat an execution, you probably want the ability to save/restore a random seed.

(Being able to repeat execution gives you cheap networking, reproducible bug cases, game recording, and a bunch of other benefits: on the other hand, it is hard to pull off, so maybe you should just punt!)
zach297
zach297
Quote:
Original post by NotAYakk
BTW, if you want the ability to repeat an execution, you probably want the ability to save/restore a random seed.

(Being able to repeat execution gives you cheap networking, reproducible bug cases, game recording, and a bunch of other benefits: on the other hand, it is hard to pull off, so maybe you should just punt!)

I made a game that used that once. It was a racing game with a completely random track which has unlimited length. Using repeat execution I would only have to use a few bytes instead of thousands to describe the tracks. Some of the older games had claims of thousands of different levels contained on their tiny cartridges. They pulled it off with random number generators. Never underestimate the power of RNGs.
Happy Deving,
zach297
NotAYakk
NotAYakk
That is also how Civ4 does multiplayer -- so it isn't just an ancient technique. :)
zach297
zach297
Correct me if I'm wrong hear, but doesn't Oblivion use RNGs to generate its caves? If so it must have taken a genius to program it.
Happy Deving,
zach297
NotAYakk
NotAYakk
Hmm? It isn't that hard to use a RNG to generate a cave system?

Or is there something interesting about Oblivion's caves?
zach297
zach297
Quote:
Original post by NotAYakk
Hmm? It isn't that hard to use a RNG to generate a cave system?

Or is there something interesting about Oblivion's caves?

Thats what I am saying though. It would be very hard and the programmer whould have to be extremely clever. Although, I just looked it up, and it seems I was wrong; Oblivions maps are not random. My mistake.
Happy Deving,
zach297
KulSeran
KulSeran
Oblivion is hand crafted. BUT look at something like the diablo series, all those maps are randomly generated off a set collection of
pieces that it stitches together.
Evil Steve
Evil Steve
Quote:
Original post by zach297
Quote:
Original post by NotAYakk
Hmm? It isn't that hard to use a RNG to generate a cave system?

Or is there something interesting about Oblivion's caves?

Thats what I am saying though. It would be very hard and the programmer whould have to be extremely clever. Although, I just looked it up, and it seems I was wrong; Oblivions maps are not random. My mistake.
Happy Deving,
zach297

1. An individual cave, or part of one could be crated from one random seed, and then that the landscape could have information about what cave uses what random seed.
2. The seed could be used to just generate a tree-like structure of caverns and tunnels, which would make it pretty simple to just try a bunch of seeds and see what it looks like.
3. The RNG could be used to perturb the cave walls, so the cave could be modeled, but the walls would be randomly adjusted.
4. Look up "fractal landscape generation" on Google and you'll see what sort of things you can do with a single 32-bit number as data and a chunk of code.



EDIT: I just read what I actually quoted; even if Oblivian doesn't use a RNG for caves, it might use it in a similar way to what I described in points 2 and 3.

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.