0

I’ve written a code to select a random color from an NSArray, but how can I make it so that the same color doesn’t get selected 2 times in a row? Any help would be greatly appreciated.

+ (NSArray *)colors {

static NSArray *colors = nil;

static dispatch_once_t once;
dispatch_once(&once, ^{ colors = @[
//green
[UIColor colorWithRed:88.0/255.0 green:195.0/255.0 blue:98.0/255.0 alpha:1],
//yellow
[UIColor colorWithRed:246.0/255.0 green:194.0/255.0 blue:48.0/255.0 alpha:1],
//orange
[UIColor colorWithRed:236.0/255.0 green:135.0/255.0 blue:40.0/255.0 alpha:1],
//red
[UIColor colorWithRed:226.0/255.0 green:51.0/255.0 blue:40.0/255.0 alpha:1],
//blue
[UIColor colorWithRed:59.0/255.0 green:156.0/255.0 blue:218.0/255.0 alpha:1],
//violet
[UIColor colorWithRed:138.0/255.0 green:70.0/255.0 blue:165.0/255.0 alpha:1],
];
});

return colours; 
}

_selectedColor = [colors objectAtIndex: arc4random() % [colors count]];
rmaddy
  • 314,917
  • 42
  • 532
  • 579
sbco
  • 11
  • 1
  • Keep a `_previousColor`, and do the selection inside a loop until it is different. – Amadan Jan 25 '16 at 02:23
  • Yea I thought about that, but I was wondering if maybe there was an easier way to do it? – sbco Jan 25 '16 at 02:26
  • That's like four lines of code, counting the parentheses. How much easier do you want it? – Amadan Jan 25 '16 at 02:27
  • Would you mind giving me an example, when I thought about that, it seemed more complicated... – sbco Jan 25 '16 at 02:33
  • I am not great at ObjC, but something like: `first = ...; do { second = ...; } while (first != second);` – Amadan Jan 25 '16 at 02:39
  • Still not sure exactly how to do it, but I can sort of see how that could work in an if statement, thanks for trying anyway. – sbco Jan 25 '16 at 02:45
  • Err, brainfart; should be `while (first == second)`. Basically, get the first colour, then get the second colour, and do it again as long as they're the same. The `...` is the random selection you already know how to do. There should be no `if` statement, `do...while` takes care of everything. – Amadan Jan 25 '16 at 02:47
  • Alright it worked! Thanks – sbco Jan 25 '16 at 03:00

2 Answers2

1

Shuffle the array of colors and then return its elements in order. When you reach the end, reshuffle and start over. Just make sure you don't allow the last element to become the first element to avoid returning the same element twice in a row. This also guarantees that you use each color an equal number of times.

@implementation UIColor (random)

static UIColor *rgb(CGFloat red, CGFloat green, CGFloat blue) {
    return [UIColor colorWithRed:red/255 green:green/255 blue:blue/255 alpha:1];
}

void shuffle(NSMutableArray *array) {
    // Based on http://stackoverflow.com/a/56656/77567
    NSUInteger count = array.count;
    if (count < 2) return;
    // Don't allow last element to become first, so you don't get the same color twice in a row.
    [array exchangeObjectAtIndex:0 withObjectAtIndex:arc4random_uniform(count - 1)];
    for (NSUInteger i = 1; i < count - 1; ++i) {
        NSInteger remainingCount = count - i;
        NSInteger exchangeIndex = i + arc4random_uniform((u_int32_t )remainingCount);
        [array exchangeObjectAtIndex:i withObjectAtIndex:exchangeIndex];
    }
}

+ (instancetype)randomColor {

    static dispatch_once_t once;
    static NSMutableArray *colors;
    static int nextColorIndex;
    static dispatch_queue_t queue; // serializes access to colors and nextColorIndex
    dispatch_once(&once, ^{
        colors = @[
            rgb(88, 195, 98), // green
            rgb(246, 194, 48), // yellow
            rgb(236, 135, 40), // orange
            rgb(226, 51, 40), // red
            rgb(59, 156, 218), // blue
            rgb(138, 70, 165), // violet
        ].mutableCopy;
        shuffle(colors);
        queue = dispatch_queue_create("UIColor+random.randomColor", 0);
    });

    __block UIColor *color;
    dispatch_sync(queue, ^{
        color = colors[nextColorIndex++];
        if (nextColorIndex == colors.count) {
            nextColorIndex = 0;
            shuffle(colors);
        }
    });
    return color;
}

@end
rob mayoff
  • 375,296
  • 67
  • 796
  • 848
-1
NSArray *colors = [NSArray new]; // ... //your code here
UIColor *selectedColor;

UIColor *randomColor; // your result

//choose random color but don't repeat the last one
randomColor = selectedColor;
while (randomColor == selectedColor) {
    randomColor = [colors objectAtIndex: arc4random() % [colors count]];
}
Krodak
  • 1,493
  • 14
  • 21
  • any comment on downvote...? With my solution you can't choose the same color as 'selectedColor' (so previously chosen), so you can't have 2 same color in the row. – Krodak Jan 25 '16 at 16:25