• Advertisement

Archived

This topic is now archived and is closed to further replies.

how to generate 2 unique random numbers at the same time?

This topic is 5157 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

high, i have a question. if i want to generate a random number, i know to use the rand () function. well this as we all know will generate the same random number over and over, which makes it not exactly random. so we add in the srand (time (NULL)); function. now, this is all fine and dandy, as long as the random numbers arent generating within the same second. but what if i wanted to generate 2 random numbers at the same time? for example, in the program im working on, my first simple little game program. it is a simple RPG combat game. theres a player, and an enemy. you run the program and it says you have entered combat, press enter to attack. you press enter, and a random generated number is generated(attack), then a nother one is generated,(defence). if attack > defence, you hit, it then rolls dice to see how much damage is dealt. after this, the enemy swings, it does the same, 2 randoms (one attack one defence, same type of comparision, same type of damage system. but what happends is they will miss or hit each other the same way, every time, and for the same amount of damage. i changed it around a bit, making it so the first attack and defence are:
attack = (rand () % 400) + 1;   //generates random number within 1-400

	attack = attack % 11 + 1 //mods that number to make it between 1-12

	defence = (rand () % 500) + 1; // generates random number within 1-500

	defence = defence % 11 + 1; // mods that number within 1-12

and the second attack and defences are :
attack = (rand () % 11) + 1; //generates a random number and mods it to be between 1-12


defence = (rand () % 11) + 1; //generates a random number and mods it to be between 1-12

this seems to keep them both unique. but not fair! the second set of attacks seems to work a lot more then the first set. does anyone know an easier way to do this? i also have problems calculating damage, since that also uses random numbers for both players, within the same second. making the damage be the same, but i also changed the numbers around to be different, but that too seems to be off. any help is appreciated. thanks

Share this post


Link to post
Share on other sites
Advertisement
I am having the exact same problems. Currently every gameloop my game randomly chooses block color and position. Since it is updated quite a bit, my block positions repeat contantly.

I will be watching this thread to see if you find an answer.

[edited by - FaR on January 11, 2004 5:07:24 PM]

Share this post


Link to post
Share on other sites
I''m using the RDTSC instruction to get a seed. Doing something like this would probably give you a pretty good one:


// Gives you a 64-bit (8 byte) seed value.

inline unsigned __int64 GetSeed64()
{
__asm rdtsc
}

// Since srand wants a 32-bit number and not a 64-bit one, we''ll have to do something about the 64-bit seed.

inline unsigned int GetSeed32()
{
unsigned __int64 i = GetSeed64();
return (unsigned int)(i >> 32) ^ (unsigned int)(0xFFFFFFFF & i);
}


Then you call srand with the value from GetSeed32.


[My Image Gallery (WIP)][Greatest Tetris clone evar!][Return your stolen MP3s]

Share this post


Link to post
Share on other sites
i am very new to programming. i dont understand your code! for starters, ive never seen __ before a data type or anything. whats that about? care to explain the rest of the code to a newbie? thans\ks

Share this post


Link to post
Share on other sites
quote:
well this as we all know will generate the same random number over and over, which makes it not exactly random

? no !? Its generating a random series of numbers that is well defined by the mathematical expression behind rand(), but calling rand multiple times will not generate multiple times the same number. use srand only once when you use a fixed parameter (dont put srand in a gameloop etc) or use some alternative random number generators (google, sry forgot the name of a good one)


oh and
quote:

rand () % 400) + 1; //generates random number within 1-400
rand () % 11) + 1; //generates a random number and mods it to be between 1-12



do you see the problem? 12 will never appear (%11 returns values from 0 to 10)


T2k

Share this post


Link to post
Share on other sites
I don''t understand you problem.

Do you want two randomly generated numbers that are different?

That''s very easy to do.

Generate a random number. Save it. Keep generating another
random number until it''s different. Save that.


int r1, r2;

r1 = rand();
do { r2 = rand(); } while (r2 == r1);

// Now r1 and r2 are different






Kami no Itte ga ore ni zettai naru!

Share this post


Link to post
Share on other sites
quote:
Original post by graveyard filla
i am very new to programming. i dont understand your code! for starters, ive never seen __ before a data type or anything. whats that about? care to explain the rest of the code to a newbie? thans\ks
Sorry, I guess I''ll explain a little bit more.

