2009-05-28 36 views
1

私はC++をかなり新しくしており、ポインタと参照のある関数パラメータをあまり理解していません。私はFisher-Yatesシャッフルでシャッフルしたいカードを用意しています。デッキはC++配列シャッフル

Card *deck[deckSize]; 

と宣言されており、deckSizeは24として宣言されています。次に、配列が初期化されます。 私はその後、シャッフル機能を呼び出す:私はワンセグ障害を取得シャッフル機能を呼び出した後、カードの価値を印刷しようとした場合

void shuffle (Card * deck[]) { 
    int deckSize = 24; 
    while (deckSize > 1) { 
     long int k = lrand48(); 
     k = k %24; 
     deckSize--; 
     Card * temp = deck[deckSize]; 
     deck[deckSize] = deck[k]; 
     deck[k] = temp; 
    } 
} 

を。どのようにこれを正しく行うためのポインターですか?

+0

この行にtempとは何ですか?deck [k] = temp ;? –

+0

"deckSize--"の直後に "Card * temp = deck [deckSize]"が表示されていないようです。コピー+貼り付けエラーですか、それとも実際にコードから抜けている行ですか? –

+1

私はそのコードに全く何か悪いことはありません。私は問題は、カードの値や配列の初期値を印刷することであると推測します。それらのコードを投稿する必要があります。 – TrayMan

答えて

2

それはあなたの問題は一見正常に見える掲示コード、から来ていないことに見えますが、その周辺のコードから。

カードの標準的な容器を使用するとどうなりますか?あなたはそれを記入し、最初に印刷してOKかどうかを確認し、シャッフルしてからもう一度印刷する必要があります。

#include <vector> 
std::vector<Card> deck; // Empty for now. Must be filled with cards. 


void shuffle (std::vector<Card> & deck) 
{ 
    int deckSize = 24; 
    while (deckSize > 1) 
    { 
     long int k = lrand48(); 
     k = k %24; 
     deckSize--; 
     Card temp = deck[deckSize]; 
     deck[deckSize] = deck[k]; 
     deck[k] = temp; 
    } 
} 
1

あなたはポインタの配列としてdeckを宣言しましたが、そのためのスペースは割り当てられませんでした。スペースを割り当てずに参照解除すると、seg-faultが発生します。

+0

彼は彼の質問で初期化されたと言った –

+0

@yz私は、 "ポインタと参照の関数パラメータを理解していない"人がポインタのスペースを割り当てることが "初期化"の一部であることを認識していない。 – Trent

+0

私は配列をループし、 "deck [i] = new Card()"で各カードを初期化します。それはスペースを割り当てるのに十分ですか? – Everett

6

私のC/C++はさびているが、私はあなたの宣言だと思う:

Card *deck[deckSize]; 

はカードへのポインタの配列を宣言しています。これが欲しいのですか?

Card deck[deckSize]; 

、その後シャッフル宣言:

void shuffle (Card deck[]) 

心アレイに保つには、0インデックスされています。 24番目の要素にアクセスするのかどうかは分かりませんが、それはブービーです。

+0

私はカードデッキ[deckSize]とは思えません。有効なC++です。 – Alan

+0

deckSizeが定数でない限り。 – Alan

+0

私はdeckSizeが定数であると仮定しました。 ASSuME :) – n8wrl

1

即時ニックピックの1つです。ほとんどの乱数の実装では、下半分のランダム性が低いため、常に乱数の上半分を使用する必要があります。だから、長い場合は、より良いランダム性を得るためにk = (k >> 24) % 24を使用することができます32ビットです。

第2に、ここでの問題は、温度を設定していないことです。コードには、temp = deck[deckSize];の行が必要です。

これが役に立ちます。

編集

さらにnitpick、あなたの乱数ジェネレータも十分にかかわらず、高いビットまたは低ビットを使用してのカードのデッキをシャッフルするのに十分な大きさではありません。 48ビット長のシーケンスしかありませんが、デッキをシャッフルするには、少なくとも226ビットの長いシーケンス(52!、デッキをシャッフルする方法の数は226ビットの長さです)が必要です。

+0

:乱数。かなり音質の良いこのサウンドは、最高のアドバイスです。 – Trent

+0

申し訳ありませんが、人間と対戦しているかどうかは関係ありませんが、シミュレーションを行っている場合、結果はまったく信頼できません。彼はその事実を知らなかった。 –

+0

