C#中的卡片洗牌

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1150646/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-06 09:26:15  来源:igfitidea点击:

Card Shuffling in C#

c#.netshuffleplaying-cards

提问by

I am trying to write a code for a project that lists the contents of a deck of cards, asks how much times the person wants to shuffle the deck, and then shuffles them. It has to use a method to create two random integers using the System.Random class.

我正在尝试为一个项目编写一个代码,该项目列出了一副牌的内容,询问这个人想要洗牌多少次,然后将它们洗牌。它必须使用 System.Random 类创建两个随机整数的方法。

These are my classes:

这些是我的课程:

Program.cs:

程序.cs:

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            Deck mydeck = new Deck();
            foreach (Card c in mydeck.Cards)
            {
                Console.WriteLine(c);
            }
            Console.WriteLine("How Many Times Do You Want To Shuffle?");

        }
    }
}

Deck.cs:

甲板.cs:

namespace ConsoleApplication1
{
    class Deck
    {    
        Card[] cards = new Card[52];
        string[] numbers = new string[] { "2", "3", "4", "5", "6", "7", "8", "9", "J", "Q", "K" };
        public Deck()
        {
            int i = 0;
            foreach(string s in numbers)
            {
                cards[i] = new Card(Suits.Clubs, s);
                i++;

            }
            foreach (string s in numbers)
            {
                cards[i] = new Card(Suits.Spades, s);
                i++;

            }
            foreach (string s in numbers)
            {
                cards[i] = new Card(Suits.Hearts, s);
                i++;

            }
            foreach (string s in numbers)
            {
                cards[i] = new Card(Suits.Diamonds, s);
                i++;

            }
        }

        public Card[] Cards
        {
            get
            {
                return cards;


            }
        }
    }  
}

Enums.cs:

枚举.cs:

namespace ConsoleApplication1
{        
    enum Suits 
    {
        Hearts,
        Diamonds,
        Spades,
        Clubs
    }
}

Card.cs:

卡.cs:

namespace ConsoleApplication1
{
    class Card
    {
        protected Suits suit;
        protected string cardvalue;
        public Card()
        {
        }
        public Card(Suits suit2, string cardvalue2)
        {
            suit = suit2;
            cardvalue = cardvalue2;
        }
        public override string ToString()
        {
            return string.Format("{0} of {1}", cardvalue, suit);
        }
    }
 }

Please tell me how to make the cards shuffle as much as the person wants and then list the shuffled cards.

请告诉我如何让卡片随人所欲地洗牌,然后列出洗牌后的牌。

回答by Philippe Leybaert

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:

Jeff Atwood ( Coding Horror) 写了几篇关于这个主题的非常好的文章:

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

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

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

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

(especially the second one is a must-read)

(尤其是第二篇必读)

回答by hughdbrown

Use Fisher-Yates shuffle.

使用Fisher-Yates shuffle

Your C# code should look something like this:

您的 C# 代码应如下所示:

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;
        }
    }
}

回答by NoMoreZealots

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 到 52 之间的数字来表示卡片并用数学方法计算出哪张卡片是。)

  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.
  1. 通过使用随机数生成器从可用卡组中挑选一张卡来处理一张卡。
  2. 将那张卡与牌堆末端的那张交换。
  3. 减少指向牌组末端的计数器,以将该牌从牌组中移除。
  4. 转到第 1 步,直到完成绘制卡片。

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.

使用您显示的数据结构应该可以做到这一点。您只需要添加一个“Draw”方法和成员变量来跟踪甲板的末端。如果你一心想要提前进行“洗牌”,那么 A 你的教授就是个混蛋,B 每当你抽 52 张牌时,牌组就会被洗牌。抽完所有牌后,您需要提供一个“DeckEmpty”方法,以及重置 End of Deck 以再次包含所有牌的方法。

回答by NoMoreZealots

The shuffling should work in this manner:

洗牌应该以这种方式工作:

You take two random cards in the deck (the index of the card in the deck is the random numbers) And swap positions of the two cards. For instance take card at index 2 and card at index 9 and have them change place.

你在牌组中随机取两张牌(牌组中牌的索引是随机数)并交换两张牌的位置。例如在索引 2 处取卡和在索引 9 处取卡并让它们改变位置。

And that can be repeated a certain number of times.

这可以重复一定次数。

The algorithm should look something like this:

该算法应如下所示:

int firstNum = rnd.Next(52);
int secondNum = rnd.Next(52);

