Shuffling

December 3, 2007

Pop quiz, hotshot. How would you write code to shuffle a deck of cards?

a complete deck of 52 cards, arranged by suit and in ascending order

I was thinking about this after reading Mike's card-shuffling algorithm woes:

Here's where the non-CS mind comes into play. My first thought was to generate an unshuffled deck as an array-like structure -- all cards in order by suit. Then I'd create a second array-like structure. I'd walk through each card in the unshuffled deck, pick a random number, and insert the card at the randomly selected spot in the second array. If the randomly chosen position in the second array was already occupied, I'd choose another random number, see if it was used, and so on until the random selection happened to land on a free spot. I'll call this the Random Insert approach.

It seemed an odd approach to me, but unlike Mike, I have the dubious benefit of a programming background. I went immediately for my old friend, the loop. Let's assume we have an array with 52 members representing the 52 cards in the deck.

var rand = new Random();
for (int i = cards.Length - 1; i > 0; i--)
{
    int n = rand.Next(i + 1);
    int temp = cards[i];
    cards[i] = cards[n];
    cards[n] = temp;
}

So we loop through the deck, switching each card with another card from a random position in the deck. Seems straightforward enough, although I do wish there was a built in Swap command in the C# language to simplify the code a bit. It's eerily similar to the Knuth or Fisher-Yates shuffle, which doesn't mean I'm particularly smart, but that shuffling is an easily solved problem.

Or is it? This looks correct; there's nothing obviously wrong here. But there are two problems with this code. Can you see them?

The first problem is right here:

new Random();

Computers are lousy random number generators. Any shuffling you do, whatever the algorithm, will only be as good as your random number generator. So if you're running, say, an online casino, you need to be very careful when you start throwing around the word "Random" in your code. If you aren't careful, there will be.. problems.

The flaw exists in the card shuffling algorithm used to generate each deck. Ironically, the code was publicly displayed at www.planetpoker.com/ppfaq.htm with the idea of showing how fair the game is to interested players (the relevant question has since been removed). In the code, a call to randomize() is included to produce a random deck before each deck is generated. The implementation, built with Delphi 4 (a Pascal IDE), seeds the random number generator with the number of milliseconds since midnight according to the system clock. That means the output of the random number generator is easily predicted. A predictable "random number generator" is a very serious security problem.

By synchronizing our clock with the clock on the online casino and hitting the "shuffle" button, our program can calculate the exact shuffle. That means we know all the cards that have yet to appear, everyone's hand, and who will win. The screen shot below shows the information displayed by our program in realtime during an actual game. Our program knows what cards are to appear in advance, before they are revealed by the online game.

To be fair, this was 1999. I'd assume most online casinos have hired competent cryptographers and statisticians by now. With the ever looming specter of insider cheating and poker bots, they'd be fools not to.

The second problem with this code is that it's too complicated. Eric "purplicious" Lippert explains why, in his own inimitable way:

The standard way of implementing this algorithm is: associate each card with a random real number between 0.0 and 1.0. Sort the list based on its associated number. That's O(n log n) and has no bias.

As it turns out, the easiest way to implement a shuffle is by sorting. It's not exactly faster, as the typical sort is O(n log n) compared to the O(n) of the Knuth Fisher-Yates shuffle algorithm. We'll just sort by a random number-- in this case, a GUID.

var cards = Enumerable.Range(0, 51);
var shuffledcards = cards.OrderBy(a => Guid.NewGuid());

So we can ultimately implement a secure, unbiased shuffle as a one-liner in a modern programming language.

Which proves.. well, nothing, I suppose, but like so many other programming problems, there are a lot of ways to get shuffling wrong if you're not careful.

Posted by Jeff Atwood
142 Comments

My apologies, indeed, I conflated Knuth's algorithm (which has no bias) with the algorithm on Mike's blog (which does have bias). Knuth's algorithm has n! possible paths, each to a distinct output, each equally likely. Julian's algorithm has n^n possible paths to n! distinct outputs, and since n! does not usually divide n^n evenly, some of those have to be overrepresented.

