Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • World
  • Users
  • Groups
Skins
  • Light
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (No Skin)
  • No Skin
Collapse
Code Project
  1. Home
  2. General Programming
  3. C#
  4. Drawing cards from a deck

Drawing cards from a deck

Scheduled Pinned Locked Moved C#
graphicshelptutorialquestionlounge
18 Posts 6 Posters 1 Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • T Offline
    T Offline
    Tony Pottier
    wrote on last edited by
    #1

    Hi, I'd like to run some simulations on a deck of 52 cards, but I don't know how to make it fast. Say, I want to draw 5 random cards from a deck. The most straightforward way to do this would be to create a List, List, List, etc. (whatever way the cards are represented), then draw a random number between 0-51, remove the card from the list, draw a number between 0-50, remove the card from the list, rinse & repeat until 5 cards are drawn. The problem is that adding/removing stuff is a costly operation. Can you see a fast way to randomly draw cards from a deck?

    CPalliniC B L H 4 Replies Last reply
    0
    • T Tony Pottier

      Hi, I'd like to run some simulations on a deck of 52 cards, but I don't know how to make it fast. Say, I want to draw 5 random cards from a deck. The most straightforward way to do this would be to create a List, List, List, etc. (whatever way the cards are represented), then draw a random number between 0-51, remove the card from the list, draw a number between 0-50, remove the card from the list, rinse & repeat until 5 cards are drawn. The problem is that adding/removing stuff is a costly operation. Can you see a fast way to randomly draw cards from a deck?

      CPalliniC Offline
      CPalliniC Offline
      CPallini
      wrote on last edited by
      #2

      I don't think it is such slow. You may use an array (of card index or references) and that swap the random selected element with the last one. :)

      If the Lord God Almighty had consulted me before embarking upon the Creation, I would have recommended something simpler. -- Alfonso the Wise, 13th Century King of Castile.
      This is going on my arrogant assumptions. You may have a superb reason why I'm completely wrong. -- Iain Clarke
      [My articles]

      In testa che avete, signor di Ceprano?

      T 1 Reply Last reply
      0
      • T Tony Pottier

        Hi, I'd like to run some simulations on a deck of 52 cards, but I don't know how to make it fast. Say, I want to draw 5 random cards from a deck. The most straightforward way to do this would be to create a List, List, List, etc. (whatever way the cards are represented), then draw a random number between 0-51, remove the card from the list, draw a number between 0-50, remove the card from the list, rinse & repeat until 5 cards are drawn. The problem is that adding/removing stuff is a costly operation. Can you see a fast way to randomly draw cards from a deck?

        B Offline
        B Offline
        benjymous
        wrote on last edited by
        #3

        Ok, I just quickly implemented what you describe, populating a List with the numbers 0-51, and removing a random entry from the list 5 times. I did this in a big loop that repeats the operation a million times, and it took roughly a second. So unless you're planning on implementing your own List, rather than using the Generics one, I wouldn't worry about speed

        Help me! I'm turning into a grapefruit! Buzzwords!

        T 2 Replies Last reply
        0
        • CPalliniC CPallini

          I don't think it is such slow. You may use an array (of card index or references) and that swap the random selected element with the last one. :)

          If the Lord God Almighty had consulted me before embarking upon the Creation, I would have recommended something simpler. -- Alfonso the Wise, 13th Century King of Castile.
          This is going on my arrogant assumptions. You may have a superb reason why I'm completely wrong. -- Iain Clarke
          [My articles]

          T Offline
          T Offline
          Tony Pottier
          wrote on last edited by
          #4

          That's a really nice idea. I'm going to try that.

          1 Reply Last reply
          0
          • B benjymous

            Ok, I just quickly implemented what you describe, populating a List with the numbers 0-51, and removing a random entry from the list 5 times. I did this in a big loop that repeats the operation a million times, and it took roughly a second. So unless you're planning on implementing your own List, rather than using the Generics one, I wouldn't worry about speed

            Help me! I'm turning into a grapefruit! Buzzwords!

            T Offline
            T Offline
            Tony Pottier
            wrote on last edited by
            #5

            Well 1 million is what I need in fact ;o Thank you for trying. It took 1 second even when you have to repopulate the list at every pass? I need to see this by myself!

            1 Reply Last reply
            0
            • B benjymous

              Ok, I just quickly implemented what you describe, populating a List with the numbers 0-51, and removing a random entry from the list 5 times. I did this in a big loop that repeats the operation a million times, and it took roughly a second. So unless you're planning on implementing your own List, rather than using the Generics one, I wouldn't worry about speed

              Help me! I'm turning into a grapefruit! Buzzwords!

              T Offline
              T Offline
              Tony Pottier
              wrote on last edited by
              #6

              This took 2.7s on my machine. What's your code?

              List deck = new List();
              uint[] cards = new uint[52];

              Random rnd = new Random();
              DateTime st = DateTime.Now;
              for (int i = 0; i < 1000000; i++)
              {
              deck.Clear();
              deck.AddRange(cards);

              //remove 5 cards
              deck.RemoveAt(rnd.Next(0, deck.Count - 1));
              deck.RemoveAt(rnd.Next(0, deck.Count - 1));
              deck.RemoveAt(rnd.Next(0, deck.Count - 1));
              deck.RemoveAt(rnd.Next(0, deck.Count - 1));
              deck.RemoveAt(rnd.Next(0, deck.Count - 1));
              

              }
              DateTime ed = DateTime.Now;

              B 1 Reply Last reply
              0
              • T Tony Pottier

                This took 2.7s on my machine. What's your code?

                List deck = new List();
                uint[] cards = new uint[52];

                Random rnd = new Random();
                DateTime st = DateTime.Now;
                for (int i = 0; i < 1000000; i++)
                {
                deck.Clear();
                deck.AddRange(cards);

                //remove 5 cards
                deck.RemoveAt(rnd.Next(0, deck.Count - 1));
                deck.RemoveAt(rnd.Next(0, deck.Count - 1));
                deck.RemoveAt(rnd.Next(0, deck.Count - 1));
                deck.RemoveAt(rnd.Next(0, deck.Count - 1));
                deck.RemoveAt(rnd.Next(0, deck.Count - 1));
                

                }
                DateTime ed = DateTime.Now;

                B Offline
                B Offline
                benjymous
                wrote on last edited by
                #7

                Random rnd = new Random(); List myDeck = new List(); DateTime start = DateTime.Now; for (int loop = 0; loop < 1000000; ++loop) { myDeck.Clear(); for (int i = 0; i < 52; ++i) { myDeck.Add(i); } List hand = new List(); // Randomly remove a random card until the deck is empty for( int draw = 0; draw<5; ++draw ) { int cardIndex = rnd.Next(myDeck.Count); int card = myDeck[cardIndex]; myDeck.RemoveAt(cardIndex); hand.Add(card); } } DateTime end = DateTime.Now; [edit] - turned off the html tags - which kills the formatting, but at least you can see the generics! Help me! I'm turning into a grapefruit! Buzzwords!

                G 1 Reply Last reply
                0
                • T Tony Pottier

                  Hi, I'd like to run some simulations on a deck of 52 cards, but I don't know how to make it fast. Say, I want to draw 5 random cards from a deck. The most straightforward way to do this would be to create a List, List, List, etc. (whatever way the cards are represented), then draw a random number between 0-51, remove the card from the list, draw a number between 0-50, remove the card from the list, rinse & repeat until 5 cards are drawn. The problem is that adding/removing stuff is a costly operation. Can you see a fast way to randomly draw cards from a deck?

                  L Offline
                  L Offline
                  Luc Pattyn
                  wrote on last edited by
                  #8

                  Hi, the strategy of putting all candidates in a collection, and extracting from there as many as you need in a random way, is correct. However, if you only want to extract a small fraction, it may be more economical to forget the collection, and just try 5 random numbers; whenever one is chosen that has been picked already, just throw the dice again. For 5 out of 52 that will occur in some 10% of the cases. If on the other hand, you decide to stick with the collection, there is no real need to build it over and over; once done, you can add the chosen items back to the collection. That would change the order, but then you could sort the collection (not sure that would be faster than recreating it), or you could ignore the issue, just relying on the randomness of the picking process. Strict randomness would mean the outcome does not depend on the previous outcome, so all candidates have the same probability, no matter where they are in the collection. Of course, if you are creating the perfect poker playing app, and are gambling your fortune, you may want to make sure, and follow the official ways... :)

                  Luc Pattyn [Forum Guidelines] [My Articles]


                  I use ListBoxes for line-oriented text (not TextBoxes), and PictureBoxes for pictures (not drawings).


                  modified on Friday, June 10, 2011 12:23 PM

                  G 1 Reply Last reply
                  0
                  • B benjymous

                    Random rnd = new Random(); List myDeck = new List(); DateTime start = DateTime.Now; for (int loop = 0; loop < 1000000; ++loop) { myDeck.Clear(); for (int i = 0; i < 52; ++i) { myDeck.Add(i); } List hand = new List(); // Randomly remove a random card until the deck is empty for( int draw = 0; draw<5; ++draw ) { int cardIndex = rnd.Next(myDeck.Count); int card = myDeck[cardIndex]; myDeck.RemoveAt(cardIndex); hand.Add(card); } } DateTime end = DateTime.Now; [edit] - turned off the html tags - which kills the formatting, but at least you can see the generics! Help me! I'm turning into a grapefruit! Buzzwords!

                    G Offline
                    G Offline
                    Guffa
                    wrote on last edited by
                    #9

                    Don't move the data around so much... Instead of shifting half the deck to remove a card, just move the last card into the empty slot. Runs in 125 ms. on my puter: :)

                    public class Deck {

                    private int\[\] \_cards;
                    private int \_used;
                    private Random \_rnd;
                    
                    public Deck() {
                    	\_cards = new int\[52\];
                    	\_used = 0;
                    	\_rnd = new Random();
                    }
                    
                    public void Init() {
                    	for (int i = 0; i < 52; i++) {
                    		\_cards\[i\] = i;
                    	}
                    	\_used = 52;
                    }
                    
                    public void GetHand(int\[\] hand) {
                    	for (int i=0;i<5;i++) {
                    		int index = \_rnd.Next(\_used);
                    		hand\[i\] = \_cards\[index\];
                    		\_used--;
                    		\_cards\[index\] = \_cards\[\_used\];
                    	}
                    }
                    

                    }

                    Deck deck = new Deck();
                    int[] hand = new int[5];
                    for (int i = 0; i < 1000000; i++) {
                    deck.Init();
                    deck.GetHand(hand);
                    }

                    Despite everything, the person most likely to be fooling you next is yourself.

                    1 Reply Last reply
                    0
                    • L Luc Pattyn

                      Hi, the strategy of putting all candidates in a collection, and extracting from there as many as you need in a random way, is correct. However, if you only want to extract a small fraction, it may be more economical to forget the collection, and just try 5 random numbers; whenever one is chosen that has been picked already, just throw the dice again. For 5 out of 52 that will occur in some 10% of the cases. If on the other hand, you decide to stick with the collection, there is no real need to build it over and over; once done, you can add the chosen items back to the collection. That would change the order, but then you could sort the collection (not sure that would be faster than recreating it), or you could ignore the issue, just relying on the randomness of the picking process. Strict randomness would mean the outcome does not depend on the previous outcome, so all candidates have the same probability, no matter where they are in the collection. Of course, if you are creating the perfect poker playing app, and are gambling your fortune, you may want to make sure, and follow the official ways... :)

                      Luc Pattyn [Forum Guidelines] [My Articles]


                      I use ListBoxes for line-oriented text (not TextBoxes), and PictureBoxes for pictures (not drawings).


                      modified on Friday, June 10, 2011 12:23 PM

                      G Offline
                      G Offline
                      Guffa
                      wrote on last edited by
                      #10

                      Luc Pattyn wrote:

                      If on the other hand, you decide to stick with the collection, there is no real need to build it over and over; once done, you can add the chosen items back to the collection.

                      Interresting idea. It shaved off about 25% of the executon time of the code I posted earlier. What I did was actually to leave the chosen items in the array, only swapping them to the unused area at the end. :)

                      Despite everything, the person most likely to be fooling you next is yourself.

                      T L 2 Replies Last reply
                      0
                      • G Guffa

                        Luc Pattyn wrote:

                        If on the other hand, you decide to stick with the collection, there is no real need to build it over and over; once done, you can add the chosen items back to the collection.

                        Interresting idea. It shaved off about 25% of the executon time of the code I posted earlier. What I did was actually to leave the chosen items in the array, only swapping them to the unused area at the end. :)

                        Despite everything, the person most likely to be fooling you next is yourself.

                        T Offline
                        T Offline
                        Tony Pottier
                        wrote on last edited by
                        #11

                        Yes I did that too, and it ran pretty fast. (400ms on my old comp) It's probably the best method. The List approach is really too slow for what I need (Monte Carlo simulations). Thanks everyone for your time.

                        1 Reply Last reply
                        0
                        • G Guffa

                          Luc Pattyn wrote:

                          If on the other hand, you decide to stick with the collection, there is no real need to build it over and over; once done, you can add the chosen items back to the collection.

                          Interresting idea. It shaved off about 25% of the executon time of the code I posted earlier. What I did was actually to leave the chosen items in the array, only swapping them to the unused area at the end. :)

                          Despite everything, the person most likely to be fooling you next is yourself.

                          L Offline
                          L Offline
                          Luc Pattyn
                          wrote on last edited by
                          #12

                          Hi Guffa, I didn't see your code until now; if you have an array, rather than a vague collection, swapping cards out of sight as you did is the right way to go IMO. Reinserting the chosen ones would mean: undo the swaps (which you should do in reverse order of course). The advantage now is you are restoring the exact state the array had to begin with without touching things that hadn't changed in the process. :)

                          Luc Pattyn [Forum Guidelines] [My Articles]


                          I use ListBoxes for line-oriented text (not TextBoxes), and PictureBoxes for pictures (not drawings).


                          modified on Friday, June 10, 2011 12:23 PM

                          G 1 Reply Last reply
                          0
                          • L Luc Pattyn

                            Hi Guffa, I didn't see your code until now; if you have an array, rather than a vague collection, swapping cards out of sight as you did is the right way to go IMO. Reinserting the chosen ones would mean: undo the swaps (which you should do in reverse order of course). The advantage now is you are restoring the exact state the array had to begin with without touching things that hadn't changed in the process. :)

                            Luc Pattyn [Forum Guidelines] [My Articles]


                            I use ListBoxes for line-oriented text (not TextBoxes), and PictureBoxes for pictures (not drawings).


                            modified on Friday, June 10, 2011 12:23 PM

                            G Offline
                            G Offline
                            Guffa
                            wrote on last edited by
                            #13

                            Actually, I just left the deck in the new order and included all cards again. As you wrote before, the order of the cards in the deck doesn't matter when you draw cards by random. :)

                            Despite everything, the person most likely to be fooling you next is yourself.

                            L 1 Reply Last reply
                            0
                            • G Guffa

                              Actually, I just left the deck in the new order and included all cards again. As you wrote before, the order of the cards in the deck doesn't matter when you draw cards by random. :)

                              Despite everything, the person most likely to be fooling you next is yourself.

                              L Offline
                              L Offline
                              Luc Pattyn
                              wrote on last edited by
                              #14

                              Yes I know, however not everyone tends to believe that. They start arguing it might be true for real random stuff, but then it is only pseudo-random and ... WTF. :)

                              Luc Pattyn [Forum Guidelines] [My Articles]


                              I use ListBoxes for line-oriented text output (not TextBoxes), and PictureBoxes for pictures (not drawings).


                              modified on Friday, June 10, 2011 12:24 PM

                              T 1 Reply Last reply
                              0
                              • L Luc Pattyn

                                Yes I know, however not everyone tends to believe that. They start arguing it might be true for real random stuff, but then it is only pseudo-random and ... WTF. :)

                                Luc Pattyn [Forum Guidelines] [My Articles]


                                I use ListBoxes for line-oriented text output (not TextBoxes), and PictureBoxes for pictures (not drawings).


                                modified on Friday, June 10, 2011 12:24 PM

                                T Offline
                                T Offline
                                Tony Pottier
                                wrote on last edited by
                                #15

                                No problem, I'll just use this then:http://thedailywtf.com/Articles/Random-Stupidity.aspx[^] :p

                                L 1 Reply Last reply
                                0
                                • T Tony Pottier

                                  No problem, I'll just use this then:http://thedailywtf.com/Articles/Random-Stupidity.aspx[^] :p

                                  L Offline
                                  L Offline
                                  Luc Pattyn
                                  wrote on last edited by
                                  #16

                                  Great. I especially like "Random() returns increasingly randomer numbers the more you call it". :)

                                  Luc Pattyn [Forum Guidelines] [My Articles]


                                  I use ListBoxes for line-oriented text output (not TextBoxes), and PictureBoxes for pictures (not drawings).


                                  modified on Friday, June 10, 2011 12:24 PM

                                  1 Reply Last reply
                                  0
                                  • T Tony Pottier

                                    Hi, I'd like to run some simulations on a deck of 52 cards, but I don't know how to make it fast. Say, I want to draw 5 random cards from a deck. The most straightforward way to do this would be to create a List, List, List, etc. (whatever way the cards are represented), then draw a random number between 0-51, remove the card from the list, draw a number between 0-50, remove the card from the list, rinse & repeat until 5 cards are drawn. The problem is that adding/removing stuff is a costly operation. Can you see a fast way to randomly draw cards from a deck?

                                    H Offline
                                    H Offline
                                    Henry Minute
                                    wrote on last edited by
                                    #17

                                    It's a bit late to be posting on this thread, but I've been busy. I wrote a Cribbage card game, some years ago and the way that I did it was to implement a deck class which had a shuffle method, which simply filled a list with random cards (numbers 0-51), drawing again if already used. Dealing then simply became a matter of taking the 'next' card, tracked by an 'index' field. This had many advantages during testing since the deck was still there in the original order. Dont know if this is a good idea, or even relevant to your simulation idea.

                                    Henry Minute If you open a can of worms, any viable solution *MUST* involve a larger can.

                                    T 1 Reply Last reply
                                    0
                                    • H Henry Minute

                                      It's a bit late to be posting on this thread, but I've been busy. I wrote a Cribbage card game, some years ago and the way that I did it was to implement a deck class which had a shuffle method, which simply filled a list with random cards (numbers 0-51), drawing again if already used. Dealing then simply became a matter of taking the 'next' card, tracked by an 'index' field. This had many advantages during testing since the deck was still there in the original order. Dont know if this is a good idea, or even relevant to your simulation idea.

                                      Henry Minute If you open a can of worms, any viable solution *MUST* involve a larger can.

                                      T Offline
                                      T Offline
                                      Tony Pottier
                                      wrote on last edited by
                                      #18

                                      Thank you for your input. Nope in my case this won't work, as you have to rebuild the deck. Creating a list is really the most straightforward way, but when you have to do this 1 million times+, it's too slow.

                                      1 Reply Last reply
                                      0
                                      Reply
                                      • Reply as topic
                                      Log in to reply
                                      • Oldest to Newest
                                      • Newest to Oldest
                                      • Most Votes


                                      • Login

                                      • Don't have an account? Register

                                      • Login or register to search.
                                      • First post
                                        Last post
                                      0
                                      • Categories
                                      • Recent
                                      • Tags
                                      • Popular
                                      • World
                                      • Users
                                      • Groups