C++ Deck Of Cards Shuffling Functions

2019-07-20 20:00发布

问题:

I am trying to build a poker game using C++. The deck shuffling function is giving me some issues. Every time that I run the program that initializes the deck, shuffles it, and then prints the deck I get the same output:

Shuffling the cards and dealing...
Printing deck...
KD
6S
7D
QD
5C
JH
9S
6D
7H
JD
QH
3C
7S
3H
TC
5D
5S
3D
AD
7C
4H
6H
JC
TS
4D
JS
QC
AH
9C
2D
5H
8C
TD
4S
2S
KS
2C
8D
KC
2H
9H
6C
KH
3S
QS
8S
8H
4C
AS
AC
9D
TH

Using the classes Deck and Card I have the relevant functions defined as follows:

Deck::Deck(){
    for (int i = 0; i < 4; i++) {
        for (int j = 0; j < 13; j++) {
            cards[i * 13 + j].suit = i;
            cards[i * 13 + j].rank = j;
        }
    }
    Card::suits[0] = "D";
    Card::suits[1] = "S";
    Card::suits[2] = "H";
    Card::suits[3] = "C";
    Card::ranks[0] = "2";
    Card::ranks[1] = "3";
    Card::ranks[2] = "4";
    Card::ranks[3] = "5";
    Card::ranks[4] = "6";
    Card::ranks[5] = "7";
    Card::ranks[6] = "8";
    Card::ranks[7] = "9";
    Card::ranks[8] = "T";
    Card::ranks[9] = "J";
    Card::ranks[10] = "Q";
    Card::ranks[11] = "K";
    Card::ranks[12] = "A";
}

void Deck::print(){
    cout << "Printing deck..." << std::endl;
    for (int i = 0; i < 52; i++) {
        cout << Card::ranks[cards[i].rank] << Card::suits[cards[i].suit] << endl;
    }
    cout << endl;
}

void Deck::shuffle(){
    top = 51;
    int x;
    Card tempCard;
    for (int i = 0; i < 4; i++) {
        for (int j = 0; j < 13; j++) {
            cards[i * 13 + j].suit = i;
            cards[i * 13 + j].rank = j;
        }
    }
    cout << "Shuffling the cards and dealing..." << endl;
    for (int i = 0; i < 52; i++) {
        x = rand() % 52;
        tempCard = cards[i];
        cards[i] = cards[x];
        cards[x] = tempCard;
    }
}

Is there something that I am doing wrong? Why do I always get the same result when it should be random? Thanks.

回答1:

Assuming you can use C++11 features, you can use this (taken from https://stackoverflow.com/a/19728404/341065):

#include <random>

std::random_device rd;     // only used once to initialise engine
std::mt19937 rng(rd);      // random-number engine used
std::uniform_int_distribution<int> uni(min,max); // guaranteed unbiased

auto random_integer = uni(rng);


回答2:

Your code has several problems with regard to randomness:

  • You do not seed your randomizer with srand, so your random number generator will always start from a default seed value. A common practice is to seed it with the current time with srand(time(NULL)). Note that you should seed the randomizer only once in your program.

  • You use x = rand() % 52;. This is bad because:

    1. Typical rand() implementations are notorious for not being very random in their low-order bits.

    2. The number of potential results from rand() (RAND_MAX+1) is unlikely to be divisible by 52. To understand why this is a problem, imagine an extreme case where rand() is perfectly uniform, can return only one of { 0, 1, 2 }, and that you do rand() % 2. It should be clear that that is far more likely going to produce 0 than 1. You can fix this by using a loop, as described in an SO answer by R...

  • For each card, you always randomly swap it with one of the 52 cards. This naive shuffling algorithm is close to being correct but is subtly wrong, which will lead to bias. You instead should use the Fisher-Yates shuffling algorithm. Since you are using C++, you could just use std::random_shuffle/std::shuffle.



回答3:

You need to seed the random number generator. Specifically call srand() once at the beginning of the program. One common way to do this is:

srand(time(NULL));


回答4:

the rand() method, if not initialized, return always the same "random" number. You have to initialize the starting point of the generation of the numbers with the function srand(). This function take a parameter which allows to generate different numbers. Put this line

srand(time(0));

before the rand function and you will have always different numbers. (time(0) is the system time. You can put here a number like 100, but you will have always same number. with time(0) the number will change every time).