Create Hand from Deck class without creating new deck object each time a hand is made

I am creating a Black Jack card game. What I am trying to do is create a hand from a deck object without creating a new deck each time I create a hand. I just want to take what is in main and apply it to the Hand class, im just not too sure how to go about doing that.

Here is the code:

Card.h:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#ifndef CARD_H
#define CARD_H

enum Face{A,F2,F3,F4,F5,F6,F7,F8,F9,F10,J,Q,K};
enum Suit{S,C,H,D};

class Card{
    private:
        unsigned char cardNum;
        Face face;
        Suit suit;
    public:
        Card(unsigned char);//take in counter (cardNum) to set each card

        void setFace();
        void setSuit();
  
        unsigned char getCrdNum(){return cardNum;}
        Face getFace(){return face;}
        Suit getSuit(){return suit;}
  
        unsigned char getValu();
    };

#endif 


Card.cpp:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
#include "Card.h"

Card::Card(unsigned char cn){
    cardNum=cn;
    setFace();
    setSuit();
}

void Card::setFace(){
    if(cardNum<4){face = A;}//Ace
    if(cardNum>=4&&cardNum<8){face=F2;}//2's
    if(cardNum>=8&&cardNum<12){face=F3;}//3's
    if(cardNum>=12&&cardNum<16){face=F4;}//4's
    if(cardNum>=16&&cardNum<20){face=F5;}//5's
    if(cardNum>=20&&cardNum<24){face=F6;}//6's
    if(cardNum>=24&&cardNum<28){face=F7;}//7's
    if(cardNum>=28&&cardNum<32){face=F8;}//8's
    if(cardNum>=32&&cardNum<36){face=F9;}//9's
    if(cardNum>=36&&cardNum<40){face=F10;}//10's
    if(cardNum>=40&&cardNum<44){face=J;}//Jack
    if(cardNum>=44&&cardNum<48){face=Q;}//Queen
    if(cardNum>=48&&cardNum<=52){face=K;}//King
}
void Card::setSuit(){
    switch(cardNum){
    //Spade
    case 0:
    case 4:
    case 8:
    case 12:
    case 16:
    case 20:
    case 24:
    case 28:
    case 32:
    case 36:
    case 40:
    case 44:
    case 48: suit=S;break;
    //Clover
    case 1:
    case 5:
    case 9:
    case 13:
    case 17:
    case 21:
    case 25:
    case 29:
    case 33:
    case 37:
    case 41:
    case 45:
    case 49: suit=C;break;
    //Hearts
    case 2:
    case 6:
    case 10:
    case 14:
    case 18:
    case 22:
    case 26:
    case 30:
    case 34:
    case 38:
    case 42:
    case 46:
    case 50: suit=H;break;
    //Diamonds
    case 3:
    case 7:
    case 11:
    case 15:
    case 19:
    case 23:
    case 27:
    case 31:
    case 35:
    case 39:
    case 43:
    case 47:
    case 51: suit=D;break;
    }
}

unsigned char Card::getValu(){
    switch(face){
        case A: return 1;break;
        case F2: return 2;break;
        case F3: return 3;break;
        case F4: return 4;break;
        case F5: return 5;break;
        case F6: return 6;break;
        case F7: return 7;break;
        case F8: return 8;break;
        case F9: return 9;break;
        case F10:
        case J:
        case Q:
        case K: return 10;break;
   }
    return 1;//should never happen
}


Deck.h:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#ifndef DECK_H
#define DECK_H

#include "Card.h"

class Deck{
    protected:
        unsigned char nCards;
        unsigned char *indx;
        unsigned char crdNDek;
        unsigned char nShffle;
        Card **deck;
    public:
        Deck(unsigned char,unsigned char);//take in number of cards the deck will have
        ~Deck();
  
        void setCrdNDek(unsigned char);
        void shuffle();
        void display();
  
        Face getFace(unsigned char crdNum){return deck[crdNum]->getFace();}
        Suit getSuit(unsigned char crdNum){return deck[crdNum]->getSuit();}
  
        unsigned char deal(unsigned char);
        unsigned char getCrdNDek(){return crdNDek;}
        unsigned char getIndx(unsigned char);
};


#endif 


Deck.cpp:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
#include <iostream>
#include <ctime>
using namespace std;
#include "Card.h"
#include "Deck.h"

