カードゲームのカードをシャッフルするにはどうすればよいですか?


13

Android用のカードゲームを開発しようとしています。トランプを効果的にシャッフルするためのコードの記述方法を教えてください。

回答:


21

カードシャッフルは、直感的に簡単に書くことができ、そうすることで完全に間違ってしまうアルゴリズムです。ウィキペディアにカードシャッフルを正しく実装するための良いリファレンスがあります。ここで紹介しているのは、「現代のアルゴリズム」のページに記載されているアルゴリズムの非常に単純化されたバージョンです

基本的な考え方は次のとおりです。

一組のカードを考えてみましょう。このディスカッションでは、デッキに任意の数のカードを置くことができ、それらは任意の順序で開始できます。

ここで、デッキの「位置」について説明します。「位置」とは、その位置のカードよりもデッキ内で高いカードの数です。たとえば、デッキの上部のカードは位置0にあり、その下のカードは位置1にあり(それよりも1枚上のカードがあるため-上部のカード)、標準の52カードのデッキでは、下部にあります51枚のカードがデッキのそれよりも高いため、カードは位置51にあります。

ここで、デッキの各位置を1つずつ、下から始めて上に向かって検討します。

各位置について、その位置またはより低い番号の位置にあるカードの1つをランダムに選択します(デッキの上部は0であり、デッキの下部から上に向かって作業していることに注意してください。ポジションごとに、そのポジション以上のすべてのカードを効果的にピックアップし、それらのカードの1つをランダムにピックアップします)。

ランダムに選択したら、現在検討している位置のカードを、ランダムに選択したカードと交換します。すでにその位置にあったカードをランダムに選択した場合、スワップは実行されません。

交換した後(または交換していない場合、既に検討中の位置にあったカードをランダムに選択した場合)、デッキの次の位置に移動して続行します。

擬似コードでは、nはデッキ内のカードの数であり、aはデッキを表す配列であるため、アルゴリズムは次のようになります。

for each i in [n .. 1] do
     j  random integer in [ 0 .. i ]
     exchange a[j] and a[i]

1
アルゴリズムはまた、きれいに、ここで可視化されていますbost.ocks.org/mike/algorithms/#shuffling
Felsirを

9

最初に、シャッフルするすべてのカードのシーケンスを定義します。

List<Card> shuffled = new ArrayList<Card>();
shuffled.addAll(allCards);

次に、シーケンス内のすべての位置を歩いて、ランダムにカードを割り当てます。

Random random = new Random();
for (int i = shuffled.size() - 1; i >= 0; i--) {
    int j = random.nextInt(i + 1);

    /* swap cards i,j */
    Card card = shuffled.get(i);
    shuffled.set(i, shuffled.get(j));
    shufflet.set(j, card);
}

shuffled、あなたのすべてのカードのランダムなシーケンスです。


3
これはクヌースのシャッフルとして知られています:en.wikipedia.org/wiki/Knuth_shuffle
krolth

2

ゲームでカードをシャッフルする方法として、「フォーマット保存暗号化」に言及して言及したいと思います。

基本的には、値0〜51とキー(シャッフルシード)を取り、値0〜51を出力する暗号化アルゴリズムです。暗号化は定義により可逆であるため、2つの入力番号は暗号化できません。同じ出力番号。つまり、0〜51を暗号化した場合、異なる順序で0〜51が出力されます。つまり、シャッフルがあり、実際のシャッフルを行う必要さえありません。

この場合、6ビットを取り込み、6ビット(0-63)を吐き出す暗号化アルゴリズムを作成または見つける必要があります。デッキから次のカードを引くには、ゼロから始まるインデックス変数を使用します。そのインデックスを暗号化し、インデックスをインクリメントし、暗号から得られた値を調べます。値が> = 52の場合、それを無視して新しい数値を生成します(そしてもちろんインデックスを再び増やします)。0-63を暗号化すると、異なる順序で0-63が出力されるため、52以上の値を無視するだけなので、0-51を取り込んで0-51を吐き出すアルゴリズムが得られます。

デッキをシャッフルするには、インデックスをゼロに戻し、暗号化キーを変更します(シードをシャッフルします)。

アルゴリズムは暗号品質である必要はありません(そうであるべきではありません、原因は計算コストが高くなります!)。このようなカスタムサイズの暗号化アルゴリズムを考え出すための本当に良い方法の1つは、feistelネットワークを使用することです。これにより、ニーズに応じてサイズと品質をカスタマイズできます。feistelネットワークのラウンド関数には、murmurhash3のようなものをお勧めします。これは高速であり、雪崩効果があり、シャッフルがランダムに表示されるためです。

さらに詳しい情報とソースコードについては、私のブログ投稿をご覧ください:http : //blog.demofox.org/2013/07/06/fast-lightweight-random-shuffle-functionality-fixed/


URLが必然的にインターネットの表面から落ちた場合、この答えは現在の言い回しではあまり役に立ちません。リンクされた記事の重要なポイントに関する回答を詳しく説明して、回答がそれ自体で成り立つようにすることを検討してください。
ラースヴィクルンド

1
良い点Lars、より多くの情報で更新されたので、読者は少なくとも、フォーマット保存暗号化を使用したカードシャッフルのソリューションのすべての特定のコンポーネントに関する詳細情報を探すことができます。ありがとう!
アランウルフ

1

Javaの1.5列挙型のチュートリアルでは、デッキを構築シャッフルと対処、カードのデッキを実装するための興味深い方法があります。すべての非常に簡単な使用してenumsであり、Collections

public class Card {
    public enum Rank { DEUCE, THREE, FOUR, FIVE, SIX,
        SEVEN, EIGHT, NINE, TEN, JACK, QUEEN, KING, ACE }

    public enum Suit { CLUBS, DIAMONDS, HEARTS, SPADES }

    private final Rank rank;
    private final Suit suit;
    private Card(Rank rank, Suit suit) {
        this.rank = rank;
        this.suit = suit;
    }

    public Rank rank() { return rank; }
    public Suit suit() { return suit; }
    public String toString() { return rank + " of " + suit; }

    private static final List<Card> protoDeck = new ArrayList<Card>();

    // Initialize prototype deck
    static {
        for (Suit suit : Suit.values())
            for (Rank rank : Rank.values())
                protoDeck.add(new Card(rank, suit));
    }

    public static ArrayList<Card> newDeck() {
        return new ArrayList<Card>(protoDeck); // Return copy of prototype deck
    }
}

そして、デッキを管理するクラス。

public class Deal {
    public static void main(String args[]) {
        int numHands = Integer.parseInt(args[0]);
        int cardsPerHand = Integer.parseInt(args[1]);
        List<Card> deck  = Card.newDeck();
        Collections.shuffle(deck);
        for (int i=0; i < numHands; i++)
            System.out.println(deal(deck, cardsPerHand));
    }

    public static ArrayList<Card> deal(List<Card> deck, int n) {
         int deckSize = deck.size();
         List<Card> handView = deck.subList(deckSize-n, deckSize);
         ArrayList<Card> hand = new ArrayList<Card>(handView);
         handView.clear();
         return hand;
     }
}


-2
    ArrayList deckCards = new ArrayList<Card>();
    //add your cards to the deck
    deckCards.add(card1);
    deckCards.add(card2);
    deckCards.add(card3);
    ....
    //shuffle the array list
    Collections.shuffle(deckCards);

1
コードのみの回答は推奨されません。
SurvivalMachine
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.