Card tempCard = MyCards[firstNum];
MyCards[firstNum] = MyCards[secondNum];
MyCards[secondNum] = tempCard;

回答by Lyozsi

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

您的 Shuffle 可能有效,但效率不高,也不栩栩如生。你应该试试这种方式:

//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

通过这种方式,您可能会以更少的迭代获得更逼真的 shuffle

回答by VANDERWEYEN Jonathan

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.

要正确地洗牌,你不应该只使用 Random 类,种子只有 2^32,这意味着你的 Random 对象只能给你 2^32(假设)不同的顺序,而有 52!(阶乘 52)代理现实生活甲板的方式。

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

我正在使用 2 个 guid 创建 32 字节的随机数据 - > 8 个 4 字节的种子,然后我用 8 个不同的种子洗牌

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

然后通过种子我得到一定数量的卡片 [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);
            }
        }
    }

回答by user3342574

Overall I'd say look at each deck as an object which contains an array of Card objects, which each Card object each contains a value and suite int property, which can be applied to an Enum of values and suites to gather the named version as per the Type of Deck you are using. (This would allow this bit of code to be more versatile and allow easier value comparisons 3 < 11 (Hyman) !~) Your style will work for a school project, I am just getting OCD with it!

总的来说,我会说将每个甲板视为一个对象,其中包含一个 Card 对象数组,每个 Card 对象都包含一个 value 和 suite int 属性,可以将其应用于值和套件的枚举以收集命名版本为根据您使用的甲板类型。(这将使这段代码更加通用,并允许更容易的值比较 3 < 11 (Hyman) !~)你的风格适用于学校项目,我只是用它来获得强迫症!

class Card
{
    public int value
    { get; set; }

    public int suite
    { get; set; }
}


abstract class Deck
{
    public Card[] cards
    { get; set; }

    public void ShuffleCards(int timesToShuffle)
    {
        Card temp;
        Random random = new Random();
         // int timesToShuffle = random.Next(300, 600); #Had it setup for random shuffle
        int cardToShuffle1, cardToShuffle2; 

        for (int x = 0; x < timesToShuffle; x++)
        {
            cardToShuffle1 = random.Next(this.cards.Length);
            cardToShuffle2 = random.Next(this.cards.Length);
            temp = this.cards[cardToShuffle1];

            this.cards[cardToShuffle1] = this.cards[cardToShuffle2];
            this.cards[cardToShuffle2] = temp;
        }
    }
}

That is assuming that you used a base Deck class, then inherit it to the type of deck you want (making it so you can apply this same code to Uno decks or what ever.) Code for normal type of deck class.

那是假设你使用了一个基本的 Deck 类,然后将它继承到你想要的甲板类型(这样你就可以将相同的代码应用于 Uno 甲板或其他任何东西。)普通类型的甲板类的代码。

class NormalDeck : Deck
{
    // This would go in the NormalGame class to apply the enumerators to the values as a cipher.
    // Need int values for logic reasons (easier to work with numbers than J or K !!!
    // Also allows for most other methods to work with other deck<Type> (ex: Uno, Go Fish, Normal cards)
    public enum Suites
    {
        Hearts,
        Diamonds,
        Spades,
        Clover
    };

    // Same comment as above. 
    public enum Values
    { Ace, Two, Three, Four, Five, Six, Seven, Eight, Nine, Ten, Hyman, Queen, King };

    public void NewNormalDeck()
    {
        // Clear the deck of cards
        if (this.cards != null)
        {
            Array.Clear(this.cards, 0, this.cards.Length);
        }

        //Set Value to length of Normal deck of Cards without Jokers 
        cards = new Card[52];

        // to keep count of which card we are.  
        int curNumofCards = 0;

        // Cycle through all of the suites listed in "suites" then all the values of     that suite
        for (int x = 0; x < Enum.GetValues(typeof(Suites)).GetLength(0); x++)
        {
            for (int y = 0; y < Enum.GetValues(typeof(Values)).GetLength(0); y++)
            {
                Card newCard = new Card();
                newCard.suite = x;
                newCard.value = y;
                this.cards[curNumofCards] = newCard;
                curNumofCards++;
            }
        }
    }
}

回答by Steve

static void Shuffle(List<int> cards)
    {
        Console.WriteLine("");
        Console.WriteLine("Shuffling");
        Console.WriteLine("---------");

        cards = cards.OrderBy(x => Guid.NewGuid()).ToList();

        foreach (var card in cards)
        {
            Console.WriteLine(card.ToString());
        }
    }