C++ Random – Why Does rand() Give Same Numbers for Small Range?

crandom

I'm trying to make sort of a game where I have a a grid of 20×20 and I display a player (P), a target (T) and three enemies (X). All these have an X and a Y coordinate which are assigned using rand(). The problem is that if I try to get more points in the game (refills for energy etc) they overlap with one or more of the other points because the range is small(1 to 20 inclusive).

These are my variables and how I'm assigning them values:
(the COORD is a struct with just an X and a Y)

const int gridSize = 20;
COORD player;
COORD target;
COORD enemy1;
COORD enemy2;
COORD enemy3;

//generate player
srand ( time ( NULL ) );
spawn(&player);
//generate target
spawn(&target);
//generate enemies
spawn(&enemy1);
spawn(&enemy2);
spawn(&enemy3);

void spawn(COORD *point)
{
    //allot X and Y coordinate to a point
    point->X = randNum();
    point->Y = randNum();
}

int randNum()
{
    //generate a random number between 1 and gridSize
    return (rand() % gridSize) + 1;
}

I want to add more things to the game but the probability of overlap increases when I do that. Is there any way to fix this?

Best Answer

While the users who complain about rand() and recommend better RNGs are right about the quality of the random numbers, they are also missing the bigger picture. Duplicates in streams of random numbers cannot be avoided, they are a fact of life. This is the lesson of the birthday problem.

On a grid of 20 * 20 = 400 possible spawn positions, a duplicate spawn point is to be expected (50% probability) even when spawning only 24 entities. With 50 entities (still only 12.5% of the whole grid), the probability of a duplicate is over 95%. You have to deal with collisions.

Sometimes you can draw all samples at once, then you can use a shuffle algorithm to draw n guaranteed-distinct items. You just need to generate the list of all possibilities. If the full list of possibilities is too large to store, you can generate spawn positions one at a time as you do now (just with a better RNG) and simply re-generate when a collision occurs. Even though having some collisions is likely, many collisions in a row are exponentially unlikely even if most of the grid is populated.

Related Topic