__int 64 is a 64-bit datatype. __asm RDTSC calls the RDTSC instruction, which returns the number of cycles executed since the CPU started up. It returns a 64 bit (8 byte) number, which is twice the size srand wants. We could just use the lower DWORD (the first four bytes) of the result, but since we have a 64 bit number, we might as well use all of it. That''s why we have to manipulate it a bit.

The line "return (unsigned int)(i >> 32) ^ (unsigned int)(0xFFFFFFFF & i);" performs a logical XOR operation with the first four bytes and last four bytes of the value we got from RDTSC. XOR goes through all the individual bits, checking if they''re 1 or 0, and sets the corresponding bit of the result to 0 if the bits in the operands are the same, or 1 if they are different.
Don''t worry if you didn''t understand the bit about XOR - it isn''t really important for now.


[My Image Gallery (WIP)][Greatest Tetris clone evar!][Return your stolen MP3s]

Share this post


Link to post
Share on other sites
thanks for all your help guys. but i seem to be even more confused now then ever. so using the srand (time (NULL));
then assigning a variable to rand likeattack = (rand () % 11) + 2;

will generate a random number based on the internal clock. it was my presumption that if you did
srand (time (NULL));

attack = (rand () % 11) + 2;
defence = (rand () % 11) + 2;

this would generate 2 random numbers, but wouldnt the numbers be exactly the same? or am i wrong about this? since they executed one after another, wouldnt that mean thye execute at the same point in time, therefore they would be the same number?

one more question, so i only put
srand (time (NULL)) once in the entire program? or do i put it in each function, or what?

could someone help me? maybe take a look at my program, run it and tell me what you think? i could really use some advise from someone whos looked at the code/program itself.
here it is. thanks guys


#include <iostream>
#include <stdlib.h>
#include <time.h>
#include <string>

using namespace std;

void intro_screen (); //a simple print screen function that prints the welcome screen


string calc_attack (int &enemyhealth); //the function that calculates the players attacks

//and returns the attack result (hit or miss)

// and "grabs" enemys health


string enemy_attack (int &health); //the function that calculates the enemeis attacks

//and returns the attack result and "grabs" player health


int main()
{
string hit_result;
string enemy_hit_result;
int go_attack;
int health = 100;
int enemy_health = 100; //initalizes the holding places for hit results, and health for both

//players




intro_screen(); //simply prints the intro screen to the screen


do
{

cout<<"You have "<<health<<" health"<<endl;
cout<<"They have "<<enemy_health<<" health"<<endl;
cout<<"Press enter to attack!"<<endl;
cin>>go_attack;

hit_result = calc_attack(enemy_health); // this finds out if the player hits or misses

// if hit, it updates the new enemies health


cout<<hit_result<<endl<<endl; //prints if player hit or missed


enemy_hit_result = enemy_attack(health); //this finds if the CPU hit or missed the player

//if hit, it updates the health variable


cout<<enemy_hit_result<<endl<<endl; //prints if CPU hit or missed


}
while ((health >= 0) && (enemy_health >= 0)); //plays the game untill one of the players dies


if (health < 0) //if player dies, say game over.

{

cout<<"You are dead"<<endl;

cout<<"Game Over"<<endl;
}
else if (enemy_health < 0) //if enemy dies, say victory

{
cout<<"You have achieved victory!"<<endl;

}

return 0;
}

void intro_screen () //simply prints the welcome screen to the player.

{
cout<<"*********************************************"<<endl;
cout<<"Welcome to FTA"<<endl;
cout<<"*********************************************"<<endl;
cout<<"Donkey Punch Productions. A company of Foo Derraro."<<endl;
cout<<"You are walking down the streets and an enemy approaches."<<endl<<endl;
cout<<"You have entered combat!!!"<<endl<<endl;

}

string calc_attack (int &enemy_health) //calculates players attack and returns "hit or miss"

// and sends back new enemy health

{
int attack;
int defence;
int damage;
string hit_result;

srand (time (NULL));
attack = (rand () % 1000) + 1; //generates random number for attack

//between 1-1000 and mods it to

// a a dice number (1-12)

attack = attack % 11 + 2;
defence = (rand () % 800) + 1; //generats random number for defence

//between 1-800 and mods it to a dice number

defence = defence % 11 + 2;
if (attack > defence) //compares attack to defence, if bigger, it is a hit and then calculates

// damage and update health

{
hit_result = "You hit!";

damage = ((rand () % 11) + 2);

enemy_health = enemy_health - damage;
}
else if (defence >= attack) //if defence is bigger, you miss

{
hit_result ="You missed!";
}

return hit_result; //returns string "hit" or "miss"

}

