How would you write a shuffle algorithm?
As I'm beginning to write my card game application, I've approached the unit test where I need to shuffle the deck. I've implemented it based on Knuth's Shuffle algorithm. My question is, what are some clever ways that other programmers have implemented it?
My current implementation works like this.
- Put all 52 cards in an array
- For Loop starting at element 51, working backwards
- Generate random number between 0 and loop element index
- Swap current element card with the element at the random index generated in previous step
- Finish when loop index reaches the zero element.
Delima with current implementation
- Is there a bias with generating a random number between 0 and the loop index? I'm doing so with java.util.Random
- Would multiple shuffle iterations over the deck solve this?
- Is it worth refactoring the shuffle algorithm to use the strategy pattern so I can have multiple implementations of shuffle? After all, this is a simple command line game, not Harrah's next killer online gambling app.
Re: How would you write a shuffle algorithm?
Re: How would you write a shuffle algorithm?
Re: How would you write a shuffle algorithm?
Re: How would you write a shuffle algorithm?
Let's say you want to shuffle the numbers 0 to 51 (each number referring to a card in your deck). First create an array of 52 booleans, setting each one to false (call this array b[]). Now generate a random number from 0 to 51 (inclusive). Call this number n. Update your array of booleans so that b[n] = true. The value of n is the first number in your shuffled list.
Generating subsequent entries for your shuffled list is handled slightly differently. First, decrement the upper value of your range of numbers, so the second number is between 0 and 50, and so forth. Once you have this number (let's call it m), find the mth entry in b[] which has a value of false. The index for that entry is the new value to add to your list of shuffled numbers. Mark that value of b[] as true. Repeat.
The process is simpler for the first step because all entries in b[] are false, so if your random number is, say, 3, you already know the 3rd entry of b[] is the 3rd false entry, so 3 is the first shuffled number. If the second random number is 3 again, then the second shuffled number is 4. In practice, things work slightly different since it's all zero-based.
I have code that demonstrates this, so let me know if you want a copy.
Re: How would you write a shuffle algorithm?
The implementation of the blog author is also wrong (or rather, overkill): you only need to loop until 26 to get a perfect shuffle.
Re: How would you write a shuffle algorithm?
Re: How would you write a shuffle algorithm?
Here is a simple perfect shuffle:
for (int i = 0; i < 26; i++) { swap(a[i], a[random(52)] }
You can prove mathematically that it's a perfect shuffle (in average, you're guaranteed that all the cards in the deck will be shuffled over a large enough sample).
Exercise for the reader: why is 26 sufficient?
Re: How would you write a shuffle algorithm?
These issues are all covered pretty well in the Wikipedia entries for Shuffling and the Knuth_shuffle. Swapping only 26 times clearly cannot produce a perfect shuffle by a pigeonhole argument.&nbsp;
If you do 26 swaps, each with 52 possibilities, you have 52^26 possible outcomes. However, there are 52! possible sequences for a deck, which is much larger than 52^26.&nbsp; Therefore, there are some sequences that your algorithm will never generate.
Andrew
Re: How would you write a shuffle algorithm?
I was given this question for an interview and I went home and just took a first crack at it. This is what I intuitively came up with.
<font color="#0000ff" size="3"><font color="#0000ff" size="3">public
{
}
shuffledCards[counter] = next;
randomHistories.Add(next);
++counter;
}
iter =
}
}
}
</font></font><font size="3"> </font><font color="#0000ff" size="3"><font color="#0000ff" size="3">static</font></font><font size="3"> </font><font color="#0000ff" size="3"><font color="#0000ff" size="3">int</font></font><font size="3">[] Shuffle(</font><font color="#0000ff" size="3"><font color="#0000ff" size="3">int</font></font><font size="3">[] cards)</font><font color="#0000ff" size="3"><font color="#0000ff" size="3">int</font></font><font size="3"> cardsCount = cards.Length;</font><font color="#0000ff" size="3"><font color="#0000ff" size="3">int</font></font><font size="3">[] shuffledCards = </font><font color="#0000ff" size="3"><font color="#0000ff" size="3">new</font></font><font size="3"> </font><font color="#0000ff" size="3"><font color="#0000ff" size="3">int</font></font><font size="3">[cardsCount];</font><font color="#2b91af" size="3"><font color="#2b91af" size="3">IList</font></font><font size="3"><</font><font color="#0000ff" size="3"><font color="#0000ff" size="3">int</font></font><font size="3">> randomHistories = </font><font color="#0000ff" size="3"><font color="#0000ff" size="3">new</font></font><font size="3"> </font><font color="#2b91af" size="3"><font color="#2b91af" size="3">List</font></font><font size="3"><</font><font color="#0000ff" size="3"><font color="#0000ff" size="3">int</font></font><font size="3">>(cardsCount);</font><font color="#0000ff" size="3"><font color="#0000ff" size="3">var</font></font><font size="3"> counter = 0;</font><font color="#0000ff" size="3"><font color="#0000ff" size="3">var</font></font><font size="3"> iter = </font><font color="#0000ff" size="3"><font color="#0000ff" size="3">true</font></font><font size="3">;</font><font color="#0000ff" size="3"><font color="#0000ff" size="3">var</font></font><font size="3"> random = </font><font color="#0000ff" size="3"><font color="#0000ff" size="3">new</font></font><font size="3"> </font><font color="#2b91af" size="3"><font color="#2b91af" size="3">Random</font></font><font size="3">();</font><font color="#0000ff" size="3"><font color="#0000ff" size="3">while</font></font><font size="3"> (iter) {</font><font color="#0000ff" size="3"><font color="#0000ff" size="3">var</font></font><font size="3"> next = random.Next(1, (cardsCount + 1));</font><font color="#0000ff" size="3"><font color="#0000ff" size="3">if</font></font><font size="3"> (randomHistories.Contains<</font><font color="#0000ff" size="3"><font color="#0000ff" size="3">int</font></font><font size="3">>(next)) {</font><font color="#0000ff" size="3"><font color="#0000ff" size="3">continue</font></font><font size="3">;</font><font color="#0000ff" size="3"><font color="#0000ff" size="3">else</font></font><font size="3"> {</font><font color="#0000ff" size="3"><font color="#0000ff" size="3">if</font></font><font size="3"> (randomHistories.Count == cardsCount) {</font><font color="#0000ff" size="3"><font color="#0000ff" size="3">false</font></font><font size="3">;</font><font color="#0000ff" size="3"><font color="#0000ff" size="3">return</font></font><font size="3"> shuffledCards;</font>Re: How would you write a shuffle algorithm?
The other Mike's algorithm is "wrong", though (in the sense that it will not generate a perfect shuffle, which I assumed was your goal).
Re: How would you write a shuffle algorithm?
Re: How would you write a shuffle algorithm?
Re: How would you write a shuffle algorithm?
Pick a random node in the graph and change its edge to point to a node that does not already have an edge pointing to it, which in the case of the first iteration with be either the bottom or top card. Set the flag on that edge so you know it's been changed. At this point, repeat the process of changing edges to point to other nodes that do not have edges pointing to them. Do this until all edges have been flagged as changed. This will ensure that no card in the deck is adjacent to any cards to which it was previously adjacent in the original deck configuration.
Re: How would you write a shuffle algorithm?
I had posted this earlier but did not do a preview.
public static int[] Shuffle(int[] cards)
{
var cardsCount = cards.Length;
int[] shuffledCards = new int[cardsCount];
var counter = 0;
var iter = true;
var random = new Random();
while (iter)
{
var randomIndex = (random.Next(1, (cardsCount + 1)) - 1);
var card = cards[randomIndex];
if (shuffledCards.Contains<int>(card))
{
continue;
}
else
{
shuffledCards[counter] = card;
++counter;
}
if (counter == cardsCount)
{
iter = false;
}
}
return shuffledCards;
}