Мне нужна помощь в создании колоды карт в Stack Overflow

Я пытаюсь создать колоду карт с помощью 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'));
}

2

Решение

Есть 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.

Отредактировано:

Кстати, вы должны следовать Эрик и совет Ханса Пассанта (см. комментарии к вашему вопросу). То, как вы делаете перетасовку, неправильно способ сделать это в том смысле, что существует гораздо более простой / более естественный / более чистый способ. Увидеть ниже,

/**
* 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, и в очень простой схеме он должен вызываться только один раз в самом начале вашей основной функции. В вашем случае, без вызова setCard () для каждой имеющейся у вас карты, вы можете получить 52 раза одну и ту же карту, даже если они были сгенерированы. случайным образом ( увидеть http://en.wikipedia.org/wiki/Pseudorandomness ).

У меня есть время, вы должны посмотреть на Случайный заголовок стандартной библиотеки C ++ который предоставляет гораздо больше C rand lib. Там даже есть метод случайного <алгоритм>!

3

Другие решения

Вы генерируете карты и отбрасываете уже присутствующие. Лучшим способом было бы генерировать их все линейно, и они перемешивали колоду.

Чем больше растет ваша колода, тем дольше она находит новую действительную карту

5

Просто начните со свежей упаковки. А затем пройдите через них, меняя текущий на случайный. Сделайте это семь раз, как они сделали.

Увидеть 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;
}
}

Это устраняет проблему при загрузке пакета и тасует его.

0

Вот Это полностью функциональный пример, который я сделал в классе в прошлом семестре, он работает довольно хорошо.

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)));
}
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;
}
0
По вопросам рекламы [email protected]