Question

I am trying to shuffle a deck of cards in my app and I use the following code. Will this sufficiently randomize the deck? I am almost certain is will just want another opinion. Thanks!

for (int i = 0; i < 40000; i++) {
    int randomInt1 = arc4random() % [deck.cards count];
    int randomInt2 = arc4random() % [deck.cards count];
    [deck.cards exchangeObjectAtIndex:randomInt1 withObjectAtIndex:randomInt2];

EDIT: In case anyone is wondering or should come across this in the future. This is what I have gone with to shuffle my deck of cards, it is an implementation of the Fisher-Yates Algorithm. I got it from the post @MartinR suggested below which can be found here: What's the Best Way to Shuffle an NSMutableArray?

NSUInteger count = [deck.cards count];
    for (uint i = 0; i < count; ++i)
    {
        // Select a random element between i and end of array to swap with.
        int nElements = count - i;
        int n = arc4random_uniform(nElements) + i;
        [deck.cards exchangeObjectAtIndex:i withObjectAtIndex:n];
    }
Was it helpful?

Solution

Your code should work rather good if [deck.cards count] < 40000 but following is better

for (int i = [deck.cards count] - 1; i > 0 ; i--) {
    int randomInt1 = arc4random_uniform(i + 1);
    [deck.cards exchangeObjectAtIndex:randomInt1 withObjectAtIndex:i];
}

from docs:

arc4random_uniform() will return a uniformly distributed random number less than upper_bound. arc4random_uniform() is recommended over constructions like ``arc4random() % upper_bound'' as it avoids "modulo bias" when the upper bound is not a power of two.

OTHER TIPS

Here is the Fisher-Yates algorithm properly implemented. And yes, it will sufficiently randomise your array, I've used it many times and it's just wonderful!

NSUInteger count = [deck.cards count];
if (count > 0) {
    for (NSUInteger i = count - 1; i > 0 ; --i) {
        [deck.cards exchangeObjectAtIndex:i
                        withObjectAtIndex:arc4random_uniform(i + 1)];
    }
}

Depending on how you have implemented your deck you can use simply use Collections.sort() or you can use an ArrayList assuming your implementation is similar to the following

    ArrayList<Integer> originalDeck = new ArrayList<Integer>();
    ArrayList<Integer> randomDeck = new ArrayList<Integer>();

    //Initalize array
    for (int i = 0; i < 52; i++) {
        originalDeck.add(i, i);
    }

    //Smart Implementation
    Collections.shuffle(originalDeck);

    Collections.sort(originalDeck);

    //Long Implementation
    int i=0, max = 0;
    while (originalDeck.size() != 0) {
        max = originalDeck.size();
        i = (int) (Math.random() * max); // goes from 0 to size-1 so always in bounds
        randomDeck.add(originalDeck.remove(i));
    }
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top