5

カードのデッキをシャッフルするためのプログラム (主にメソッド) を書くように依頼されました。次のプログラムを書きました。

public class Deck {

////////////////////////////////////////
// Data Members
////////////////////////////////////////

private Card[] cards; // array holding all 52 cards
private int cardsInDeck; // the current number of cards in the deck

public static final int DECK_SIZE = 52;

/**
 * Shuffles the deck (i.e. randomly reorders the cards in the deck). 
 */
public void shuffle() {
    int newI;
    Card temp;
    Random randIndex = new Random();

    for (int i = 0; i < cardsInDeck; i++) {

        // pick a random index between 0 and cardsInDeck - 1
        newI = randIndex.nextInt(cardsInDeck);

        // swap cards[i] and cards[newI]
        temp = cards[i];
        cards[i] = cards[newI];
        cards[newI] = temp;
    }
}

}

しかし、上記のシャッフル方法には、次のような論理エラーがあります。カード番号 4 をカード番号 42 に置き換えて、2 回交換するとします。これを行わない方法はありますか?

ここで 1 つの投稿を確認しました :カードのデッキをシャッフルする

しかし、それは私には意味がありませんでした。

4

3 に答える 3

5

デッキをシャッフルする最良の方法は、シャッフルしないことです。乱数の使用方法は既に知っているので、Fisher-Yates shuffle を変更して、カードをランダムな順序で、重複せず、最初の並べ替えなしで抽出することができます。

これらの物理的な用語で考えてください (実際のカードのデッキを使用する場合)。デッキを前にシャッフルしてから一番上のカードを連続して抽出するのではなく、ソートされた順序でデッキを残して、毎回ランダムな場所からカードを抽出します.

これがどのように機能するかの完全な説明については、こちらを参照してください。ただし、以下では、1 から 9 までの 3 つの数字の抽出について説明します。


(シャッフルされていない) リスト{1,2,3,4,5,6,7,8,9}(明らかに長さ 9) から始めて、その長さに基づいて乱数を生成します (0 から 8 まで、Java が行うゼロベースのインデックスを使用すると仮定します)。最初の乱数が 4 だとしましょう。

次に、アイテムを位置番号 4 ( 5) に保存し、リスト内の _last アイテム ( 9) をその位置に移動して、長さを 1 減らします。これにより{1,2,3,4,9,6,7,8}、長さが 8 になります。

次に、長さに基づく乱数 (0 ~ 7 を含む) を使用して、2 番目の数値に戻ります。この場合、乱数 1 を取得します。

オフセット 1 の項目は2、最初のステップと同じようにリストを調整{1,8,3,4,9,6,7}し、長さを 7 にします。

ここで、現在の長さ 7 に基づいて 3 番目の乱数を取得し、たまたま再び 4 になったとします。そのアイテムは現在、リストを長さ 69になるように変更した後、それを返します。{1,8,3,4,7,6}

これがどのように発展しているかを見ることができるはずです。前もってリスト全体をソートすることを心配することなく、繰り返しなしでランダムなシーケンス (つまり、乱数ジェネレーターが許可する限りランダム) を実現できます。

于 2013-05-01T06:27:49.220 に答える