我正在尝试使用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'));
}
答案 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/shuffle和http://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;
}