string enemy_attack (int &health) // calculates enemy attack "hit" or "miss" and calculates damage

//and updates health.

{
int attack;
int defence;
int enemydmg;
string enemy_hit_result;

srand (time (NULL));

attack = (rand () % 11) + 2; //makes attack a random between 1-12


defence = (rand () % 400) + 1;
defence = defence % 11 + 2;

//makes attack a random between 1-12


if (attack > defence) //if attack > defence, you hit is sent back, and calculates damage

//and updates health

{
enemy_hit_result = "You were hit!";

enemydmg = (rand () % 11) + 1;

health = health - enemydmg;
}

else if (defence >= attack) //if defence > attack, "miss" is returned, health stays unchanged


{
enemy_hit_result ="They missed you!";
}

return enemy_hit_result;
}

Share this post


Link to post
Share on other sites
first of all DO NOT CALL SRAND() before every random number .. this is just WRONG WRONG WRONG .. because then you are NOT getting random nubmers, you are getting a number based on the time, completely and totally ...

RAND generates a SEQUENCE of DIFFERENT pseudo-random nubmers, from a seed ... EACH time you reset the seed to a certain number, you get the SAME sequence, but the relationship between each number in the sequence is HIGHLY unpredictable before hand in the sense that they do not follow any easily recognizable patterns, and therefore are well suited for generated many different sub-sequences out of ...

SRAND is meant to be used ONCE, to initial the sequence at the start of your number generation ...

NOT ONLY can it be used to set to a thing like the clock time, so that you are highly likely to get different behavior every time you play the game. But it is also possible to CHOOSE a number and save it, so you can RERUN the same numbers again ... this is how PICKING a game in MAJONG or FREECELL works .. you are PICKING the seed to the random number generator - which then yeilds a certain deck during the shuffling algorithm (which calls RAND many times).

IF you can SRAND many times, you get LESS random seeming behavior in general, because the clock advances in a PREDICTABLE way ... the algortihm rand uses is based on trying to generated numbers based on a source, and yet not in any easily predicatable or identifiable way (they do this by combining many operations, at least one of which overflows out of the used registers) ...

Share this post


Link to post
Share on other sites
what about inside different functions? should i just call srand(time) in the main, and go about doing my rands() everywher else in the program (including outside of main)? what i mean to say is, is srand(time) a global thing? or do i have to do it in each one of the functions?

Share this post


Link to post
Share on other sites
quote:
Original post by graveyard filla

srand (time (NULL));
attack = (rand () % 11) + 2;
defence = (rand () % 11) + 2;

this would generate 2 random numbers, but wouldnt the numbers be exactly the same? or am i wrong about this? since they executed one after another, wouldnt that mean thye execute at the same point in time, therefore they would be the same number?




These two numbers would not necessarily be the same. The C rand () function returns numbers that are pseudo-randomized by running them through some function, using the result of the previous call(s) as some part of the calculation in the next call. Two calls in a row that return the same number might or might not (In my opinion, should) be possible depending on the particular function implementation.

As other posters noted, only srand once in your program and you'll be fine.

Some programmers like to seed the program with
srand (time (NULL) * getpid ()); 
so that two programs started at the same time (network clients on two separate computers, for instance) are far less likely to get the same seed. If you're working on Windows, I think getpid is implemented, or it might be called GetWindowsProcessID or something like that.

-PJM

[edited by - pmargate on January 11, 2004 6:19:49 PM]

Share this post


Link to post
Share on other sites
thanks. i understand now. now i just wish someone would look at my code and tell me what im doing wrong. (my next problem)

when you run the program, it will say "press enter for attack". but, you have to type in a number , then press enter, and then the attack sequence will run. this is because my code is writtin:
int go_attack;
cout<<"press enter to attack"<
cin>>go_attack;
attack sequence;

now, go_attack doesnt do anything, i just put it there so the program would wait untill it got input from the user, before it ran the attack sequence. how do i make it so the player doesnt have to put an integer for it to run? how do i make it so they just type enter? if you dont understand what im saying, just run the code and you will see what im trying to figure out. thanks!