Deck::Deck(unsigned char nCards,unsigned char nShffle){
    srand(static_cast<unsigned int>(time(0)));
    this->nCards=nCards;
    this->nShffle=nShffle;
    this->crdNDek=0;
    indx=new unsigned char[this->nCards];
    deck=new Card*[nCards];
    for(unsigned char i=0;i<(this->nCards);i++){
        deck[i]=new Card(i);
        indx[i]=i;
    }
    shuffle();
}
Deck::~Deck(){
    for(unsigned char i=0;i<nCards;i++){
        delete deck[i];
    }
    delete []deck;
    delete []indx;
}
void Deck::setCrdNDek(unsigned char crdNDek){
    this->crdNDek=crdNDek;
}
void Deck::shuffle(){
    for(char i=0;i<10;i++){//shuffle deck 10 times(change to user defined shuffle)
        for(char j=0;j<nCards;j++){
            unsigned char rndTemp = rand()%nCards;
            unsigned char temp = indx[j];
            indx[j]=indx[rndTemp];
            indx[rndTemp]=temp;
        }
    }
}
void Deck::display(){
    for(int i=0;i<nCards;i++){
        //Face of Card
        switch(deck[indx[i]]->getFace()){
            case A: cout<<"A"; break;
            case F2: cout<<"2"; break;
            case F3: cout<<"3"; break;
            case F4: cout<<"4"; break;
            case F5: cout<<"5"; break;
            case F6: cout<<"6"; break;
            case F7: cout<<"7"; break;
            case F8: cout<<"8"; break;
            case F9: cout<<"9"; break;
            case F10: cout<<"10";break;
            case J: cout<<"J"; break;
            case Q: cout<<"Q"; break;
            case K: cout<<"K"; break;
        }
        //Suit of card
        switch(deck[indx[i]]->getSuit()){
            case S: cout<<"S ";break;
            case C: cout<<"C ";break;
            case H: cout<<"H ";break;
            case D: cout<<"D ";break;
        }
    }
}
unsigned char Deck::deal(unsigned char n){
    unsigned char hand;
    return hand=indx[crdNDek++];
}


Main:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
#include <iostream>

using namespace std;
#include "Deck.h"

int main(int argc, char** argv) {
  
  
    unsigned char nCards=52;
    unsigned char nShffle=10;
    unsigned char nCrdsD=2;
  
    Deck deck(nCards,nShffle);
  
    //Hand
    unsigned char *hand;
    unsigned char crdsNHnd=0;
    hand=new unsigned char[nCrdsD];
    for(unsigned char i=0;i<nCrdsD;i++){
        hand[i]=deck.deal(i);
        crdsNHnd++;
    }
  
    //Display hand
    for(unsigned char i=0;i<crdsNHnd;i++){
        switch(deck.getFace(hand[i])){
            case A: cout<<"A"; break;
            case F2: cout<<"2"; break;
            case F3: cout<<"3"; break;
            case F4: cout<<"4"; break;
            case F5: cout<<"5"; break;
            case F6: cout<<"6"; break;
            case F7: cout<<"7"; break;
            case F8: cout<<"8"; break;
            case F9: cout<<"9"; break;
            case F10: cout<<"10";break;
            case J: cout<<"J"; break;
            case Q: cout<<"Q"; break;
            case K: cout<<"K"; break;
        }
        switch(deck.getSuit(hand[i])){
                case S: cout<<"S ";break;
                case C: cout<<"C ";break;
                case H: cout<<"H ";break;
                case D: cout<<"D ";break;
        }
    }

    //Display
    //deck.display();
  
    delete []hand;
    return 0;
}
Last edited on
PLEASE learn to use code tags, they make reading and commenting on source code MUCH easier.

http://www.cplusplus.com/articles/jEywvCM9/
http://www.cplusplus.com/articles/z13hAqkS/

HINT: you can edit your post and add code tags.

Some formatting & indentation would not hurt either


Using code tags show you are serious.
@Furry Guy thank you! much better
do you need to know what cards have been used so you can't deal them again?

a simple card game design is a card object (suit, value, in play boolean, whatever)
and a deck of those (can be a container, rather than a full class)
shuffle and deal, mark used cards so can't repeat them...
is that what you seek, or ???
this is what i came up with:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#ifndef HAND_H
#define HAND_H

