7

カードのデッキをシャッフルするカードのデッキのコードを書いています。私はコードをテストしましたが、それが実際に正しく実行されているはずのことを実行しているかどうかは本当にわかりませんか?どう思いますか?

これは、シャッフルメソッドのコードです。

public void shuffle()
{
    for( int x = myDeck.size(); x > 0 ; x--) 
     {
        Random rn = new Random();
        int index1 = rn.nextInt(52);
        Card c = myDeck.remove(index1);
        myDeck.add(c);
     }
  }

私の出力はその数がシャッフルされているように見えますが、スペードのハートなどのカードの名前ではありません、

たとえば、これはコードをテストしたときの出力です。

Deuce of spades
Seven of spades
Eight of spades
Ace of spades
Three of hearts
Five of hearts
Six of hearts
Seven of hearts
Nine of hearts
Ten of hearts
Queen of hearts
King of hearts
Ace of hearts
Seven of diamonds
Eight of diamonds
Jack of diamonds
King of diamonds
Three of clubs
Seven of clubs
Nine of clubs
Jack of clubs
Queen of clubs
King of clubs
Ace of clubs
Queen of spades
Deuce of clubs
Three of spades
Nine of diamonds
Four of spades
Four of clubs
Deuce of hearts
Jack of spades
Ten of clubs
Six of diamonds
Jack of hearts
Six of clubs
Four of diamonds
Five of diamonds
Ace of diamonds
Four of hearts
Nine of spades
Ten of spades
Five of spades
Three of diamonds
Six of spades
Five of clubs
Deuce of diamonds
Eight of hearts
King of spades
Ten of diamonds
Eight of clubs
Queen of diamonds

いつも繰り返される名前があるように。シャッフルのポイントはそれを混ぜることなので間違っていますか?

これが実際の質問です。カードをプレイするときは、もちろん、デッキをシャッフルすること、つまり、カードがランダムな順序で配られるように物事を配置することが重要です。これを達成する方法はいくつかあります。1つの戦略は、デッキからランダムにカードを繰り返し選び、それを最後に移動することです。次のコードは、Randomクラス(オンラインコースの「ArrayLists」セクションの8ページで会った)を使用して、そのような「選択して最後に移動」操作を実行します。

Random rn = new Random();
int index1 = rn.nextInt( 52 );
Card c = myDeck.remove( index1 );
myDeck.add( c );

デッキを効果的にシャッフルするには、この操作を何度も(たとえば500回)繰り返す必要があります。単一のRandomオブジェクトとforループを使用してmyDeckをシャッフルするDeckクラスの新しいインスタンスメソッドshuffleを作成します。mainメソッドを適切に変更した後、それを使用して新しいコードをテストします。

だから私の主な質問は:私はこれを間違っているのですか?

4

4 に答える 4

15

に変更rn.nextInt(52);するだけrn.nextInt(x)で、適切なFisher-Yates shuffleが得られます。52 回を超える反復を行う必要はありません。

これが機能する理由:

  • 最初の反復 (xが 52 のとき) では、完全なデッキからランダムにカードを選択し、最後に移動します。

  • 2 回目の反復 ( が 51 のとき) では、残りのxカードからランダムなカードを選択し、最後に移動します。

    ...等々。

  • 52 回の繰り返しの後、最初に選択されたカードが最初のインデックスに配置されます。このカードはデッキ全体からランダムに選ばれたため、各カードの確率は等しくなります。

  • 2 番目のインデックス、3 番目のインデックス、... についても同様です。

  • したがって、デッキの各可能な順列は、同じ確率であるということになります。


(本番コードではCollections.shuffle、これらの状況でのみ使用してください。)

于 2012-08-06T21:05:14.587 に答える
2

これを行う最善の方法は、組み込みのCollections.shuffle()メソッドを使用することです。これは、ArrayList をランダムな方法で (またはランダムに近い方法で) シャッフルします。

現時点でのロジックの問題は、デッキからランダムにカードを選んで最後に置き、それを 52 回行っていることです。これで、多くのカードに対してこれを複数回行うことになり、まったく行わないものもあるという良い変更が得られました。したがって、ランダム化されていないように見える多くのカードで発生している問題です。

デッキ内のカードの数に対してこの操作を行う必要があるというロジックがあるようですが、これには欠陥があります。何度も実行する必要があります。

2 つの主な論理的解決策があります。まず、これを何度も行うことができます。つまり、現在行っているよりも 10 倍多く行うか、組み込みの (またはより効果的な) シャッフル アルゴリズムを使用するようにコードを再設計することができます。 .

于 2012-08-06T21:06:20.680 に答える
1

質問はヒントを与えます:

デックを効果的にシャッフルするには、この操作を何度も (たとえば 500 回) 繰り返す必要があります。

ループは 52 回しか実行されませんが ( myDeck.size())。したがって、カードを取り外してランダムに 52 回だけ交換します。それだけでは十分ではないようです。

ps: よりも書く方が一般的for(int i = 0; i < max; i++)ですfor (int i = max; i >0 i--)

于 2012-08-06T21:05:05.250 に答える
0

ループを次のように変更します。

  ArrayList<Integer> myDeck = new ArrayList<Integer>();
   for(int i=0; i< 52; i++){
       myDeck.add(i);
   }
   Random rn = new Random();    
   for( int x = 52; !myDeck.isEmpty() ; x--) {                
        int index1 = rn.nextInt(myDeck.size());
        //Card c = (Card)myDeck.remove(index1);  -> this comment here should be removed
        System.out.print(index1 + ", ");
     }
  }

この方法では、同じカードを繰り返し選択することはありません。さらに、カードを削除すると常に変化する数字 (セル) < myDeck.size() を選択し、デッキにカードがない場合は救済します。

于 2012-08-06T21:27:13.623 に答える