无法在C ++中生成一副纸牌

时间:2018-12-06 22:34:36

标签: c++

我正在做一个项目,用C ++模拟扑克游戏。当前,每当我在Visual Studio中以调试模式通过该功能时,我似乎可以使用的功能。但是,每当我实际运行该程序时,控制台光标都会闪烁,并且似乎不会在类初始化之后执行。如果我在调试模式下运行,它将在生成卡的某个时候停止。我知道即时生成卡并不是随机的,为简单起见,我将其删除。

Card类:

class Card
{
    public:
    string value;
    string suit;
    int ValToInt();
};

Deck类:

class Deck
{
public:
    int deckSize;
    Card deck[52];
    void RandCard(Card &card);
    Deck();
};

RandCard功能:

void Deck::RandCard(Card &card)
{
    bool duplicateCard = false;
    Card tempCard;
    const string valueList[13] = { "A","2","3","4","5","6","7","8","9","10","J","Q","K" };
    const string suitList[4] = { "s", "c", "h", "d" };
    do {
        tempCard.value = valueList[rand() % 13];
        tempCard.suit = suitList[rand() % 4];

        for (int i = 0; i < deckSize; i++)
        {
            if ((deck[i].value == tempCard.value) && (deck[i].suit == tempCard.suit))
            {
                duplicateCard = true;
                break;
            }
        }
    } while (duplicateCard == true);
    card = tempCard;
}

默认构造函数以及我如何尝试使用RandCard函数:

Deck::Deck()
{
    deckSize = 0;
    Card emptyCard;
    emptyCard.value = "EMPTY";
    emptyCard.suit = "EMPTY";
    for (int i = 0; i < 52; i++)
    {
        RandCard(deck[i]);
        deckSize++;
    }
}

谢谢您的帮助。

3 个答案:

答案 0 :(得分:2)

如果要混合生成52张牌,最好的选择是生成52张牌并使用std :: shuffle或std :: random_shuffle。这是有原因的。想象以下情况:

您已经生成了51张卡,并且即将生成第52张卡。您正在随机生成一张卡,并检查它是否已经在卡组中。获得唯一卡的几率是1/52。对于第51张卡,赔率是2/52,依此类推。因此,您在进行不必要的无数次迭代以随机生成最后几张卡。实际上,在第19张卡之后,重复一张卡的可能性非常高。因此,std :: shuffle是您的朋友。

对于it stops at some point during the generation of the cards,请参阅@Stephan Lechner的评论。

  

一旦plicateCard在某处变为真,它将再也不会为假。然后(duplicateCard == true)将会是一个无限循环

答案 1 :(得分:1)

由于问题被标记为c++,因此我想指出OP的示例代码正在使用旧的C编码样式。

一些注意事项:

  • 在普通enums上使用std::string
    • 卡片的花色有限,因此请使用有限的enum
  • 使用std::vector / std::array代替C样式的数组
  • 使用STL的algorithm
  • 使用static constexpr变量作为常量而不是魔术数字
  • 使用C ++ operator overloading

考虑这些注意事项并使用c++11功能,您可以像这样重写代码:

Value

enum class Value : int8_t
{
    None = -1,
    Two,
    Three,
    Four,
    Five,
    Six,
    Seven,
    Eight,
    Nine,
    Ten,
    Jack,
    Queen,
    King,
    Ace
};

Suit相同

enum class Suit : int8_t
{
    None = -1,
    Heart,
    Diamond,
    Spade,
    Club
};

现在您可以定义一个函数以返回字符串表示形式

template<typename T>
std::string to_string(const T&);

template<>
std::string to_string<Value>(const Value& value)
{
    std::string str;
    switch(value)
    {
    case Value::None:  str = "None"; break;
    case Value::Two:   str = "2"; break;
    case Value::Three: str = "3"; break;
    case Value::Four:  str = "4"; break;
    case Value::Five:  str = "5"; break;
    case Value::Six:   str = "6"; break;
    case Value::Seven: str = "7"; break;
    case Value::Eight: str = "8"; break;
    case Value::Nine:  str = "9"; break;
    case Value::Ten:   str = "T"; break;
    case Value::Jack:  str = "J"; break;
    case Value::Queen: str = "Q"; break;
    case Value::King:  str = "K"; break;
    case Value::Ace:   str = "A"; break;

    default: break;
    }
    return str;
}

template<>
std::string to_string<Suit>(const Suit& suit)
{
    std::string str;
    switch(suit)
    {
    case Suit::None:    str = "None"; break;
    case Suit::Heart:   str = "h"; break;
    case Suit::Diamond: str = "d"; break;
    case Suit::Spade:   str = "s"; break;
    case Suit::Club:    str = "c"; break;
    default: break;
    }

    return str;
}

(在名称空间中)定义常量

namespace constants
{
static constexpr const size_t num_values = 13;
static constexpr const size_t num_suits  = 4;
static constexpr const size_t num_cards  = num_values * num_suits;
}

现在您的Card类可以看起来像这样

class Card
{
public:

    constexpr Card() = default;
    constexpr Card(Value value, Suit suit) : m_value(value), m_suit(suit) {}

    Value  value()  const noexcept { return m_value; }
    Suit   suit()   const noexcept { return m_suit;  }

    Card& operator++() // 
    {
        if(m_value == Value::Ace)
            m_suit  = static_cast<Suit>((static_cast<int8_t>(m_suit) + 1) % constants::num_suits);

        m_value = static_cast<Value>((static_cast<int8_t>(m_value) + 1) % constants::num_values);
        return *this;
    }
    Card  operator++(int)
    {
        Card result(*this);
        ++(*this);
        return result;
    }

private:
    Value m_value{};
    Suit  m_suit{};

};

std::ostream& operator<<(std::ostream& os, const Card& card)
{
    os << to_string(card.value()) << to_string(card.suit());
    return os;
}

稍后使用operator++初始化Deck时,在Deck类中使用iota重载(由于@ user4581301)。

最后,您的Deck类可以如下所示:

class Deck
{
public:
    using Type           = std::array<Card, constants::num_cards>;
    using iterator       = Type::iterator;
    using const_iterator = Type::const_iterator;

    iterator       begin()       noexcept { return m_deck.begin(); }
    const_iterator begin() const noexcept { return m_deck.begin(); }
    iterator       end()         noexcept { return m_deck.end();   }
    const_iterator end()   const noexcept { return m_deck.end();   }

    void init()
    {
        std::iota(m_deck.begin(), m_deck.end(), Card(Value::Two, Suit::Heart));
    }

    void randomInit()
    {
        init();
        std::shuffle(m_deck.begin(), m_deck.end(), m_g);
    }

private:

    Type m_deck;
    std::random_device m_rd;
    std::mt19937 m_g{m_rd()};
};


std::ostream& operator<<(std::ostream& os, const Deck& deck)
{
    for(const auto& card : deck)
        os << card << ' ';

    return os;
}

要测试Deck::randomInit()

int main(int argc, char** argv)
{
    Deck deck;

    deck.randomInit();
    std::cout << deck << '\n';

    return 0;
}  

LIVE DEMO

答案 2 :(得分:0)

您可以通过嵌套的for循环生成甲板。这是一个近似值。

auto p = 0; // Deck position
for(auto i = 0; i < 13; i++) { // values
      for(auto j = 0; j < 4;  j++) {  // suits
          deck[p++] = /*Call constructor here.*/
      }
}   

然后,您可以执行@Sahil所说的话。

编辑:

我忘记指定仅适用于枚举。否则将很难将整数映射到字符串。