2013-05-01 5 views
5

デッキをシャッフルするためのプログラム(主に方法)を書くように求められました。私は、以下のプログラムを書いた:2つの値を交換した後のカードデッキのシャッフル、冗長性

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

} 

をしかし、次の通りである上記のシャッフル方法で論理エラーがあります:私は、私は 2回交換するよ、カード番号42でカード番号4を交換するとします。私はこれをしない方法があるのだろうか?

私はここつのポストを確認:Shuffling a deck of cards

をしかし、それは私には意味がありませんでした。あなたはCollections.shuffleと実装を比較することができ

+0

私が知っている限り、これは配列内の2つの要素を入れ替える方法です(少なくともJavaの場合) – MadProgrammer

+0

@MadProgrammer:スワップを行う3行は問題ありませんが、シャッフルの一般的な方法はありません。幸いにも、それは簡単に修正されます。 –

+0

@JonSkeet私は数分間壁に頭を向けなければならなかったが、あなたは何を意味するのかを見て、OPは各反復の "全体"リストをシャッフルしている。 。clear as mud;) – MadProgrammer

答えて

15

からの抜粋ですこれをやっていないのいずれかの方法は何ですか?

絶対に。 1つのカードをと交換する代わりに、の後にのカードを交換するだけです。

いずれのカードでも、選択されていない「残りのカードすべて」のスロットiにあるカードが実際に選択されています。それはという概念的にはのカードのリストから始まり、のカードを無作為に取り除いて新しいシャッフルコレクションに入れます。あなたが実際に行っている間に場所を交換しているという事実は無関係です。いつでも残りのスロットから無作為に選んでいます。

詳細については、Wikipedia article on the Fisher-Yates shuffleをお読みください。

(一部の実装では、終了から入れ替えるので、要素xが範囲[0, x]のランダムな要素と交換される。それは、私が説明した内容と同等ですが、ちょうどミラー。個人的に私はそれが簡単に最初を考えることを見つけますコレクションの一部はシャッフルされた部分であるとは限りませんが、それは固有の違いではなく、私の部分では失敗です)List<Card>を使用する場合、Collections.shuffleを使用してこれのためのコードを書いてください。

+2

+1 'Collections.shuffule' – MadProgrammer

7

、1つは間違いなく右に動作しますが、これは私が思ったんだけど、SRC

// Shuffle array 
    for (int i=size; i > 1; i--) 
     swap(arr, i-1, rnd.nextInt(i)); 

... 

    private static void swap(Object[] arr, int i, int j) { 
     Object tmp = arr[i]; 
     arr[i] = arr[j]; 
     arr[j] = tmp; 
    } 
5

時には、デッキをシャッフルする最善の方法は、でなく、をシャッフルすることです。あなたは既に乱数の使い方を知っているので、Fisher-Yatesシャッフルの修正を使用して、重複なしで無作為にカードを抽出することができます。

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

詳細については、hereを参照してください。ただし、以下の1〜9の3つの数字を抽出することにします。


(明らかに長さ9の)(unshuffled)リスト{1,2,3,4,5,6,7,8,9}で始まり、その長さに基づいて乱数を生成する(Javaはない0~8含め、我々が使用すると仮定すると、ゼロベースの索引から) 。たとえば、最初の乱数が4であるとします。

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

次に、長さ(0〜7を含む)に基づく乱数を使用してもう一度戻ります。この場合、今みましょう7.

の長さと{1,8,3,4,9,6,7}を与え、我々は2ある1オフセットで乱数1

アイテムを得るでしょうし、我々は最初のステップとして、同じリストを調整します現在の長さ7に基づいて3番目の乱数を取得し、再び4になるとします。その項目は今度は9になりますので、リストを変更して長さが6の{1,8,3,4,7,6}になりました。

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

+0

なぜ最後の位置に移動する必要がありますか?アイテムを削除するだけです。 – Paparazzi

+1

@Paparazzi、答えは単純な配列以上の何も仮定していないので、削除演算子はありません。ベクトル型コレクションを使用している場合は、上記の項目がすべて下にシフトされているため、効率が悪い可能性があります。 – paxdiablo

関連する問題