Eric Lippert on December 6, 2007 8:24 AM

All the talk about random number generators aside, I think we've lost sight of something here: How physical shuffling is done. The "perfect" shuffle algorithm actually shuffles like a casino dealer would, not in some pseudo perfect mathematical sense. Standard gaming rules dictate 7 shuffles in a standard 2 halves fanned back into 1 style with a cut at the end. This means that any card starting at the dead bottom of the deck has no way of making it all the way to the top of the deck, and vice versa prior to the cut. In short, the shuffle is not a true random reordering by any stretch.

Anyway, here's my take on how I'd do this:

1) Start with 52 cards in an array.
2) Split the deck at a "random" half somewhere between the 1/3 and 2/3 marks with weighting towards the middle.
3) Walk the index alternating between your start position and your half position reading 1-5 cards at a time at random (see 3a)
3a) The random algorithm used would need to have 2 weights included. first, a base weight towards 2 or 3 for realism. Second, a calculated weight based on the half of the decks relative remaining size as compared to the other halfs remaining size. This "corrects" instances of one side of the deck running out of cards significantly faster than the other, as any physical shuffler would also do.
4) Repeat steps 2-3 for a total of 7 iterations
5) Allow the player a way to "cut" the deck, or calculate a "random cut anywhere in the deck, weighted towards center.

Not in code because, honestly, I don't have time right now. Maybe I'll do it on the quick and dirty via Ruby. I think this is closer to reality of a shuffle, though.

vince on December 6, 2007 8:44 AM

Sorry to ask a silly question in the midst of such heady discussion, but I just can't figure out the snippet:

var cards = Enumerable.Range(0, 51);
var shuffledcards = cards.OrderBy(a = Guid.NewGuid());

- What the heck is a?
- Where is/are the other params to OrderBy (docs say this method needs at least 2)
- In the lambda expression, how can a be a param to NewGuid which doesn't take any?

Card carrying 80% member on December 6, 2007 9:31 AM

Re: The first problem

Several people have mentioned using implicit user input data as the actual source of random numbers (mouse coordiantes, key press distributions, etc). I think that in many cases, however, this is still vulnerable to reverse-engineering by a resourceful hacker. Plus your range of possible values is limited by the granularity of the implicit user input data.

Instead I suggest to just pull and discard numbers from your PRNG in a core loop somewhere in your code. Maybe a message-processing loop, or when waiting on user input. Just make sure it's somewhere that gets run on a fairly constant basis anytime the app is running. This is a simple way to ensure there are no "synch points" in your app that a hacker can count on to line up their PRNG with your app's. Because you're constantly generating numbers and there's no way to know how many will be generated between the last time you actually used one and the next time you will actually use one.

WaterBreath on December 6, 2007 10:40 AM

Re: Bias
At first I thought your algorithm had a bias because (to paraphrse Peter) you're choosing a card to swap with in the range [1..X] instead of using the the range [1..52]

wikipedia on Knuth's Shuffle (http://en.wikipedia.org/wiki/Knuth_shuffle) gives a good description as to why this _isn't_ the case. In brief, swaping with a card in the range [1..52] gives 52^52 possible swap sequences, but there's only 52! possible decks. 52^52 52! so there are multiple sequences leading to a particular deck. 52^52 is not divisible by 52! so some decks have more sequences leading to them then others.

Thanks for a great article!

Mike on December 6, 2007 11:18 AM

Catto must be sick, how long has it been since he missed a post?

Craig on December 6, 2007 12:41 PM

Thinking about my comment I made before, and using a complicated hash table (which is very interesting to learn) to sort your data into, and then take it out in sequential order is a bad way to do it. Of course it was the only thing I could think of on my 15 minute break at work.

Using your GUID idea, just adding the randomly generated number to the GUID would guarentee a "good enough" random dispersion with a unique number.

#If random number is a long integer Then
randomIndexOfCard = random() + (getGUID() mod [larges random number possible]);
#Else
randomIndexOfCard = random() * sizeof(long int) + getGUID();
#Endif

Loop until each card indexed and sort the cards as a shuffle.

