Here's a category for NSMutableArray to shuffle the array in place. It does a decent job on small arrays, but note that the random number function used, mrand48()
, doesn't contain enough bits of randomness to produce all possible shuffles of a deck of cards, so there's some bias in the shuffles produced. If your game is purely for entertainment, this may be sufficient. If not, you can replace mrand48()
with a better generator.
Don't forget to seed the random number generator at start up with srand48()
.
// --- NSMutableArray+Random.h ---
#import <Foundation/Foundation.h>
@interface NSMutableArray (Random)
/// Shuffle a mutable array in place. Uses a Fisher-Yates shuffle as described
/// in http://en.wikipedia.org/wiki/Fisher-Yates_shuffle .
- (void)shuffle;
@end
// --- NSMutableArray+Random.m
#import "NSMutableArray+Random.h"
/// Return a pseudo-random unsigned integer in the range
/// [0, exclusiveUpperBound) using the mrand48() function.
/// Seed the random number state by calling srand48().
/// See http://developer.apple.com/iphone/library/documentation/System/Conceptual/ManPages_iPhoneOS/man3/rand48.3.html
static NSUInteger randomUIntegerFromZeroUpTo(NSUInteger exclusiveUpperBound) {
NSUInteger const maxUInteger = 0xffffffff;
NSUInteger largestMultipleOfMaxUInteger
= maxUInteger - (maxUInteger % exclusiveUpperBound);
// discard random integers outside the range [0, largestMultipleOfMaxUnsignedInteger)
// to eliminate modulo bias
NSUInteger randomUInteger;
do {
randomUInteger = (NSUInteger) mrand48();
} while (randomUInteger >= largestMultipleOfMaxUInteger);
return randomUInteger % exclusiveUpperBound;
}
@implementation NSMutableArray (Random)
- (void)shuffle {
for (NSUInteger unshuffled = self.count; unshuffled > 1; --unshuffled) {
NSUInteger index1 = unshuffled - 1;
NSUInteger index2 = randomUIntegerFromZeroUpTo(unshuffled);
[self exchangeObjectAtIndex:index1 withObjectAtIndex:index2];
}
}
@end