#include "Deck.h"

class Hand{
    protected:
        unsigned char *hand;
        unsigned char nCrdsD;
        unsigned char crdsNHnd;
    public:
        Hand(Deck*,unsigned char);
        ~Hand();
        
        void display();
        void display(bool);
        unsigned char getCrdsNHnd(){return crdsNHnd;}
        unsigned char getHndVal(Deck&);
        //Hand(const Hand*);
};

#endif 


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
#include <iostream>

using namespace std;

#include "Hand.h"

Hand::Hand(Deck *deck,unsigned char nCrdsD){
    unsigned char n = deck->getCrdNDek();
    crdsNHnd=0;
    this->nCrdsD=nCrdsD;
    hand=new unsigned char[nCrdsD];
    for(unsigned char i=0;i<nCrdsD;i++){
        hand[i]=deck->deal(n);
        crdsNHnd++;
    }
}
Hand::~Hand(){
    delete []hand;
}
void Hand::display(){
    unsigned char valu=0;
    for(unsigned char i=0;i<crdsNHnd;i++){
        Card card(hand[i]);
        switch(card.getFace()){
            case A:   cout<<"A"; break;
            case F2:  cout<<"2"; break;
            case F3:  cout<<"3"; break;
            case F4:  cout<<"4"; break;
            case F5:  cout<<"5"; break;
            case F6:  cout<<"6"; break;
            case F7:  cout<<"7"; break;
            case F8:  cout<<"8"; break;
            case F9:  cout<<"9"; break;
            case F10: cout<<"10";break;
            case J:   cout<<"J"; break;
            case Q:   cout<<"Q"; break;
            case K:   cout<<"K"; break;
        }
        switch(card.getSuit()){
            case S: cout<<"S ";break;
            case C: cout<<"C ";break;
            case H: cout<<"H ";break;
            case D: cout<<"D ";break;
        }
        valu+=card.getValu();
    }
    cout<<static_cast<int>(valu);
}
void Hand::display(bool faceDwn){
    unsigned char i=0;
    if(faceDwn){
        cout<<"XX ";
        i++;
    }
    unsigned char valu=0;
    for(i;i<crdsNHnd;i++){
        Card card(hand[i]);
        switch(card.getFace()){
            case A:   cout<<"A"; break;
            case F2:  cout<<"2"; break;
            case F3:  cout<<"3"; break;
            case F4:  cout<<"4"; break;
            case F5:  cout<<"5"; break;
            case F6:  cout<<"6"; break;
            case F7:  cout<<"7"; break;
            case F8:  cout<<"8"; break;
            case F9:  cout<<"9"; break;
            case F10: cout<<"10";break;
            case J:   cout<<"J"; break;
            case Q:   cout<<"Q"; break;
            case K:   cout<<"K"; break;
        }
        switch(card.getSuit()){
            case S: cout<<"S ";break;
            case C: cout<<"C ";break;
            case H: cout<<"H ";break;
            case D: cout<<"D ";break;
        }
        valu+=card.getValu();
    }
    cout<<static_cast<int>(valu);
}