Then all you have to do is shuffle, rince, and repeat! (7 times sounded like a good number :)...

James on December 7, 2007 3:20 AM

Eh Jeff, you disapoint me!
Do you really need to show algo-complexity when N=52? Let asume you do not do a N^8 algo, and it OK with that.

Second point is: Random() sucks for cryptography but it is enough for human's game. Assuming no one can know the initial generator number, rand.Next() is ok.

Tell me if i wrong, but i belive if i give you this algo:
Random rand = new Random(x);
while(true)
{
Console.WriteLine(rand.Next(100)%2 == 0);
}

And i give you the 50000 first results:
true
false
false
false
false
true
true
...
Do you will be able to retrieve the "x" number?
I think the answer is no.

In this case the only problems for a casino is to find a good "x" that now one can predict. I have no idea of how to.

It seem to me that all of your sort carts algo are OK. So the best one is the easier to understand.


Olivier de Rivoyre on December 7, 2007 9:35 AM

Mmm, Java has a shuffle functin, I had no idea.

Wrote my own shuffle mechanism which is exactly the same as the one posted...

I guess it does prove that it's easy ;) Although I was pleased that it went in O(n).

Carra on December 8, 2007 3:16 AM

How, pray tell, do you intend to make your "pull and discard" algorithm non-deterministic?

Maybe I am being naive here... But if so could someone explain what about my proposal is any less deterministic than what others have proposed?

How could someone predict how many numbers will be discarded unused while, for example, the app is waiting for the user to click a button? The actual numbers used for the randomness-critical app features will not be consecutive numbers generated by the PRNG. How far we jump forward in the numbers we actually use depends on how many cycles of processor time are actually spent in that loop, discarding numbers. I'm sure this isn't completely unobtainable info, but I don't think it is any easier than, say, hooking into the mouse location data.

I'd guess this has a similar effect to reseeding your generator often. But, not knowing a whole heck of a lot about the math behind PRNGs... maybe you're saying this somehow makes the numbers less random?

Waterbreath on December 8, 2007 9:27 AM

Perhaps you can use a random timing?
But, oops, that requires a random number, which requires a non-deterministic PRNG... in other words, you need a non-deterministic PRNG to build your non-deterministic PRNG...

If I'd read the comment a little more carefully, I would have quoted his question in my last comment, because that is what I am answering.

Again, I'm not saying it's perfect. It can be hacked. I'm just saying that it's no worse than other people's more complex solutions.

WaterBreath on December 8, 2007 9:32 AM

For all you old-timers out there, heres some code you can run on your VIC 20 to shuffle those cards...

...
5 cntr%=1
7 REM ** cntr% holds the order in which cards are drawn
10 DIM a(52)
13 REM ** 52 cards in a standard deck
15 REM ** initialise them to 0
17 FOR c=1 TO 52:a(c)=0: NEXT c
19 REM ** pick a card
20 i%= INT( RND(1)*52)+1
25 REM ** look to see if this item can be inserted
30 IF a(i%) 0 GOTO 20
35 a(i%)=cntr%:cntr%=cntr%+1
37 REM ** if we haven't picked 52 cards, go again
40 IF cntr% 53 GOTO 20
45 REM **
47 REM ** display results
49 REM **
50 FOR z=1 TO 52: PRINT a(z): NEXT z
...

Not so much Try and catch, more like pray and hope ;o)

Steve on December 9, 2007 4:38 AM

@Waterbreath

... could someone explain what about my proposal is any less deterministic than what others have proposed?

Determinism is all I was pointing out. Anything that is deterministic makes up no part of the randomness in the result.
eg. Giving a PRNG it's own output as a new input seed does nothing for the randomness (though some generators still do this for security reasons). Ie. anything that you know to be deterministic may as well be removed.

How could someone predict how many numbers will be discarded unused while, for example, the app is waiting for the user to click a button?

Phrase the question slightly differently: where is the true source of randomness?
If you said "the timing of the mouse click", you'd be right. Thus, it is the only thing an attacker needs to control, eg. by stuffing a mouse-click event into the queue by some means, and voila, complete compromise; the attacker knows the exact state of the PRNG. Bugger.