乱数ジェネレータの範囲に関するアドバイスが有効です。あなたがカードをプレイしているのかどうかは問題ではありませんが、シャッフルを使って誰がより良い学校に通うのか、誰がそうでないのか(私はここでの経験から話します)を判断するのであれば、 :これは公正ですか?さて、あなたはおそらくk =(k >> 24)%24をしたくないでしょう - それはあなたにかなり限られた乱数ジェネレータを残します。 (範囲[0,23] – Thanatos

1
Card *deck[deckSize]; 

は、私はあなたがしたいと思う:

Card *deck = new Card[deckSize]; 
+0

'deckSize'はコンパイル時定数です。したがって、' Card * deck [deckSize] 'は完全に細かく、動的割り当て。 –

+0

いいえ、間違っています。あなたはそれがコンパイル時定数であると仮定しますが、あなたは確信することはできません。猫は生きているのか、猫は死んでいるのですか? – Alan

0

基本配列は、上記のように、変数として渡される変数では定義できません。

注意してください。

typename array[SIZE];

の 最後の要素はarray[SIZE-1]、ないarray[SIZE]です。それはおそらくあなたがsegfaultを取得している場所です。

本当にあなたは本当にSTLコンテナを使用しようとすべきではありません。私はそれが呼び出し元のコードを参照するのに役立つかもしれないと思う

1

 

class Card{ 
public: 
    Card(int number):number_(number){} 
    int getNumber(){return number_;} 
// ... 
private: 
    int number_; 
}; 

void shuffle (Card * deck[]) { 
    int deckSize = 24; 
    while (deckSize > 1) { 
     long int k = lrand48(); 
     k = k %24; 
     deckSize--; 
     Card * temp = deck[deckSize]; 
     deck[deckSize] = deck[k]; 
     deck[k] = temp; 
    } 
} 

int main(int argc, char* argv[]){ 
{ 

    const int deckSize=24; 
    Card* deck[deckSize]; 
    for(int i = 0 ; i getNumber()

うまく動作する必要があることを

0

人々はあなたがコンテナを使用していないことを訴えている:STLは(あまりにもシャッフルアルゴリズムを持っています。あなたの配列のサイズを宣言していません。それは問題ではないことに心配しないでください。カードへのポインタの配列を持っている。しかし、私はそれがクラッシュする理由はありません。あなたのコードに基づいて、私が書いたサンプルコードです:

#include <stdio.h> 
#include <stdlib.h> 
#define DECK_SIZE 24 
void shuffle(int deck[]) { 
    int n = DECK_SIZE, t; 
    while (n > 1) { 
     long k = lrand48() % DECK_SIZE; 
     n--; 
     t = deck[n]; 
     deck[n] = deck[k]; 
     deck[k] = t; 
    } 
} 
int main(int argc, char **argv) { 
    int deck[DECK_SIZE], i; 
    for (i = 0; i < DECK_SIZE; ++i) 
     deck[i] = i + 1; 
    shuffle(deck); 
    for (i = 0; i < DECK_SIZE; ++i) 
     printf("%i\n", deck[i]); 
    return 0; 
} 

これを実行すると、正常に動作します。つまり、何か別のことが起こっているということです。デッキにあるすべてのカードの値を印刷してからシャッフルして、そこにセグメンテーションがあるかどうかを確認してみてください。

ただし、コードにエラーがあります。あなたの機能は正しくシャッフルされません。シャッフルする正しい方法は、デッキ全体から選択したカードに各カードを入れ替えるのではなく、Nの位置の各カードを0..Nの範囲から選択したカードと入れ替えることです。各カードをランダムカードと交換した場合、N^Nの可能な結果が得られます。カードを元の場所に戻すと、重複する可能性があります。 3枚のカードデッキでは、これは間違っていることが明らかです。なぜなら、3枚のカードの3!= 6の順列があるにもかかわらず、27種類のシャッフルで終わるので、そのうちいくつかは同じです。問題は、6が27の係数ではないので、いくつかの順列は他の順列よりも可能性が高いということです。

void shuffle_correctly(int deck[]) { 
    int i, t, k; 
    for (i = 2; i < DECK_SIZE; ++i) { 
     k = lrand48() % i; 
     t = deck[i-1]; 
     deck[i-1] = deck[k]; 
     deck[k] = t; 
    } 
} 
+0

Dietrick、私はあなたのルーチンと彼は同等だと思うが、配列の両端で始める。 "i"は2からDECK_SIZEに単調に増加することに注意してください。そして彼の "n"はDECK_SIZEから2に単調に減少します。どちらもフィッシャー - イェイツです。 –

+0

ああ私の間違いは、あなたが正しく指摘したようにlrand48()%nと呼ぶべきです。しかし、これは両方のルーチンが全く異なることを意味します。私は彼が(上記の調整で)Fisher-Yates(http://en.wikipedia.org/wiki/Fisher-Yates_shuffle)であると確信しています。しかし、私はあなたがそうではないと信じています。現在の場所をランダムカード*で現在の場所にシャッフルします。つまり、カードが複数回移動する可能性があります。フィッシャー・イェイツでは一度しか動かないかもしれません。 –

13

ただ、このような<algorithm>で見つかったstd::random_shuffleを使用します:

std::random_shuffle(deck, deck + deckSize); 

をし、自分のデッキをシャッフルすることでこれを回避するために、このようにそれをやってみてください。

2

また、あなたのためにフィッシャー・イエーツを行い

std::random_shuffle(deck, deck + deckSize)

を使用することができます。

しかし、標準的なランダムライブラリでは、すべての可能なランダム置換の中から純粋に選択するビットが不十分である可能性があります。