0

I would like to know how to make it so that the same picture is not chosen twice in a row. Lets say pictures are given a number 1-3. If picture 1 is chosen, then picture 1 will not be chosen next. If picture 3 is chosen, then picture 1 can be chosen again, and so on.

I know that I would have to use a while statement, except I don't know how. Heres what I have as of now:

- (void)chooseBackgroundImage{
  if(thisNumber % 10 == 0){
    int chooseBackgroundImage = arc4random() % 7;
    switch (chooseBackgroundImage) {
        case 0:
            backgroundImage.image = [UIImage imageNamed:@"CyanToYellowBackground.png"];
            break;
        case 1:
            backgroundImage.image = [UIImage imageNamed:@"GreenToBlueBackground.png"];
            break;
        case 2:
            backgroundImage.image = [UIImage imageNamed:@"OrangeToGreenBackground.png"];
            break;
        case 3:
            backgroundImage.image = [UIImage imageNamed:@"OrangeToPurpleBackground.png"];
            break;
        case 4:
            backgroundImage.image = [UIImage imageNamed:@"PurpleToCyanBackground.png"];
            break;
        case 5:
            backgroundImage.image = [UIImage imageNamed:@"RedToBlueBackground.png"];
            break;
        case 6:
            backgroundImage.image = [UIImage imageNamed:@"YellowToRedBackground.png"];
            break;
       }
    }
}

I've also tried using:

- (void)chooseBackgroundImage{
if(slogansGenerated % 10 == 0){
    int chooseBackgroundImage = arc4random() % 7;
    while(chooseBackgroundImage == oldChooseBackgroundImage){
    switch (chooseBackgroundImage) {
        case 0:
            backgroundImage.image = [UIImage imageNamed:@"CyanToYellowBackground.png"];
            break;
        case 1:
            backgroundImage.image = [UIImage imageNamed:@"GreenToBlueBackground.png"];
            break;
        case 2:
            backgroundImage.image = [UIImage imageNamed:@"OrangeToGreenBackground.png"];
            break;
        case 3:
            backgroundImage.image = [UIImage imageNamed:@"OrangeToPurpleBackground.png"];
            break;
        case 4:
            backgroundImage.image = [UIImage imageNamed:@"PurpleToCyanBackground.png"];
            break;
        case 5:
            backgroundImage.image = [UIImage imageNamed:@"RedToBlueBackground.png"];
            break;
        case 6:
            backgroundImage.image = [UIImage imageNamed:@"YellowToRedBackground.png"];
            break;
    }
    int oldChooseBackgroundImage = chooseBackroundImage
  }
}

But nothing seems to work. Is there any way to create a non-repeating random number?

Jojodmo
  • 23,357
  • 13
  • 65
  • 107
  • i think i know what you want, add a iVar, ie currentSelection, then use an if statement, check that the current pic is newly selected pic – DogCoffee Oct 20 '13 at 05:35

3 Answers3

2

I recon you're looking for something like this.

-(int)getNonRepeatedRandom{
    int randomNumber = -1;
    do{
        randomNumber = arc4random_uniform(7);
    } while (randomNumber == oldRandomNumber);
    oldRandomNumber = randomNumber; //set the random number to old random so you can check it on the next run.
    return randomNumber;
}

oldRandomNumber will have to be an iVar for this to work though.

You should use arc4random_uniform instead of arc4random modulus to get rid of modulous bias.

David Wong
  • 10,284
  • 3
  • 39
  • 34
  • This is what I've been trying to do... using `!=` in the while statement makes a ever-going do-while loop, and using `==` never changes the number – Jojodmo Oct 20 '13 at 16:03
  • Oops I made a logical mistake. This code does work fine though. It is slightly more random than the accepted answer. – David Wong Oct 20 '13 at 21:15
  • I actually do use arc4random_uniform now. Even though I don't fully understand exactly why it would be any more random, or better than arc4random(). Thanks though! +1 – Jojodmo Oct 21 '13 at 03:00
  • Check out modulo bias here http://stackoverflow.com/questions/10984974/why-do-people-say-there-is-modulo-bias-when-using-a-random-number-generator also uniform is easier to use. – David Wong Oct 21 '13 at 04:33
2

The following is probably random enough for you needs:

First add an instance variable, say, lastChosenBackgroundImage.

After:

int chooseBackgroundImage = arc4random() % 7;

add:

if(chooseBackgroundImage == lastChosenBackgroundImage)
   chooseBackgroundImage = (chooseBackgroundImage + 1) % 7; // same as last time, move to next choice
lastChosenBackgroundImage = chooseBackgroundImage; // remember for next time

This does mean that picking the next image is twice as probable as picking any of the other ones, but I suspect that will not be a significant issue for your use case.

CRD
  • 52,522
  • 5
  • 70
  • 86
0

Use this utility function to give you random integers between a range (in your case 0 and 6) -

#define MAX_ATTEMPTCOUNT 10
// Provides a random number between the range (both inclusive).
+ (int)randomIntegerInRange:(int)fromInt toInteger:(int)toInt excluding:(NSArray *)excludeNumbers {
    NSAssert((toInt - fromInt) > 0 && (!excludeNumbers ? YES : (toInt - (fromInt - 1)) >= [excludeNumbers count]), @"Invalid range");
    static int randomAttempts = 0;

    srandom(time(NULL));
    int randomInteger = fromInt + random() % (toInt - (fromInt - 1));

    if (excludeNumbers != nil) {
        for (NSNumber *number in excludeNumbers) {
            if ([number intValue] == randomInteger) {
                if (randomAttempts == MAX_ATTEMPTCOUNT) {
                    // Reached the maximum attempt count to get the random number but failed to find one.
                    break;
                }
                else {
                    // Recursive call to get obtain the next number.
                    ++randomAttempts;
                    randomInteger = [self randomIntegerInRange:fromInt toInteger:toInt excluding:excludeNumbers];
                }
                break;
            }
        }

        if (randomAttempts >= MAX_ATTEMPTCOUNT) {
            // Pick up the first number that's not there in visited words.
            randomAttempts = 0; // Reset the counter for next attempt.
            randomInteger = fromInt;

            for (; randomInteger <= toInt; ++randomInteger) {
                bool found = NO;
                for (NSNumber *number in excludeNumbers) {
                    if ([number intValue] == randomInteger) {
                        // Found the number.
                        found = YES;
                        break;
                    }
                }
                if (!found) break;
                else continue;
            }
        }
    }

    return randomInteger;
}

Add the returned integer in an array (array of excluded numbers) which is actually passed as parameter (excludeNumbers).

Let me know if any issue (I made it for one of my project so may not completely suit your need so feel free to modify it or ask me)

Ashok
  • 6,224
  • 2
  • 37
  • 55