In this Quick Tip, I will show you how to implement the Fisher-Yates shuffle algorithm. Once we have learned how it works, we will use it to shuffle a virtual deck of cards.
Note: Although this tutorial is written using JavaScript, you should be able to use the same techniques and concepts in almost any game development environment.
1. Introduction to the Algorithm
There are several ways to shuffle a set of elements, as demonstrated in this post. While those are all valid options, the one method I have always used is the one implemented by the Fisher-Yates Shuffle Algorithm.
I like this method because it does an “in place” shuffle without the need to create a new array (or whatever data structure you happen to be using).
2. Using the Algorithm
If you gave the Wikipedia page a quick read through, you’ll have seen it mentions a couple of different methods of implementing the algorithm. The one we will be using is called the “Modern Method”:
To shuffle an array a of n elements (indices 0...n-1): for i from (n − 1) down to 1 do set j to a random integer with 0 ≤ j ≤ i exchange a[j] and a[i]
- You start with the last element in the list (the top card in the deck, if you like).
- You pick another element at random between the first one and your selected one.
- You swap these two elements.
- You pick the last-but-one element in the list (the second card in the deck), and repeat #1-#3 until you reach the bottom of the deck.
I have put together a visual demo that show the steps the algorithm takes. Hopefully it makes the above explanation clearer:
Translating this into a for
loop would look like this:
var someArray = [1,2,3,4,5,6,7,8,9]; var theLength = someArray.length - 1; var toSwap; // The index we will swap (i.e. the random number) var temp; // A temporary variable to hold reference to index variable i points to for (i = theLength; i > 0; i--) { toSwap = Math.floor(Math.random() * i); temp = someArray[i]; someArray[i] = someArray[toSwap]; someArray[toSwap] = temp; }
The reason we need the temp
variable is because we need have a reference to the first element. If we did not have a reference to the first element, then when we swapped the second element with the first, we would lose the first element. Since the first element now equals the second, when we swapped the first with the second it would “be the second element”, since the second element is now in the first’s place. By having a reference to the first item we can then set the second element equal to it instead.
3. Putting the Algorithm Into Practice
The above demonstration is nice for a visual representation of how the algorithm works, but to put it to real world use we will now use it to shuffle some virtual cards. Below is the code.
$(function () { var serverString = "http://source.tutsplus.com/gamedev/authors/JamesTyner/FisherYates/src/images/"; var cards = []; var i; for (i = 1; i <= 13; i++) { cards.push("c" + i); } //console.log(cards); function drawCards(){ $("#holder").empty(); for (i = 0; i < cards.length; i++) { $("#holder").append("<img src=" + serverString + cards[i] + ".png/>"); } } drawCards(); $("#shuffle").on('click', shuffle); var theLength = cards.length - 1; var toSwap; var tempCard; function shuffle() { console.log("Cards before shuffle:" + cards); for (i = theLength; i > 0; i--) { toSwap = Math.floor(Math.random() * i); tempCard = cards[i]; cards[i] = cards[toSwap]; cards[toSwap] = tempCard; } console.log("Cards after shuffle: "+cards); drawCards(); } });
Here we create a deck of thirteen cards, and then shuffle them when the shuffle button is pressed. The Fisher-Yates Shuffle algorithm is implemented in the shuffle()
function.
I have created another demo to show this in action, but you can also try it yourself with the files included in this tutorial’s downloadable assets.
4. Conclusion
The Fisher-Yates Shuffle algorithm is one of several ways to implement shuffling within your applications. There is no need to create new arrays, as it does the shuffle in place. I am a big fan of this shuffle algorithm, and maybe you are now as well.
Thanks for reading and I hope you have found this tutorial useful.