How We Learned to Cheat at Online Poker: A Study in Software Security (1999)
cigital.com
cigital.com
cards = range(52)
shuffled = []
while len(cards)>0:
shuffled.append(random.choice(cards))
cards.remove(shuffled[-1])
return shuffled
which should be, given a good randomness, literally equivalent to drawing randomly from a pool of 52 cards to form a deck. Is this somehow less efficient than their algorithm? for (i is 1 to 52)
Swap i with random position between i and 52
After i iterations, the first i entries are your "shuffled", and the last 52 - i entries are your "cards". "random.choice(cards)" corresponds to picking a "random position between i and 52".When you use your language's random function, you are getting a pseudorandom generator. As noted in the article, they were able to figure out the seed for the random function. Once you know the seed, the game is over. The adversary can now figure out the exact shuffled deck.
Also see: http://ericlippert.com/2013/05/06/producing-permutations-par...
Easy way to shuffle a deck is just to give each card a random 32-bit index and sort. You don't need to do anything fancy to get them shuffled up. The problem is, if your random number generator is predictable then the algorithm doesn't matter.
It is not just the predictability of the generator that is the issue (all PRNG are predictable really), what really matters is the size of the seed state, which should vastly exceed the number of value shuffles (52! - a huge number).
Depending on the array implentation, adding and removing elements is often an O(n) operation, which isn't terribly efficient. The Fisher-Yates method lets you get the same results without messing with the array length.
cards = range(52)
random.shuffle(cards)
return cards