Conclusion: pulling numbers from the PRNG did nothing to increase the randomness, you were actually relying solely on the mouse click for all your entropy.
In other words: you may as well not bother with pulling numbers because it's deterministic. The mouse-click was good, its (one of) your source(s) of randomness; when it occurs you can roll the timing into the PRNGs input. It will contribute whatever tiny entropy it might have (possibly none if the attacker has corrupted it - but that shouldn't matter because you have many other sources... right?).

I'd guess this has a similar effect to reseeding your generator often...

Ah, I see the problem. You are accustomed to the cute little things referred to as "RNGs" in many standard libraries; you seed them once and then use them forever. Those are a poor shadow of a PRNG - you basically just shouldn't ever use them. They are, often, trivially easy to brute-force attack.

A real PRNG has inputs as well as an output. "seeding" as you know it, should be occurring frequently in an unending stream, never ceasing, from many sources.

So... what are the sources?

Anything.

If you aren't certain of the value of a source (and you shouldn't be, because who can accurately judge the entropy in a mouse-click?), stuff it in anyway. A real PRNG is unaffected by a compromised entropy source because its output is the ENTROPY SUM of it's inputs. Thus, if one source is compromised (or simply deterministic from the outset), it is merely a source with zero entropy; it is not detrimental in any other way (so long as the remaining sources sum to the level of entropy required).

Andrew R on December 9, 2007 7:34 AM

"The standard way of implementing this algorithm is: associate each card with a random real number between 0.0 and 1.0. Sort the list based on its associated number. That's O(n log n) and has no bias."

Couldn't you use integers instead of real numbers, then use a non-comparison sort like bucket/radix sort?

Tom Robinson on December 11, 2007 12:04 PM

this is my way of getting a random number (please don't criticize the memory access part, simply ACCESSING memory is safe)

When the app starts, itll do a simple srand (i use C/C++) with the parameter of the the time in milliseconds divided by how long the app has been running. it then mallocs an array (no calloc, thatll make everything 0) the length of the random number. It then finds out how much time has passed since the last time we checked the apps run-time. the difference is modulated by a number produced by a call to rand() untill it is a number small enough to fit in the allocated memory. Then access the that entity of the array and you will get a random number from bytes that arent even part of your programs. If its 0, the program retries with a dif rand number until a successful number is obtained

seems long and complicated, but doesnt use any long or system specific procedures and is quite fast since all are functions are part of the language and simple math/memory operations

JavaGuy147 on May 12, 2008 4:39 AM

They could collect a seed like truecrypt does with mouse moves and/or some mandelbrot point.

J on June 22, 2008 10:05 AM

I'd just do the calculation for each card as required.

Less tampering possible I'd think

Pi on August 24, 2008 9:49 AM

This seems to do the trick very well for me, ported from an old ass javascript shuffle prototype I made a loooooong time ago.

One thing I didn't understand with it though, is if I used
r.Next(0, m_cards.Count - 1) which would have been the true final index, it stuck itself in an infinite loop, oh wellz. works now =)

public void Shuffle()
{
Random r = new Random();

Listint used = new Listint();
ListCard temp = new ListCard();
do
{
int index = r.Next(0, m_cards.Count);

while (used.IndexOf(index) -1)
index = r.Next(0, m_cards.Count);

used.Add(index);
temp.Add(m_cards[index]);
}
while (temp.Count m_cards.Count);

m_cards.Clear(); // not necessary
m_cards = temp;
}

RRyyaann on September 3, 2008 10:30 AM

why did my msg get removed x.x

RRyyaann on September 3, 2008 10:50 AM

okay and now it's not. what the heck.

RRyyaann on September 3, 2008 10:51 AM

now what I was gunna say before my browser went screwy.
how could you possibly 'predict' my post example?

you run that code once, twice, three times, they're all different. That means somewhere in the world. Somebody trying to sync their generator to the seed of the random() their code is going to produce a different result.

