我正在做一个项目,用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++;
}
}
谢谢您的帮助。
答案 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样式的数组algorithm
库static constexpr
变量作为常量而不是魔术数字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;
}
答案 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所说的话。
编辑:
我忘记指定仅适用于枚举。否则将很难将整数映射到字符串。