#include <iostream>
#include <stdlib.h>
#include <time.h>
#include <string>

using namespace std;

void intro_screen (); //a simple print screen function that prints the welcome screen


string calc_attack (int &enemyhealth); //the function that calculates the players attacks

//and returns the attack result (hit or miss)

// and "grabs" enemys health


string enemy_attack (int &health); //the function that calculates the enemeis attacks

//and returns the attack result and "grabs" player health


int main()
{
string hit_result;
string enemy_hit_result;
int go_attack;
int health = 100;
int enemy_health = 100; //initalizes the holding places for hit results, and health for both

//players

srand (time (NULL)); //set the seed to the internal clock of the computer



intro_screen(); //simply prints the intro screen to the screen


do
{

cout<<"You have "<<health<<" health"<<endl;
cout<<"They have "<<enemy_health<<" health"<<endl;
cout<<"Press enter to attack!"<<endl;
cin>>go_attack;

hit_result = calc_attack(enemy_health); // this finds out if the player hits or misses

// if hit, it updates the new enemies health


cout<<hit_result<<endl<<endl; //prints if player hit or missed


enemy_hit_result = enemy_attack(health); //this finds if the CPU hit or missed the player

//if hit, it updates the health variable


cout<<enemy_hit_result<<endl<<endl; //prints if CPU hit or missed


}
while ((health >= 0) && (enemy_health >= 0)); //plays the game untill one of the players dies


if (health < 0) //if player dies, say game over.

{

cout<<"You are dead"<<endl;

cout<<"Game Over"<<endl;
}
else if (enemy_health < 0) //if enemy dies, say victory

{
cout<<"You have achieved victory!"<<endl;

}

return 0;
}

void intro_screen () //simply prints the welcome screen to the player.

{
cout<<"*********************************************"<<endl;
cout<<"Welcome to FTA"<<endl;
cout<<"*********************************************"<<endl;
cout<<"Donkey Punch Productions. A company of Foo Derraro."<<endl;
cout<<"You are walking down the streets and an enemy approaches."<<endl<<endl;
cout<<"You have entered combat!!!"<<endl<<endl;

}

string calc_attack (int &enemy_health) //calculates players attack and returns "hit or miss"

// and sends back new enemy health

{
int attack;
int defence;
int damage;
string hit_result;


attack = (rand () % 11) + 2; //generates random number for attack

// a dice number (2-12)

defence = (rand () % 11) + 2; //generats random number for defence

// a dice number


if (attack > defence) //compares attack to defence, if bigger, it is a hit and then calculates

// damage and update health

{
hit_result = "You hit!";

damage = ((rand () % 11) + 2);

enemy_health = enemy_health - damage;
}
else if (defence >= attack) //if defence is bigger, you miss

{
hit_result ="You missed!";
}

return hit_result; //returns string "hit" or "miss"

}

string enemy_attack (int &health) // calculates enemy attack "hit" or "miss" and calculates damage

//and updates health.

{
int attack;
int defence;
int enemydmg;
string enemy_hit_result;


attack = (rand () % 11) + 2; //makes attack a random between 1-12


defence = (rand () % 11) + 2;


//makes attack a random between 1-12


if (attack > defence) //if attack > defence, you hit is sent back, and calculates damage

//and updates health

{
enemy_hit_result = "You were hit!";

enemydmg = ((rand () % 11) + 2);

health = health - enemydmg;
}

else if (defence >= attack) //if defence > attack, "miss" is returned, health stays unchanged


{
enemy_hit_result ="They missed you!";
}

return enemy_hit_result;
}


if you dont undertand what im trying to say, just compile the program and you will find out real fast what the problem is. thanks

[edited by - graveyard filla on January 11, 2004 6:23:16 PM]

[edited by - graveyard filla on January 11, 2004 6:24:54 PM]

[edited by - graveyard filla on January 11, 2004 6:25:49 PM]

[edited by - graveyard filla on January 11, 2004 6:26:24 PM]

Share this post


Link to post
Share on other sites
go_attack is an int, so cin is waiting and will not return until you give it one to put in go_attack.

Share this post


Link to post
Share on other sites
i know this.

i want it to work by just pressing enter. i dont want to have to put an integer, or anything.
if i take out the

cin>>go_attack;