Even being that it's based on a random number between 0 and 52, sure there are limited numbers of output. But being that it makes sure it never reuses the same index before placing the card back in the deck makes it very hard to predict the actual output... by any 'algorithm'.
Now I'm definitely not the greatest programmer in the world. But it seems so farfetched that a person (or code) could predict:
a) the randomly generated number (more possible)
b) the next number to be placed in 'used' (less possible)

Of course, we all program to learn (or make money) so please, if I am wrong, I wanna know why =)

RRyyaann on September 3, 2008 11:04 AM

make an array of 52
assign a random number between 1 a 100000 to each entry
assign the first card to the highest number, the second card to the second highest number, etc.

Rob on September 19, 2008 5:19 AM

I am just a poker player who is researching RNG integrity as it relates to my online poker play.I have no programming experience nor a high education.I have been playing on pokerstars for 3 yrs and have been suspect of the randomness for a long time.Most arguments in this area are about other players being able to predict the rng and act accordingly to win.Thus, all this hullaballoo on how to create a truly random shuffle to nullify these hackers attempts to steal me hard earned dollars.All of this seems to me to be smoke in eyes of the masses.Corruption has always been seeded at the top of the food chain and not us lowly joe's tryin to make a buck to feed our families and pay our bills.I am far more concerned about corruption at the highest levels within my arena, ie, Pokerstars, Intel, and the 2 companies that certified their RNG.Even if pokerstars itself has no part in this conspiracy theory, although they clearly stand to benefit the most from the ability to control cards dealt to players and when, the 2 companies they hired to verify integrity of their Intel RNG were given all their source code and means of seed generation, meaning those employees who performed such tests could take that information and develop code to create an ATM for themselves via pokerstars and/or its players.As for Intel, if they are out to screw us then we are all lost.I could go on and on about my conspiracy theories as to Pokerstars and how they do it, but I really only wanted to make two points about all that I have read here as it relates to online poker, the shuffle, and collusion:
1. Being that the cards are dealt one at a time to the players in a circular motion, if the cards are too random in a shuffled deck about to be dealt, wouldn't that be creating a greater likelihood of players getting dealt pairs and suited connectors, and that those same cards would fall on the ensuing flop, turn, and river? ie trips, flushes, 2 pairs, and full boats.Like if all four aces were stuck together at the top quarter of the deck then 4 out of 9 or 10 players would receive one ace and a random card, not pocket aces.I think that these decks are over-shuffled and that is creating these common instances of pocket rockets, trips, full houses, and quads even.Ive seen quads way to many times.This also creates a much more exciting game for the players.We all want to hit those big hands, not just win playing a solid hand.It would seem like a win win scenario for all involved to taint the rng just enough to make play more exciting at their website verses another... right? I ask questions I already know the answer to, I just wonder if anyone agrees with me.

2. If Pokerstars, or any other online gaming site, its employees and programmers, were out to control the game and the outcomes for profit, above and beyond that which they already make with the odds in their favor, then who would know it? Who could prove it? Who could stop it?
Who would even care except for the idiots like myself who keep playing the machine believing its fair and random and that I just need to improve my play ?

Lastly, I just want to say that overall I have made more money than I have lost playing online poker and should be the last person to raise these questions or even care, but I really feel as though something is wrong with the RNG that I have been intimate with for many years and if so, then that is wrong,whether or not it has negatively affected me.I feel that these RNG's should be built by and subject to the scrutiny of people like yourselves, much as how Linux flavors have been developed and scrutinized by the knowing public and not a private multi-million dollar company who's employees cant be trusted, nor the CEO, who would gladly take a % or a payoff to say the RNG is good.

Rich on November 29, 2008 2:20 AM

when writing a card dealer are there any requirements other than:

1. not predictable
2. during a hand don't deal the same card twice ;)
3. the cards should be dealt randomly

dbasnett on February 14, 2009 3:24 AM

perfect shuffle in perl :

sub shuffle {
my @a = ();
my @b = ();

return @_ if (@_ 2);

for (@_) {
if (random_bit()) {
push @a, $_;
} else {
push @b, $_;
}
}

return (shuffle(@a), shuffle(@b));
}

