我需要帮助在C ++中生成一副牌

时间:2014-11-16 01:16:02

标签: c++ playing-cards

我正在尝试使用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类的构造函数中,我有一个for()循环,它生成所有52张牌并确保牌组中没有匹配的牌。至少它应该。问题是,我不能使循环迭代超过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'));
}

5 个答案:

答案 0 :(得分:5)

您正在生成卡片并丢弃已存在的卡片。一种更好的方法是线性地生成所有这些并将它们随机化。

您的套牌越多,找到新的有效卡的时间就越长

答案 1 :(得分:3)

52张牌组中有13个

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时无限循环的原因。

已编辑:

顺便说一句,你应该遵循Eric's和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/shufflehttp://blog.codinghorror.com/the-danger-of-naivete

另外请考虑(正如drescherjm在他的评论中所说的那样)将调用放在本课程之外。对srand的调用会重置rand函数的种子,并且在一个非常基本的方案中,只应在main函数的最开头调用一次。在您的情况下,如果没有为您拥有的每张卡调用setCard(),即使它们是随机生成(参见http://en.wikipedia.org/wiki/Pseudorandomness),您最终可能会获得同一张卡的52倍。 / p>

我有时间你应该看看C++ random standard library header,这提供了更多的C rand lib。甚至在<algorithm>中也有一种随机方法!

答案 2 :(得分:0)

刚开始吃一包。然后通过它们随机地交换当前的那个。这样做了七次。

请参阅https://www.math.hmc.edu/funfacts/ffiles/20002.4-6.shtml

代码排序

int pack[52];
for (int i = 0; i < 52; ++i) {  pack[i] = i; }
for (int shuffle = 0; shuffle < 7; ++ shuffle) {
    for (int i=0; i < 52; ++i) {
       j = rand() % 52;
       t = pack[i];
       pack[i] = pach[j];
       pack[j] = t;
    }
}

这样可以在加载包时解决问题,并将其改组。

答案 3 :(得分:0)

Here是我上学期在课堂上做的一个功能齐全的例子,效果非常好。

Deck::Deck()
{
    cout << "Constructor was run" << endl;
    nextCard = 0;
    cards = new Card[numCards];
    int c = 0;
    for (int s = 0; s < Card::numSuits; s++)
    {
        for (int r = 1; r <= Card::numRanks; r++)
        {
            Card cd(s, r);
            cards[c++] = cd;
        }
    }
    srand(static_cast<int>(time(0)));
}

答案 4 :(得分:0)

我宁愿先准备完整的无盖板甲板,然后每次用户抽取一张牌,从甲板上随机挑一张,用甲板上的最后一张牌替换它在甲板上的位置,减少甲板的大小。

int deck[52];
int size=0;

void init()
{
    for (int i=0; i<52; i++)
        deck[i]=i;
    size=52;
}

int draw()
{
    if (!size)
        init();
    int i = rand()%size;
    size--;
    int card = deck[i];
    deck[i]=deck[size];
    return card;
}