Now what I have to figure out is after I deal the cards, i need to add cards if the player decides to add a card or not depending on their card values. I think i have an idea:
create a copy constructor for the hand, copy the hand over then add the next card from the deck. But im still a little stumped if thats what is needed to be done.
Last edited on
Somehow I don't understand your logic.
When you create a Hand you would remove the card from the Deck.
When the Deck is empty the game is over and you need to create a new Deck.
You might want to create a Player and a Dealer class as well. Both the player and dealer will have a hand. The dealer will manage the deck.
Also it would be much easier to use a std::vector<Card> in the Hand and Deck class.
1
2
3
4
5
6
void Card::setFace(){
    // lots of code
}
void Card::setSuit(){
    switch(cardNum){
    // lots of code 

Study what cardNum % 4 and cardNum / 4 give you.

1
2
3
    unsigned char nCards=52;
    unsigned char nShffle=10;
    unsigned char nCrdsD=2;

nCards is obvious.
nShffle is pointlessly shorted by one character, what's wrong with nShuffle and keeping things readable?
nCrdsD is wft does this mean?
Keep the code readable, by using meaningful and readable names for things.

> Also it would be much easier to use a std::vector<Card> in the Hand and Deck class.
+1 for this.

You can then have a simple deal function like this, who's only job is to simply move one card from the deck to the hand. Vectors know how many elements they have, so you don't need to track that separately.
 
void deal ( vector<card>&deck, vector<card> &hand);


Also this for shuffling, no need to roll your own.
https://en.cppreference.com/w/cpp/algorithm/random_shuffle
@thmm yeah, i have both a player and dealer class that do just that.

Player.h:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#ifndef PLAYER_H
#define PLAYER_H

#include <string>

using namespace std;

#include "Hand.h"
#include "User.h"

class Player:public User{
    protected:
        Hand *hand;
        string name;
        //Add coin bag
    public:
        Player();
        Player(string);
        
        void setHand(Hand *);
        void prntHnd();
        void prntHnd(bool);
        string getName();
};

#endif 


Player.cpp:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include <string>
using namespace std;

#include "Player.h"

Player::Player(){
    this->name=" ";
    this->hand=nullptr;
}
Player::Player(string name){
    this->name=name;
    this->hand=nullptr;
}

void Player::setHand(Hand *hand){
    this->hand=hand;
}
void Player::prntHnd(){
    this->hand->display();
}
void Player::prntHnd(bool faceDwn){
    this->hand->display(faceDwn);
}
string Player::getName(){
    return this->name;
}


Dealer:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#ifndef DEALER_H
#define DEALER_H
#include "Player.h"


class Dealer:public Player{
    protected:
        bool faceDwn;
        unsigned char nCards;
        unsigned char nShffle;
        unsigned char nCrdsD;
        Deck *deck;
    public:
        Dealer(unsigned char,unsigned char,unsigned char);
        ~Dealer();
        Deck *getDeck();
        Hand *deal();
        bool getFaceDwn(){return faceDwn;}
        void setFaceDwn(bool);
};

#endif 

Dealer.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include "Dealer.h"

Dealer::Dealer(unsigned char nCards,unsigned char nShffle,unsigned char nCrdsD){
    this->faceDwn=true;
    this->nCards=nCards;
    this->nShffle=nShffle;
    this->nCrdsD=nCrdsD;
    this->name="Dealer";
    this->deck=new Deck(this->nCards,this->nShffle);
}
Dealer::~Dealer(){
    delete deck;
}
Deck *Dealer::getDeck(){
    return deck;
}
Hand *Dealer::deal(){
    hand=new Hand(this->deck,this->nCrdsD);
    return this->hand;
}
void Dealer::setFaceDwn(bool faceDwn){
    this->faceDwn=faceDwn;
}



I think i may have figured a way to keep the pointers instead of using a vector. I thought about overloading the + operator when dealing the next card.
here is what i have so far:


1
2
3
4
5
6
7
8
9
Hand Hand::operator +(Hand &right){
    unsigned char *tempVal= new char[this->crdsNHnd+right.getCrdsNHnd()];
    for(unsigned char i=0;i<this->crdsNHnd;i++){
        tempVal[i]=hand[i];
    }
    tempVal[this->crdsNHnd+right.getCrdsNHnd()-1]=right.getHand(0);
    this->hand=tempVal;
    this->crdsNHnd++;
}


but tbh im not sure if this will work or not.
Wow, either you really like unsigned char, or you're coding
for a very memory constrainted machine. ints are
normally the preferred arithmetic type. unsigned chars are generally
used for characters which include ASCII values greater than 127.

You need to learn about caasting. Casting allows you to change
the type of a variable or expression. We can shorten your program
considerably by using the properties of card number, a little
arithmetic, and casting. In setFace() we can use the modulo operator
to get the face value and then cast it to your enum. Likewise, in
setSuit() all we have to do is divide card number by 4 then cast it
to the Suit enum.
the binary % operator yields the remainder from the division
of the first expression by the second.


I think i may have figured a way to keep the pointers instead
of using a vector.

Why? A vector should always be preferred over pointers.

card.h
L4-5: enum class should be preferred.

L19-20,22: These should be const.

deck.h
L8-11: We don't need these variables at all.

L9: We don't need cards to be dynamically allocated. We can use a
vector. I've renamed this variable to cards.

L15: If you're going to derive another class from Deck, your destructor
should be virtual.

deck.cpp
L8: Do not call srand() multiple times. srand() sets the RNG to a
particular starting point. Calling srand() repeatedly can cause the
RNG to return the same random numbers. srand() should be called ONCE
at the beginning of main().
http://www.cplusplus.com/reference/cstdlib/srand/
Better yet, use the facilities in <random>.

L21-25: If you don't use dynamic memory, the destructor is not needed.

L42-64: Why are you repeating this logic? You already have the logic to
display a card in the Card classs. Use it.

main.cpp
L9-11: use constexpr for constants.

card.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
#ifndef CARD_H
#define CARD_H

enum class Face { A, F2, F3, F4, F5, F6, F7, F8, F9, F10, J, Q, K };
enum class Suit { S, C, H, D };

class Card 
{
    Face face;
    Suit suit;

    void setFace(int cn);
    void setSuit(int cn);

public:
    Card();
    Card(int cn);   //take in counter (cardNum) to set each card

    Face getFace() const;    
    Suit getSuit() const;
    int getValu() const;
    void Display() const;
};

#endif 

card.cpp
[code]
#include <algorithm>
#include <string>
#include <iostream>
#include "Card.h"
using namespace std;

Card::Card()
{}

Card::Card(int cn) 
{
    setFace(cn);
    setSuit(cn);
}

void Card::setFace(int cn) 
{   //  cn is 1 - 52
    face = (Face)(cn % 13);
}

void Card::setSuit(int cn) 
{   //  cn is 1-52
    suit = (Suit)(cn / 4);
}

Face Card::getFace() const
{
    return face;
}

Suit Card::getSuit() const
{
    return suit;
}

//  Return the Blackjack value of the card
int Card::getValu() const 
{
    return min((int)face, 10);
}

void Card::Display() const
{
    const string face_char = "A23456789xJQK";
    const string suit_char = "SCHD";

    if ((int)face == 10)
        cout << "10";
    else
        cout << face_char[(int)face];
    cout << suit_char[(int)suit];
}


deck.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#ifndef DECK_H
#define DECK_H
#include <vector>
#include "Card.h"

constexpr int CARDS_PER_DECK{ 52 };     

class Deck {
protected:
    std::vector<Card>    cards;

public:
    Deck(); 
    virtual ~Deck();
        
    void display();

    Face getFace(int crdNum) const;
    Suit getSuit(int crdNum) const;
    
    Card deal();    
};

#endif  


deck.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
#include <iostream>
#include <ctime>
#include <algorithm>

using namespace std;
#include "Card.h"
#include "Deck.h"

Deck::Deck() {

    for (int i = 0; i < CARDS_PER_DECK; i++) {
        cards.push_back(Card(i));
    }
    random_shuffle(cards.begin(), cards.end());
}

Deck::~Deck() 
{}

Face Deck::getFace(int crdNum) const
{
    return cards[crdNum].getFace();
}

Suit Deck::getSuit(int crdNum) const
{
    return cards[crdNum].getSuit();
}

void Deck::display() {
    for (int i = 0; i < CARDS_PER_DECK; i++) 
        cards[i].Display(); 
}

Card Deck::deal() 
{
    Card    card;
    
    card = cards[0]; 
    cards.erase(cards.begin()); 
    return card;
}


main.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#include <iostream>
#include "Deck.h"
using namespace std;

int main() 
{   
    constexpr int CARDS_TO_DEAL{ 2 };
    
    Deck deck;
    vector<Card> hand;  
    Card temp;

    srand(static_cast<unsigned int>(time(0)));
    
    //  Deal two cards to the hard
    for (int i = 0; i < CARDS_TO_DEAL; i++) 
    {
        temp = deck.deal();
        hand.push_back(temp);
    }

    //Display hand
    for (int i = 0; i < hand.size(); i++) 
    {
        hand[i].Display();        
    }

    //Display
    //deck.display();
   
    return 0;
}

deck.cpp L14. random_shuffle() was depreciated in C++14 and removed in C++17. The replacement is shuffle() http://www.cplusplus.com/reference/algorithm/shuffle/ which requires <random>

main.cpp remove L13

deck.cpp L14

 
shuffle(cards.begin(), cards.end(), default_random_engine(random_device{}());


Another 'take' on the minimum coding of a black-jack game without needing classes:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
#include <iostream>
#include <deque>
#include <vector>
#include <random>
#include <numeric>

int main()
{
   // create & seed a C++ random engine
   std::default_random_engine prng(std::random_device {} ());

   // create an alias to represent a card
   using card = unsigned;

   // create a "standard" deck of 52 cards
   std::deque<card> deck(52);

   // populate the deck to represent all 52 cards
   std::iota(deck.begin(), deck.end(), 0);

   // two lambdas to parse out suit and rank of a card
   auto rank = [ ] (card c) { return "AKQJT98765432"[c % 13]; };
   auto suit = [ ] (card c) { return "SHDC"[c / 13]; };

   // casino black-jack uses more than a single deck
   // multiple decks combined are called a shoe
   std::deque<card> shoe;

   // 3 decks for the shoe
   for (size_t i { }; i < 3; ++i)
   {
      shoe.insert(shoe.begin(), deck.begin(), deck.end());
   }

   // display the original order of cards in the shoe
   std::cout << "Unshuffled shoe:\n";
   for (card ccount { }; const card & c : shoe)
   {
      std::cout << rank(c) << suit(c) << ' ';
      ccount++;

      // if 13 cards have been displayed in a line, start a new line
      if (0 == (ccount % 13)) { std::cout << '\n'; }
   }
   std::cout << '\n';

   // shuffle the shoe, using the random engine created earlier
   std::shuffle(shoe.begin(), shoe.end(), prng);

   // display the shuffled shoe
   std::cout << "Shuffled shoe:\n";
   for (card ccount { }; const card & c : shoe)
   {
      std::cout << rank(c) << suit(c) << ' ';
      ccount++;

      if (0 == (ccount % 13)) { std::cout << '\n'; }
   }
   std::cout << '\n';

   // create 2 players and the dealer
   std::vector<card> p1;
   std::vector<card> p2;
   std::vector<card> d;

   // deal two cards to each player/dealer
   for (size_t itr { }; itr < 2; ++itr)
   {
      p1.push_back(*shoe.begin());
      shoe.pop_front();

      p2.push_back(*shoe.begin());
      shoe.pop_front();

      d.push_back(*shoe.begin());
      shoe.pop_front();
   }

   // display players' and dealer's hands
   // the 'hole' card is displayed with parentheses
   std::cout << "Player 1: ";
   std::cout << '(' << rank(p1[0]) << suit(p1[0]) << ") ";
   std::cout << rank(p1[1]) << suit(p1[1]) << '\n';

   std::cout << "Player 2: ";
   std::cout << '(' << rank(p2[0]) << suit(p2[0]) << ") ";
   std::cout << rank(p2[1]) << suit(p2[1]) << '\n';

   std::cout << "Dealer:   ";
   std::cout << '(' << rank(d[0]) << suit(d[0]) << ") ";
   std::cout << rank(d[1]) << suit(d[1]) << '\n';
   std::cout << '\n';

   // display the shoe with already dealt cards
   std::cout << "Shoe after dealing cards to players:\n";
   for (card ccount { }; const card & c : shoe)
   {
      std::cout << rank(c) << suit(c) << ' ';
      ccount++;

      if (0 == (ccount % 13)) { std::cout << '\n'; }
   }
   std::cout << '\n';
}

Unshuffled shoe:
AS KS QS JS TS 9S 8S 7S 6S 5S 4S 3S 2S
AH KH QH JH TH 9H 8H 7H 6H 5H 4H 3H 2H
AD KD QD JD TD 9D 8D 7D 6D 5D 4D 3D 2D
AC KC QC JC TC 9C 8C 7C 6C 5C 4C 3C 2C
AS KS QS JS TS 9S 8S 7S 6S 5S 4S 3S 2S
AH KH QH JH TH 9H 8H 7H 6H 5H 4H 3H 2H
AD KD QD JD TD 9D 8D 7D 6D 5D 4D 3D 2D
AC KC QC JC TC 9C 8C 7C 6C 5C 4C 3C 2C
AS KS QS JS TS 9S 8S 7S 6S 5S 4S 3S 2S
AH KH QH JH TH 9H 8H 7H 6H 5H 4H 3H 2H
AD KD QD JD TD 9D 8D 7D 6D 5D 4D 3D 2D
AC KC QC JC TC 9C 8C 7C 6C 5C 4C 3C 2C

Shuffled shoe:
9C 5H 8S 4S KD KC 9D 2C 6H 7C KH 5H AD
KS QS 2H 5C 3D 7C TD 3H 2S 3H JC TS QS
4C 4C 5D AS 9H AD JS 8C AH 9C TD TC JD
KS 4S 2H JS 6S QC 8D 8H 2S QD 6D KH 5S
9D JD 3C QC 6H JC AS 3C 2H KS 9S 4H JH
KH AC 2D 2D 3D 6H 9C 4H 8H 2C AD AH 4D
4S JH 5S JC 5S 7C 5C 3S 7S QD 3D KC 7D
9H 8S 6D QH KD 6D 5D 7D 3H 5C AS TD JD
7H TC TS 6C 6C TS 8D 6S QH 7D 9S 8D 9S
2S 3S 8C 8S TH 8C 9D AC TH TH 7H 3S AH
8H TC KD 2D JH QD KC JS 3C AC 4D QH 4D
2C 7H QC 7S 6C 7S 5D 5H 4H 4C 9H QS 6S

Player 1: (9C) 4S
Player 2: (5H) KD
Dealer:   (8S) KC

Shoe after dealing cards to players:
9D 2C 6H 7C KH 5H AD KS QS 2H 5C 3D 7C
TD 3H 2S 3H JC TS QS 4C 4C 5D AS 9H AD
JS 8C AH 9C TD TC JD KS 4S 2H JS 6S QC
8D 8H 2S QD 6D KH 5S 9D JD 3C QC 6H JC
AS 3C 2H KS 9S 4H JH KH AC 2D 2D 3D 6H
9C 4H 8H 2C AD AH 4D 4S JH 5S JC 5S 7C
5C 3S 7S QD 3D KC 7D 9H 8S 6D QH KD 6D
5D 7D 3H 5C AS TD JD 7H TC TS 6C 6C TS
8D 6S QH 7D 9S 8D 9S 2S 3S 8C 8S TH 8C
9D AC TH TH 7H 3S AH 8H TC KD 2D JH QD
KC JS 3C AC 4D QH 4D 2C 7H QC 7S 6C 7S
5D 5H 4H 4C 9H QS 6S

Why a std::deque for holding all the cards to be dealt to players? More efficient removal of elements from front or end of the container.

FYI, "deque" is usually pronounced as "deck." A deque of cards.

Some times throwing stuff into classes increases the complexity of the code unnecessarily.

I would design the game and how it works on paper before I write a single line of code.

Displaying the value of a card is more in line with the mechanics of a deck IMO than individual cards. There are other types of decks than standard poker/black-jack decks. Pinochle decks, for instance.

Or Tarot decks.

Delegating how cards are displayed to a deck class makes changing the game from black-jack to poker to pinochle or some other game, and the type of deck used, easier.

Creating a player class would be a logical step for organizing, using a C++ container like a std::vector to hold all the players. Including the dealer (number of players + 1).

The preceding code was munged-up quite some time ago as a test bed, the thread's topic gave me a chance to reexamine what was written, and offer it up as a possible design idea.
Ooops! I forgot to comment what is done when adding cards to a player's hand.

69
70
71
72
73
74
75
      // begin() returns an iterator to the first element, like a pointer
      // need to retrieve the stored value using operator*
      // and add that value to the player's hand
      p1.push_back(*shoe.begin());
      
      // remove the first element from the shoe
      shoe.pop_front();
Furry Guy wrote:
Displaying the value of a card is more in line with the mechanics of a deck IMO than individual cards. There are other types of decks than standard poker/black-jack decks. Pinochle decks, for instance.

I disagree with you on that. Keep in mind the objectives of object orientation. Suit, Face, and point value are attributes of the individual cards. A deck is simply a collection of cards. One could inherit a Pinochle class from Card. The Deck class would not change.
Last edited on
It isn't a design choice I would make, I see it as counter-intuitive.

Personally I wouldn't over-classify just to be OOP intensive. Keep things to a minimum.

But of course, YMMV.
Last edited on
@Furry Guy's post seems to have been mislaid in the Christmas Post...
@seeplus

Furry Guy renamed himself to George P :+)
Topic archived. No new replies allowed.