This is similar to the radix sort algorithm with random numbers.

random_bit returns a boolean. This bit can be read from /dev/random for true randomness on linux.

GuB on March 11, 2009 10:30 AM

Very cool app. Can you tell me where to download the Help files? Apparently they didn’t make it during the install process, so it won’t load them. Thanks!

sohbet on July 6, 2009 5:46 AM

Thank you very muCh

sohbet on July 19, 2009 9:54 AM

Thanks for addressing this issue so quickly, Dr. Lessig. I thought something was fishy in that article.

chat siteleri on July 27, 2009 8:27 AM

So the OrderBy criteria:
- var shuffledcards = cards.OrderBy(a => Guid.NewGuid());
is basically equivalent to
- Random rand = new Random()
- var shuffledcards = cards.Sort((a,b) => rand.Next(0,2) == 0 ? -1 : 1);
since a new guid is created on every comparison. So it's basically sorting with every Compare returning a random result - which isn't the same as the sort Eric mentioned - it will likely be biased based on the sorting algorithm used.

Kumar on July 30, 2009 1:13 PM

thank you was a useful article...

bedava sohbet on August 5, 2009 2:42 AM

Thanks a load for the stats. Haven’t seen anything nearly as comprehensive or useful anywhere else.

sohbet on August 16, 2009 9:47 AM

I can’t wait for the day when web design programs are as easy as layout programs for print!

chat on August 16, 2009 1:16 PM

how can i divide the deck into three parts and then shuffle them?

mn480591 on August 20, 2009 1:02 PM

A possible source of randomness that is available to everyone is environmental RF noise. This can be sampled off of the line input from the sound card. Best if it is hooked up to a radio between AM stations, but even with nothing plugged into it, there is usually a little noise. In an actual casino, a microphone may be a good source as well. What is needed is a real world (as opposed to computed) source because the real world is not predictable. Sample this several times, and combine the results into a seed.

Not quite radioactive decay, but pretty good for the price.

Grant Johnson on February 6, 2010 10:14 PM

Any algorithum is going to be predictable where are "random" numbers should be unpredictable. So there is a problem right there.

Sampling noise and mouse click helps makes the output more unpredictable, thus the resulting number should be unpredictable.

Of course there are many ways to shuffle cards. Throw all cards on table and move them around with your hands. Stack, cut and deal. You could also try to mimic that behavior and consider the deck shuffled.

Jon Raynor on February 6, 2010 10:14 PM

There is also probabilities to be considered. If decks are shuffled, probability says 1/52 chance of first card being an Ace of Spades. Now you may shuffle a thousand times and not get an Ace of Spades as the first card, but with a large amount of attempts (and I do mean large), the percentage should converge to 1/52. Otherwise, someone may think your shuffle is rigged.

So not only does you shuffle have to be random, but its results should converge to known probabilities over time.

Jon Raynor on February 6, 2010 10:14 PM

Two thoughts that are being addressed here:

1) If you are doing anything you care about, research the random number generator (PRNG) you are using. The best ones will have passed a number of theoretical tests to deterimine that they indeed have no pattern. Fun to note that one of the quick litmus tests is to generate a large number of 5-card poker hands and see how the result aligns to computed probabilities.

2) Using noise and other environmental sources is tempting. However, I think this creates a maintenance burden to ensure that the quality of the random number stream is high and stays high!

Jason B on February 6, 2010 10:14 PM

As others have said, the problem with Random is often the seed. .NET's random number generator is pretty decent if you use an unpredictable seed:
Random rand = new System.Random(Guid.NewGuid().GetHashCode());

