Use Fisher-Yates shuffle.

Your C# code should look something like this:

static public class FisherYates
{
    static Random r = new Random();
    //  Based on Java code from wikipedia:
    //  http://en.wikipedia.org/wiki/Fisher-Yates_shuffle
    static public void Shuffle(int[] deck)
    {
        for (int n = deck.Length - 1; n > 0; --n)
        {
            int k = r.Next(n+1);
            int temp = deck[n];
            deck[n] = deck[k];
            deck[k] = temp;
        }
    }
}

Shuffling a deck of cards is something that seems trivial at first, but usually the algorithm that most people come up with is incorrect.

Jeff Atwood (Coding Horror) wrote a few very good articles on the subject:

http://www.codinghorror.com/blog/archives/001008.html

http://www.codinghorror.com/blog/archives/001015.html

(especially the second one is a must-read)


I think this is a case where you may just be getting too caught up in the abstraction.

Shuffling a deck of cards in software is a matter of providing the deck to the user in a random order. This doesn't actually require you to shuffle them ahead of time.

Init your deck. (I typically use a number from 1 to 52 to represent the card and mathmatically compute which card is.)

  1. Deal a card by using a random number generator to pick a card out of the Deck of availible cards.
  2. Swap that card with the one at the end of the deck.
  3. Decrement a counter pointing to the end of the deck, to remove that card from the deck.
  4. Goto step 1 until you are done drawing cards.

Edit: And generally speaking, if you have a good random number generator nothing is gained by "Shuffling" it multiple times.

This should be possible using the data structures you've shown. You just need to add a "Draw" method, and member variable to keep track of the end of the deck. If you are hell bent on actually performing the "shuffle" ahead of time, then A your professor's a jerk, B anytime you draw 52 cards the deck will be shuffled. Once you've draw all cards, you need to provide a "DeckEmpty" method, and method to reset the End of Deck to include all cards again.


to correcly shuffle a deck you should NOT ONLY use the Random class, the seed is only 2^32 which means your Random object can give you only 2^32 (supposed) different order where there is 52! (factorial 52) way of agencing a real life deck.

i'm using 2 guid to create 32bytes of random data -> 8 seed of 4bytes and i shuffle the cards with thoses 8 different seeds

then by seed i get a certain number of cards [5,5,6,6,6,7,8,9]

here is the code i use

    public void Shuffle(Guid guid1, Guid guid2)
    {
        int[] cardsToGet = new int[] { 5, 5, 6, 6, 6, 7, 8, 9 };
        byte[] b1 = guid1.ToByteArray();
        byte[] b2 = guid2.ToByteArray();

        byte[] all = new byte[b1.Length + b2.Length];
        Array.Copy(b1, all, b1.Length);
        Array.Copy(b2, 0, all, b1.Length, b2.Length);

        List<Card> cards = new List<Card>(this);
        Clear();

        for (int c = 0; c < cardsToGet.Length; c++)
        {
            int seed = BitConverter.ToInt32(all, c * 4);
            Random random = new Random(seed);
            for (int d = 0; d < cardsToGet[c]; d++)
            {
                int index = random.Next(cards.Count);
                Add(cards[index]);
                cards.RemoveAt(index);
            }
        }
    }

Your Shuffle might work, but it's not really efficient and not lifelike. You should try this way:

//The shuffle goes like this: you take a portion of the deck, then put them in random places
private void Shuffle()
{
 int length = DeckofCards.Count;
 int level = 20; //number of shuffle iterations

 List<Card> Shuffleing; //the part of the deck were putting back
 Random rnd = new Random();
 int PickedCount, BackPortion; //the last used random number

 for (int _i = 0; _i < level; _i++)
 {
  PickedCount = rnd.Next(10, 30); //number of cards we pick out
  Shuffleing = DeckofCards.GetRange(0, PickedCount);
  DeckofCards.RemoveRange(0, PickedCount);

  while (Shuffleing.Count != 0)
  {
   PickedCount = rnd.Next(10, DeckofCards.Count - 1); //where we place a range of cards
   BackPortion = rnd.Next(1, Shuffleing.Count / 3 + 1); //the number of cards we but back in one step
   DeckofCards.InsertRange(PickedCount, Shuffleing.GetRange(0, BackPortion)); //instering a range of cards
   Shuffleing.RemoveRange(0, BackPortion); //we remove what we just placed back
  }
 }
}

This way you might get a more lifelike shuffle with less iterations