1. ホーム
  2. c++

[解決済み] C++でカードのデッキを生成するのを手伝ってほしい

2022-03-14 15:12:03

質問

C++を使用して、カードのデッキを生成しようとしています。すでにすべてのコードを書きましたが、どうしても解けない問題があります。

Deck::Deck(){
         Card card;
         bool match = false;
         for (int i=0;i<47;i++){
             do{
                card.setCard();
                match = cardInDeck(card, i);
                }while(match == true);
             match = false;
             cards[i] = card;
         }
         numDrawn = 0;
    }

Deckクラスのコンストラクタでは、52枚のカードをすべて生成して、デッキに一致するカードがないことを確認するfor()ループを用意しています。少なくとも、そうする必要があります。しかし、このループを47回以上繰り返しても、うまくいかないのです。47回を超えると、実行時にコンソール画面が空っぽになり、カーソルが点滅する以外には何も表示されません。47を超える数値の何が原因で動作しなくなるのか、よくわかりません。広範囲にテストした結果、0から48の間のすべての数字が動作しました。

もしかしたら、私のコードのどこかに、私が見ていないだけで、小さなエラーがあるのかもしれません。本当にわかりません。しかし、私は本当に私が得ることができる任意の助けを感謝します。

以下は私の全コードです。

#include<iostream>
#include<stdlib.h>
using namespace std;

void run();

class Card{
      private:
              char suit;
              int value;
      public:
             Card();
             void setCard();
             void getCard();      
             int getValue();
             int getSuit();
      };

class Deck{
      private:
              Card cards[52];
              int numDrawn;
      public:
             Deck();
             void shuffle();
             void draw();
             bool cardInDeck(Card card, int index);
      };

int main(){
    run();
}

Card::Card(){
     srand(time(NULL));
     value = rand() % 12 + 1;
     suit = rand() % 4 + 1;            
}

void Card::setCard(){
     value = rand() % 12 + 1;
     suit = rand() % 4 + 1;            
}

void Card::getCard(){
     cout<<" ----"<<endl<<"|    |"<<endl<<"| ";

     if (value == 1) cout<<'A';
     else if (value == 10) cout<<'J';
     else if (value == 11) cout<<'Q';
     else if (value == 12) cout<<'K';
     else cout<<value;

     if (suit == 1) cout<<(char)3;
     else if (suit == 2) cout<<(char)4;
     else if (suit == 3) cout<<(char)5;
     else cout<<(char)6;

     cout<<" |"<<endl<<"|    |"<<endl<<" ----"<<endl;
}

int Card::getSuit(){
    return suit;
}

int Card::getValue(){
    return value;
}

bool Deck::cardInDeck(Card card, int index){
     bool match;
     for(int i=0;i<=index;i++){
             if((card.getValue() == cards[i].getValue()) && (card.getSuit() == cards[i].getSuit())){
                  match = true;
                  break;
                  }
             else match = false;
     }
     return match;
}

Deck::Deck(){
     Card card;
     bool match = false;
     for (int i=0;i<47;i++){
         do{
            card.setCard();
            match = cardInDeck(card, i);
            }while(match == true);
         match = false;
         cards[i] = card;
     }
     numDrawn = 0;
}

void Deck::shuffle(){
     Card card;
     bool match = false;
     for (int i=0;i<52;i++){
         do{
            card.setCard();
            match = cardInDeck(card, i);
            }while(match == true);
         match = false;
         cards[i] = card;
     }
     numDrawn = 0;        
}

void Deck::draw(){
     cards[numDrawn].getCard();
     numDrawn++;
}

void run(){
     Deck cards;
     char choice;
     int cardsDrawn = 0;
     cout<<"Enter 's' to shuffle the deck, 'd' to draw a card, or 'x' to exit:  ";
     do{
     cin>>choice;
     switch(choice){
                    case 'X':
                    case 'x':break;
                    case 'S':
                    case 's':cards.shuffle();
                             cout<<"Deck shuffled."<<endl;
                             cardsDrawn = 0;
                             break;
                    case 'D':
                    case 'd':if (cardsDrawn == 52){
                                 cout<<"Out of cards. Deck reshuffled."<<endl;
                                 cards.shuffle();
                                 cardsDrawn = 0;
                                 break;
                             }
                             else{
                                  cards.draw();
                                  cardsDrawn++;
                                  break;
                             }
                    default: cout<<"Invalid entry.\a Enter a valid option('s','d','x'):  ";
                    }
     }while((choice != 'x') && (choice != 'X'));
}

解決方法は?

13個あります。 52枚のカードで

Card::Card(){
     srand(time(NULL));
     value = rand() % 13 + 1;
     suit = rand() % 4 + 1;            
}

void Card::setCard(){
     value = rand() % 13 + 1;
     suit = rand() % 4 + 1;            
}

12 * 4 -> 48

13 * 4 -> 52

12の値を持つ元のコードでは48種類のカードしか生成できないので、52を生成しようとすると無限ループになるのはこのためです。

編集中です。

ちなみに、フォローすべきは エリックの とHans Passant(質問に対するコメント参照)のアドバイスがあります。シャッフルのやり方は いけない もっとシンプルで自然でクリーンな方法があるという意味で。以下をご覧ください。

/**
 * Forward counting implementation of Fisher-Yates / Knuth shuffle.
 * see https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle
 */
template< typename A >
void shuffle ( A& a, int i, const int j ) {

    // one item left => no need to shuffle
    const int _j = j - 1;

    for ( ; i < _j ; ++i ) {

        // pick item uniformly at random to put at ith position
        // once moved the item will stay in place
        const int k = i + rand() % ( j - i );

        // swap
        auto tmp = a[i];
        a[i] = a[k];
        a[k] = tmp;

    }
}

の場合、52種類のカードをすべて一度に生成する必要があります。

Card::Card( const int value, const int suit ) {
     this->value = value;
     this->suit = suit;            
}

// we do not need this anymore
// void Card::setCard(){
//     value = rand() % 13 + 1;
//     suit = rand() % 4 + 1;            
// }

Card cards[52];

int i = 0;
for ( int suit = 1 ; suit <= 4 ; ++suit ) {
    for ( int value = 1 ; value <= 13 ; ++value ) { 
        cards[i] = Card( value, suit );
        ++i;
    }
}

そして最後にデッキをシャッフルします

shuffle( cards, 0, 52 );

この一般的な問題についての詳細な参考文献 : http://bost.ocks.org/mike/shuffle http://blog.codinghorror.com/the-danger-of-naivete .

また、(drescherjmのコメントで提案されているように)srandの呼び出しをこのクラスの外に置くことを検討してください。srand の呼び出しは rand 関数の種をリセットするもので、基本的には main 関数の冒頭で一度だけ呼び出されるべきものです。あなたの場合、カードごとに setCard() を呼び出さないと、同じカードが 52 回も生成されてしまうかもしれません。 ランダム ( 参照 http://en.wikipedia.org/wiki/Pseudorandomness ).

時間があれば C++ランダム標準ライブラリヘッダ C の rand lib をはるかに上回る機能を提供します。にはシャッフルメソッドもあります。 <algorithm> !