the program will just run, completely through, with no response from the user, untill one of the player dies. it will simply just run from start to finish. i want the player himself to initialize the attack. but not with an integer. i just want the player to press enter, and nothing else. do you understand? run the code and you will see what i mean. it will say press enter to attack, but you will have to press a number then enter. i simply want to skip pressing the number. i just want to press enter.

Share this post


Link to post
Share on other sites
Just a general point about rand, and srand... I think a lot of newbies get the impression the doing srand(time(0)) means that all random numbers are in some sense related to the current time. That is to say.. the time at any point you call rand determines the random number. This is clearly not the case.. as afaik srand takes an int. It is also important to understand that rand() will generate pseudo random numbers whether or not it has been seeded. That is to say, you can use rand with no seed in your program, and it will give you (per call to rand) another number from its (apparently) random sequence. The fact is however that it will provide exactly the same sequence every time you call the program. This will be well known to anyone who has made some graphical routine that relied strongly on random numbers, and obtained exactly the same result every time. This deterministic behaviour can be useful in many situations. Imagine you had a landscape generator that relied on rand() for random numbers. Feeding it the same seed would result in exactly the same landscape. This means that (for example) the user could enter a seed.. or the seed could be saved.. and your "random" landscape could be reproduced precisely. In this circumstance, seeding rand with time, serves no purpose... in fact it would eliminate the reproducability that you sought (unless you saved the time on seeding). There are of course circumstances when you require apparently non-deterministic random numbers. That is to say a stream of random numbers which cannot be foretold. A good option in this situation is to seed your deterministic random number generator (rand) with a seed, that has no specific significance. In general people like to use the time, hence srand(time(0)); This number (time(0)) represents the number of seconds since some date in the past (sorry, can''t remember it). This means that on each system, no to runs will be the same, unless you run two copies within the same second. This is rarely an issue.. however has been pointed out, it is possible that you require such variation between remote machines. It is possible that two copies would be seeded from time at the same second, and hence the extra factor of multiplication. The process ID for each instance will be unique, and will almost certainly be different machine to machine. This multiplication factor makes the probability of two remote machines, or even two copies on the same machine would have the same random number sequence. On a similar not... if it is important that all machines do use the same number sequence, then the server would generate a seed, and transmit to all participants. I hope that someone somewhere finds this little bit of info useful.

Share this post


Link to post
Share on other sites
Yet another redundant take on it.

Basically, it works like this:

-- topsecretfilewithrandfunctions.c --
int seed; /* global variable, which thus gets initialized to 0, I think */

void srand(int s) {
seed = s;
}

int rand() {
seed = f(seed); /* some implementation/hardware-specific functions */
return g(seed);
}


This is a state machine with reset, basically. We see the following implications:

- if you don't call srand at all, then you always get the same sequence when you call rand() several times - the first time you get g(f(0)), the second time you get g(f(f(0))), the third time you get g(f(f(f(0)))) etc.
- If you call srand with the same value every time right before rand(), then you get the same value every time - g(f(seed)).
- If you call srand with a slowly-changing value every time (for example, time(0), which changes once per second - probably slow compared to whatever calculation you're doing), then the output value will change infrequently.
- If you call srand with the same value, every now and then, then the sequence will 'reset' with each call.
- If you call with different but slowly changing values, every now and then, well, you're still shooting yourself in the foot in almost every case.

What you want to do is call srand *once*, *before rand is ever called*. Then just call rand any time you like. It doesn't matter so much if your seed value is something simple like time(0) because g(f(x)) is already pretty hard to relate to x, with the functions that are used internally.

If for some strange reason you need to reproduce the sequence of random numbers, then you need to save the seed that you used at the start of it, and reseed and restart. E.g.


int myseed = time(0);
int myvalues[100];
srand(myseed);
for (int j = 0; j < 100; j++)
myvalues[j] = rand();
int secondrun[100];
srand(myseed);
for (int j = 0; j < 100; j++)
secondrun[j] = rand();
/* Now both arrays contain a sequence of 100 "random numbers" - myvalues[j] != myvalues[k] in general - but it's the same sequence - myvalues[j] == secondrun[j] for all i in range. */
/* If I used 'time(0)' directly in the srand calls, and the system clock just happened to tick off a second some time during the first loop, then the sequences would NOT be the same. */


HTH!

(Edited to avoid creating italic tags with my array subscripts >_<

[edited by - Zahlman on January 11, 2004 9:47:57 PM]

Share this post


Link to post
Share on other sites

  • Advertisement