Alex Hughes
Alex Hughes

Reputation: 11

Random number with no repetition

What I am trying to do is make it so that the game I am creating will randomly change characters every 5 seconds. I got this working via a timer, the only problem is I don't want them repeating, I'm currently working on dummy code so it's just changing the screen colour, but how can I make it so that it doesn't repeat the number it just called?

if (timer <= 0)
{
    num = rand.Next(2);
    timer = 5.0f;   
}

That is the current code and then in the draw I've literally just done "if num equals a certain number then change background colour".

I tried adding a prev_num checker but I can't get it to work properly (here it is)

if (timer <= 0)
{
    prev_number = num;
    num = rand.Next(2);
    if (prev_number == num)
    {
        num = rand.Next(2);
    }
    else
    {
        timer = 5.0f;
    }
}

Upvotes: 1

Views: 242

Answers (3)

Hannesh
Hannesh

Reputation: 7488

Create an array of sequential numbers and then shuffle them (like a deck of cards) when your application begins.

int[] numbers = new int[100];
for(int i = 0; i < numbers.Length; i++)
    numbers[i] = i;
Shuffle(numbers);

Using a function to shuffle the list:

public static void Shuffle<T>(IList<T> list)  
{  
    Random rng = new Random();  
    int n = list.Count;  
    while (n > 1) {  
        n--;  
        int k = rng.Next(n + 1);  
        T value = list[k];  
        list[k] = list[n];  
        list[n] = value;  
    }  
}

You can then access them sequentially out of the list. They will be random as the list was shuffled, but you won't have any repetitions since each number only exists once in the list.

if (timer <= 0)
{
    num = numbers[index];
    index++;
    timer = 5.0f;   
}

Upvotes: 0

FacticiusVir
FacticiusVir

Reputation: 2077

Consider that if you're picking (for example) a random number from 1-5 then there are five possible outcomes, so you would use rand.Next(5) to select the zero-based "ordinal" or index of the outcome, then convert it into the range you actually want (in this case, by adding one).

If you want a random number from 0-4, excluding the number you just picked, then there are only four possible outcomes, not five - if the previous number was 3, then the possible outcomes are 0, 1, 2 or 4. You can then simplify your algorithm by choosing one of those four outcomes (rand.Next(4)) and mapping that ordinal to your desired range. A simple mapping would be to say if the new random number is below the previous number, return it as-is, otherwise (if equal or greater) add one.

int new_num = rand.Next(4);
if(new_num >= prev_num)
{
    new_num++;
}

Your new number is now guaranteed to be in the same range as the previous number, but not equal to it.

Upvotes: 1

Buh Buh
Buh Buh

Reputation: 7546

Maybe just put it into a loop instead of a single check?
Also, I think because your timer was inside the else then it was not always updated correctly.

if (timer <= 0)
{
    tempNum = rand.Next(2);

    do
    {
        tempNum = rand.Next(2);
    }
    while (tempNum == num)

    num = tempNum;
    timer = 5.0f;
}

Upvotes: 0

Related Questions