For something like online gambling where significant money's involved, the crypto RNG would be better. In that case, you'll need to give up on a one-liner (unless it's one unreadable line), since the RNG returns an array of bytes.

http://msdn2.microsoft.com/en-us/library/system.security.cryptography.rngcryptoserviceprovider.aspx

Jon Galloway on February 6, 2010 10:14 PM

I know this is a late comment, but I have something to add to this. I don't have experience with deck shuffling algorithms, however I can't really see much problem here. Even though random and psuedo random coding is sketchy at best, when it comes to deck shuffling, it shouldn't be difficult to figure out how to randomize the deck.

Take real world shuffling with the hands, you roughly cut the deck in half, then attempt to merge them so that the deck is in staggered as perfectly as possible. However in real life it doesn't happen with perfection, and therefore there are always a few to several cards that are "misplaced" in the pattern. repeat until one is "comfortable" with the randomized nature of the deck.

One could simply emulate this with a few random routines. Literally randomly deciding which is the next card to merge into the new deck from the split decks.

If one loops the deck through something like this, the results should be staggeringly more random than initially suspected.

dim deck
for i = 0 to 12

main(

Scot McPherson on February 6, 2010 10:14 PM

I would like to have a preview first, I hit the post button accidentally while writing thise. Though I suppose I should have written in a text editor first.

I don't think you need the rest to understand what I mean though.

Scot McPherson on February 6, 2010 10:14 PM

This is a bit of a tongue-in-cheek suggestion, but I've actually used it a few times.

As many posters have pointed out, choosing a good seed value can make all the difference. My method is called Pr0nSeed. I select an image from a library of photos I've taken. (I've yet to run out, but I could shuffle them based on (say) file-size and dimensions and a random component, and then cycle through the newly shuffled list).

Then I use the built-in RNG to select a pixel (in a variant of this, you could simply cycle through each pixel in sequence, but that depends on your image -- continuous tone gradients can be predictable). Then I build a seed using the R, G, and B values of the pixel that results.

Obviously the type of images you use will affect the quality of your seed -- for one thing, the less compression and the less post-processing, the better.

You could even generate the "random" number directly from the RGB values without using the RNG to generate X and Y values, just by iterating through the pixels.

Another thought to improve quality (i.e. unpredictability): If you have a library of images you can (in a pre-process) run through them and toss out those that don't meet a certain threshold for the number of distinct colors (i.e. an overexposed picture of a white piece of paper would be fairly useless).

Also, you could pick R, G, and B values from separate pixels, not the same one.

This seeding algorithm relies on the idea that you own a collection of images that no-one else has access to. If you take your own pictures (particularly high-res ones) and secure them decently, you can rely (as far as I can see) on your sequence being fairly unpredictable.

I called it Pr0nSeed because when I originally came up with I needed a large library of images, so I used my, uh, downloaded adult-themed images :) Now I use a collection of photos I've taken myself which are far more boring but contain less continuous-tone imagery -- stuff like sand, gravel, trees, etc.

Ultimately this algorithm uses the system RNG (or a library RNG) simply as an indexer into a large array (the image) of unpredictable numbers. The current picture is changed every "x" calls to Random(), where "x" represents a tradeoff between possibly repeating values (due to a poor RNG or an image with too few distinct colors) and performance.

Not being a mathematician (or, indeed, even having a CS qualification of any kind) I'd be interested in comments on potential flaws in this approach (I'm sure there are many).

cmza12 on February 19, 2011 8:43 AM

I hope this comment will bubble up.

Post has a lot of good details, but there is a problem with the second code in C#.

var cards = Enumerable.Range(0, 51);
var shuffledcards = cards.OrderBy(a => Guid.NewGuid());


There are two problems with it covered by Eric Lippert:

Do not use a random function as a comparator and feed that to a sorting algorithm. Sort algorithms are permitted to do anything they please if the comparator is bad, including crashing, and including producing non-random results. As Microsoft recently found out, it is extremely embarrassing to get a simple algorithm like this wrong.

Do not sort on a "random" GUID as your key. GUIDs are guaranteed to be unique. They are not guaranteed to be randomly ordered. It is perfectly legal for an implementation to spit out consecutive GUIDs.


Source: http://stackoverflow.com/questions/5519385/calling-a-list-of-methods-in-a-random-sequence/5519621#5519621

Kind Regards,
Lukas M

Lukas M on April 13, 2011 3:35 AM

«Back

The comments to this entry are closed.