16

カードのデッキの内容をリストし、デッキをシャッフルしたい回数を尋ねてからシャッフルするプロジェクトのコードを書こうとしています。System.Random クラスを使用して 2 つの乱数整数を作成するメソッドを使用する必要があります。

これらは私のクラスです:

Program.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:

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:

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

Card.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);
        }
    }
 }

カードを好きなだけシャッフルする方法とシャッフルしたカードのリストを教えてください。

4

9 に答える 9

52

Fisher-Yates shuffleを使用します。

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;
        }
    }
}
于 2009-07-19T19:41:14.767 に答える
17

カードのデッキをシャッフルすることは、最初は些細なことのように思えますが、通常、ほとんどの人が考え出すアルゴリズムは正しくありません。

Jeff Atwood ( Coding Horror ) は、この件に関して非常に優れた記事をいくつか書いています。

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

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

(特に2枚目は必読)

于 2009-07-19T19:29:33.510 に答える
5

これは、抽象化にとらわれすぎている可能性があるケースだと思います。

ソフトウェアでカードのデッキをシャッフルすることは、ランダムな順序でデッキをユーザーに提供することです。これは実際に事前にそれらをシャッフルする必要はありません。

デッキを初期化します。(私は通常、カードを表すために 1 から 52 までの数字を使用し、どのカードであるかを数学的に計算します。)

  1. 乱数発生器を使用して、使用可能なカードのデッキからカードを 1 枚選び、カードを配ります。
  2. そのカードをデッキの最後にあるカードと交換します。
  3. デッキの最後を指しているカウンターを 1 つ減らし、そのカードをデッキから取り除きます。
  4. カードを引くまで、ステップ 1 に進みます。

編集:そして、一般的に言えば、優れた乱数ジェネレーターがあれば、それを複数回「シャッフル」しても何も得られません。

これは、あなたが示したデータ構造を使用して可能になるはずです。「Draw」メソッドとメンバー変数を追加して、デッキの最後を追跡するだけです。事前に実際に「シャッフル」を実行することに夢中になっている場合は、A 教授は馬鹿げています。B 52 枚のカードを引くたびにデッキがシャッフルされます。すべてのカードを引いたら、「DeckEmpty」メソッドと、すべてのカードを再び含めるために End of Deck をリセットするメソッドを提供する必要があります。

于 2009-07-19T19:58:57.820 に答える
3

デッキを正しくシャッフルするには、Random クラスだけを使用するべきではありません。シードは 2^32 しかありません。つまり、Random オブジェクトは 2^32 (想定) の異なる順序で 52 しか提供できません! (factorial 52) 実際のデッキを作成する方法。

私は 2 つの GUID を使用して 32 バイトのランダム データを作成しています -> 4 バイトの 8 つのシードを作成し、それらの 8 つの異なるシードでカードをシャッフルします

次に、シードによって特定の数のカードを取得します[5,5,6,6,6,7,8,9]

ここに私が使用するコードがあります

    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);
            }
        }
    }
于 2013-07-16T10:07:04.460 に答える
2

シャッフルは機能するかもしれませんが、実際には効率的ではなく、リアルではありません。この方法を試してください:

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

このようにして、より少ない反復でよりリアルなシャッフルを得ることができます

于 2012-11-04T19:44:02.993 に答える
0

全体として、各デッキを Card オブジェクトの配列を含むオブジェクトとして見てください。各 Card オブジェクトには、値とスイートの列挙型に適用できる値とスイートの int プロパティが含まれており、名前付きバージョンを次のように収集できます。使用しているデッキの種類ごと。(これにより、このコードのビットがより用途が広くなり、3 < 11 (jack) の値を簡単に比較できるようになります!~) あなたのスタイルは学校のプロジェクトで機能します。私はそれで OCD を取得しています!

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

これは、基本的な 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, Jack, 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++;
            }
        }
    }
}
于 2014-02-23T05:47:58.897 に答える
-1

シャッフルは次のように機能するはずです。

デッキからランダムに 2 枚のカードを取り (デッキ内のカードのインデックスは乱数です)、2 枚のカードの位置を入れ替えます。たとえば、インデックス 2 のカードとインデックス 9 のカードを取り、それらを入れ替えます。

そして、それは一定の回数繰り返すことができます。

アルゴリズムは次のようになります。

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

Card tempCard = MyCards[firstNum];
MyCards[firstNum] = MyCards[secondNum];
MyCards[secondNum] = tempCard;
于 2009-07-21T18:52:48.003 に答える
-1
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());
        }
    }
于 2018-07-25T14:53:52.973 に答える