Use once on arc4random() number

2k Views Asked by At

How you code arc4random() that does not repeat number twice?

For instance. I'm using switch and button. I don't want to generate reused the same arc4random number again. If I have arc4random that generation numbers 2,4,42,32,42... I don't want to 42 to appear again.

How do I avoid this?

  switch (arc4random() % 50 )
        {
            case 1:
                text.text = @"You are silly boy";
                break;
            case 2:
                text.text = @"Well, you very very silly"];
                break;
            case 3:
                text.text = @"stop being silly"];
                break;
            case 4:
                [text.text = @"silly... silly"];
                break;
            case 5:
                text.text = @"what you silly boy"];
                break;

           ...
            case 0:
                text.text = @"you silly"];
                break;
        }
2

There are 2 best solutions below

2
On BEST ANSWER

One way of doing it would be as follows:

static int maxNumOfCases = 50; //This could be any number of cases that you need in your app.

......

switch (arc4random() % (maxNumOfCases--)) {
            case 1:
                text.text = @"You are silly boy";
                break;
            case 2:
                text.text = @"Well, you very very silly"];
                break;
            case 3:
                text.text = @"stop being silly"];
                break;
            case 4:
                [text.text = @"silly... silly"];
                break;
            case 5:
                text.text = @"what you silly boy"];
                break;
                ...
            case 0:
            text.text = @"you silly"];
            break;
}

This code always switches to a unique case on each invocation. The way the code works is by decreasing the range of arc4random() at each invocation by 1.

Update: Keep note that this method biases more towards the end of the run to a smaller range of numbers. So this is not a true non-repeating random number generation. But if thats not a concern, its an easy one liner to include in your code.

2
On

arc4random() is not a repeating generator, that is each invocation is independent of all other invocation. But that also means that just invoking arc4random() will not (generally) produce 50 unique numbers.

One way is to create an array of the integers you want and then walk through the array and swap each one with another chosen at random (in your case) with (arc4random() % 50). They just use consecutive values from the array and when at the end create a new array and randomize it.

Example: The values in the list will be random numbers between 0 and 49 with no repeats:

int n = 50;
int list[n];
for (int i = 0; i<n; i++)
    list[i] = i;

for (int i = n-1; i>=1; i--) {
    int ran = arc4random() % (i+1);
    int tmp = list[i];
    list[i] = list[ran];
    list[ran] = tmp;
}

for (int i = 0; i<n; i++)
    NSLog(@"%d", list[i]);

This is the modern version of the Fisher–Yates shuffle, designed for computer use and introduced by Richard Durstenfeld.

Note: using mod to create a subset creates a bias but in a case of 50 the bias is negligible.