Beginning of a blackjack game

This is the beginning of a blackjack game. The very beginning. All it does is create a dealing shoe,fills it, outputs that, shuffles the shoe, outputs that, refills the shoe, shuffles it and outputs that. It looks a whole lot like C and not much like C++. Pointers on making it look C++ would be appreciated. It should compile. None Windows will have to comment out the Sleep() and windows.h. If you do comment out the initializeshoe() right before it.

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
  // Beginning of a Blackjack game
#include <iostream>
#include <cstdlib> 
#include <ctime> 
#include <windows.h>

#define DECKS 6                //number of decks in dealing shoe


void initialize_shoe(int *shoe);   //fill dealing shoe with cards
void shuffle_shoe(int *shoe);      // shuffle the shoe

int main(){

	int shoeindice = 0;
	int *shoe = new int[DECKS * 52];     //create the shoe

	initialize_shoe(shoe);
	for (int deck = 0; deck < DECKS; deck++){           //output the shoe
		for (int i = 0; i < 52; i++)
			std::cout << std::hex << shoe[shoeindice++]; //using hex to see individual cards better
		std::cout << '\n';
	}
	std::cout << "\n\n\n";
	shoeindice = 0;
	shuffle_shoe(shoe);

	for (int deck = 0; deck < DECKS; deck++){           //output the shuffled shoe
		for (int i = 0; i < 52; i++)
			std::cout << std::hex << shoe[shoeindice++];
		std::cout << '\n';
	}
	std::cout << "\n\n\n";

	initialize_shoe(shoe);   //First I commented this out because it runs so fast
	                           // the srand() in the shuffle seeds with the exact same time
							   // so the cards are shuffled in the exact same order.
	Sleep(500);       //Then I added this to fix the prop with srand(time())

	shuffle_shoe(shoe);
	shoeindice = 0;

	for (int deck = 0; deck < DECKS; deck++){        // see what the shoe looks like the second time
		for (int i = 0; i < 52; i++)
			std::cout << std::hex << shoe[shoeindice++];
		std::cout << '\n';
	}
	
	delete shoe;

	return 0;

}
void initialize_shoe(int *shoe){  //fill shoe with values 1(Ace) -13(king). Card suits don't matter in Blackjack
	int shoeindice = 0;

	for (int deck = 0; deck < DECKS; deck++)
		for (int rank = 1; rank < 14; rank++)
			for (int suit = 0; suit < 4; suit++)
				*(shoe + shoeindice++) = rank;


}

void shuffle_shoe(int *shoe){   //first attempt at a simple shuffle

	int temp, card1, card2;
	int size = 52 * DECKS;

	srand((unsigned)time(0)); // the problem in main. This returns the time in seconds since 1970.
							  //If main reinitialized the shoe and called it back, its was so fast
							  //time was returning the same value as the difference in time was
							  //microseconds.
	for (int i = 0; i < 400; i++){
		card1 = (rand() % size);
		card2 = (rand() % size);
		temp = *(shoe + card1);
		*(shoe + card1) = *(shoe + card2);
		*(shoe + card2) = temp;
	}
}
Last edited on
Pointers on making it look C++ would be appreciated.


You have one very obvious class to start with - Shoe.
Most blackjack implementations also implement Deck as a class, although with a shoe that may not be so important.
Another common class is Card to encapsulate suit and face value.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Shoe
{  int * m_cards;
    int m_numdecks;
public:
    Shoe (int numdecks)
    { m_numdecks = numdecks;
       m_cards = new int[numdecks * 52];
    }
    virtual ~Shoe ()
    { delete [] m_cards;
    }
    void initialize ();
    void shuffle ();
    void display ();
};


line 70: srand() should only ever be called once in your program usually at beginning of main. Calling srand() multiple times in the same second will reset the RNG to return the same sequence of numbers.

Line 38: No reason for Sleep(). See above note regarding srand().

One note: You're storing rank (1-14) into your cards. Keep in mind that all face cards have a value of 10 in blackjack.




Last edited on
Thanks. Here is the revised beginning. I looks more c++. I'm just wondering if I should work the Jack, queen, king, ace and suits in there now if for nothing else, variety. I guess make Card a class with the name, rank and suit and make the shoe m_cards a pointer to an array off Cards.

Here's the revision:

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
// Blackjack02
#include <iostream>
#include <cstdlib> 
#include <ctime> 

#define DECKS 6                //number of decks in dealing shoe

class Shoe
{
	int * m_cards;
	int m_numdecks;
public:
	Shoe(int numdecks)
	{
		m_numdecks = numdecks;
		m_cards = new int[numdecks * 52];
	}
	virtual ~Shoe()
	{
		delete[] m_cards;
	}
	void initialize();
	void shuffle();
	void display();
};


void Shoe::initialize(){
	int shoeindice = 0;

	for (int deck = 0; deck < m_numdecks; deck++)
		for (int rank = 1; rank < 14; rank++)
			for (int suit = 0; suit < 4; suit++)
				*(m_cards + shoeindice++) = rank < 10 ? rank : 10;


}

void Shoe::shuffle(){
	int temp, card1, card2;
	int size = 52 * m_numdecks;
	
	for (int i = 0; i < 400; i++){
		card1 = (rand() % size);
		card2 = (rand() % size);
		temp = *(m_cards + card1);
		*(m_cards + card1) = *(m_cards + card2);
		*(m_cards + card2) = temp;
	}

}
void Shoe::display(){

	int shoeindice = 0;

	for (int deck = 0; deck < m_numdecks; deck++){           
		for (int i = 0; i < 52; i++)
			std::cout << std::hex << m_cards[shoeindice++];
		std::cout << '\n';
	}
	std::cout << '\n';
}
int main(){

	
	Shoe myshoe(DECKS);

	srand((unsigned)time(0));
	myshoe.initialize();
	myshoe.display();
	myshoe.shuffle();
	myshoe.display();
	myshoe.initialize();
	myshoe.shuffle();
	myshoe.display();

	

	return 0;

}
Last edited on
I guess make Card a class with the name, rank and suit and make the shoe m_cards a pointer to an array off Cards.

That's a good next step.

You might consider the standard library shuffle instead of writing your own:
http://www.cplusplus.com/reference/algorithm/random_shuffle/


I thought about using random_shuffle, but I'm not that clear on the parameters it takes and whether arrays have to be created with the <array> header.

This is where I'm at:

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
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
// Blackjack03
#include <iostream>
#include <cstdlib> 
#include <ctime> 

#define DECKS 6                //number of decks in dealing shoe

class Card
{
	
	int m_rank;
	char m_name;
	char m_suit;
	
public:
	void setcard(int rank, char suit);
	void showcard();

};
void Card::setcard(int rank, char suit){
	char names[]{ 'A', '2', '3', '4', '5', '6', '7', '8', '9', 'T', 'J', 'Q', 'K'};
	m_suit = suit;
	m_rank = rank;
	m_name = names[rank-1];

}
void Card::showcard(){
	
		std::cout << m_name << m_suit;
}
class Shoe
{
	Card * m_cards;
	int m_numdecks;
	int cardsdelt = 0;
public:
	Shoe(int numdecks)
	{
		m_numdecks = numdecks;
		m_cards = new Card[numdecks * 52];
	}
	virtual ~Shoe()
	{
		delete[] m_cards;
	}
	void initialize();
	void shuffle();
	void display();
	void deal(int numplayers);
};


void Shoe::initialize(){
	int shoeindice = 0;
	char suit[]{'H', 'D', 'C', 'S'};

	for (int deck = 0; deck < m_numdecks; deck++)
		for (int rank = 1; rank < 14; rank++)
			for (int s = 0; s< 4; s++)
				m_cards[shoeindice++].setcard(rank, suit[s]);
			


}

void Shoe::shuffle(){
	Card temp;
	int card1, card2;
	int size = 52 * m_numdecks;

	for (int i = 0; i < 400; i++){
		card1 = (rand() % size);
		card2 = (rand() % size);
		temp = m_cards[card1];
		m_cards[card1] = m_cards[card2];
		m_cards[card2] = temp;
	}

}
void Shoe::display(){

	int shoeindice = 0;

	for (int deck = 0; deck < m_numdecks; deck++){           
		for (int i = 0; i < 26; i++){
			m_cards[shoeindice++].showcard();
			std::cout << " "; 
		}
		std::cout << '\n';

		for (int i = 0; i < 26; i++){
			m_cards[shoeindice++].showcard();
			std::cout << " ";
		}
		std::cout << '\n';
	}
	std::cout << '\n';
}

void Shoe::deal(int numplayers){

	/*  This will probably take a Player class array
	not an int.
	*/
}
int main(){
	Shoe myshoe(DECKS);
	
	srand((unsigned)time(0));
	myshoe.initialize();
	myshoe.display();
	myshoe.shuffle();
	myshoe.display();
	myshoe.initialize();
	myshoe.shuffle(); 
	myshoe.display();
	
	return 0;

}
I thought about using random_shuffle, but I'm not that clear on the parameters it takes and whether arrays have to be created with the <array> header.


You do not need to use std::array in order to use random_shuffle, although doing so makes things simpler, since std::array provides begin() and end() iterators automatically.

random_shuffle is a template. All you need to provide are iterators to the first element and to the element past the last.

template <class RandomAccessIterator>
void random_shuffle (RandomAccessIterator first, RandomAccessIterator last);


1
2
3
4
5
6
7
8
class Shoe
{
public:
  Card * begin ()
  {  return m_cards; }
  Card * end ()
  {  return m_cards[m_numcards]; }
...


1
2
3
void Shoe::shuffle ()
{  random_shuffle (begin(), end());
}
Last edited on
That's straight forward enough. Thank you.

Another question, if you don't mind. I'm going to form a player class. Along with things like position at table, money, cards in hand, ISDEALER, ISHUMAN, I would like to have parameters that are pointers to the functions that control their playing/hit and their betting strategy.

I want to simulate real players entering and leaving the game based on success, and real players are going to play differently and stupidly( split 2's etc.). Am I going to have to stick all those betting and playing strategies in the player class or is it possible to have a member thats a pointer to a function outside the class? I want to have about 10 or so playing strategies and betting strategies and assign them randomly to simulated players entering the game.
You might consider derived classes for your different types of players.

Your base class (Player) provides the interface to the various derived classes.

Here's a simple example:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class Player
{
public:
  Player ();
  virtual void Bet () = 0;  // Pure virtual. Actual implementation is in derived classes.
};

class Stupid : public Player
{
  Stupid () {};
  void Bet ()
  {  if (hand.get_score() == 20)
        hit (); 
   }
};

int main ()
{  Player * player[MAX_PLAYERS];
    player[0] = new Stupid;
    player[1] = new Conservative;
    // etc
}






Thanks again, I 'm going to work on it.
I wrote the decision making functions for the dealer who must stand on a soft 17 and a player using basic strategy. And it looks just like C. I can't imagine the overhead to work this into some type of class.

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
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
//Strategy.cpp

#include "Strategy.h"

/*
          // Playing strategies #defined in header

#define DEALER 0
#define GOOD 1
#define BAD 2

      // Decision returns
#define HIT 1
#define STAND 0
#define BLACKJACK 2
#define BUST 3
#define SPLIT 4
#define DOUBLE 5     */

int dealer(int *cards, int numofcards);
int basic4to8decks(int *cards, int numofcards, int dealercard);

// parsing fuction prototyped in header
int decision(int *cards, int numofcards, int playlevel, int dealercard){

	switch (playlevel){
		case DEALER:
			return dealer(cards, numofcards);
		case GOOD:
			return basic4to8decks(cards, numofcards, dealercard);
	}
}

int dealer(int *cards, int numofcards)
{
	int score = 0;
	if (numofcards == 2){ // Just dealt
		if (cards[0] == 1 || cards[1] == 1){  //Dealer has an ace
			if (cards[0] >= 10 || cards[1] >= 10)
				return BLACKJACK;
			else if (cards[0] >= 6 || cards[1] >= 6) //Dealer has 17 or better and must stand
				return STAND;
			else return HIT;
		}
		if (cards[0] + cards[1] >= 17)
			return STAND;
		else return HIT;

	}
	for (int i = 0; i < numofcards; i++){
		score += cards[i]>9 ? 10 : cards[i];
		if (cards[i] == 1)
			score += 10;
	}
	if (score < 17)
		return HIT;
	else if (score <= 21)
		return STAND;
	for (int i = 0; i < numofcards; i++){
		if (cards[i] == 1){
			score -= 10;
			if (score <= 21 && score >= 17)
				return STAND;
			else if (score < 17)
				return HIT;
		}
	}
	return BUST;
}

int basic4to8decks(int *cards, int numofcards,int dealercard){

	int score = 0;
	if (dealercard == 1) dealercard += 10;

	if (numofcards == 2){           //New Hand
		if (cards[0] == cards[1]){ // Handle pairs
			switch(cards[0]){
			case 1:
			case 8: return SPLIT;
			case 10:return STAND;
			case 5: if (dealercard >= 10)
						return HIT;
					else return DOUBLE;
			case 2:
			case 3:
				if (dealercard <= 7)
					return SPLIT;
				else return HIT;
			case 9:
				if (dealercard >= 10 || dealercard ==7)
					return STAND;
				else return SPLIT;
			case 7:
				if (dealercard <= 7) return SPLIT;
				else return HIT;
			case 6:
				if (dealercard <= 6) return SPLIT;
				else return HIT;
			case 4:
				if (dealercard == 5 || dealercard == 6)
					return SPLIT;
				else return HIT;
			}

		} // end of pairs
		//no pair still here
		if (cards[0] == 1 || cards[1] ==1 ){         //check for ace
			switch (cards[0] == 1 ? cards[1] : cards[0]){ //switch non ace
				case 10:
				case 9:
				case 8:
					return STAND;
				case 7:
					if (dealercard >= 3 && dealercard <= 6)
						return DOUBLE;
					else if (dealercard >= 9)
						return HIT;
					else return STAND;
				case 6:
					if (dealercard >= 3 && dealercard <= 6)
						return DOUBLE;
					else return HIT;
				case 5:
				case 4:
					if (dealercard >= 4 && dealercard <= 6)
						return DOUBLE;
					else return HIT;
				case 3:
				case 2:
					if (dealercard == 5 || dealercard== 6)
						return DOUBLE;
					else return HIT;

			}
		}    //End of ace combo's
			//no aces , still here
	}
	 // fall through no aces or pairs or more than two cards. Count em up
	for (int i = 0; i < numofcards; i++){
		score += cards[i];
		if (cards[i] == 1)
			score += 10;
	}
	if (score > 21){
		for (int i = 0; i < numofcards; i++){
			if (cards[i] == 1)
				score -= 10;
			if (score < 21)
				break;
		}
		if (score > 21) //couldn't bring it below 21
			return BUST;
	}
	switch (score){
		case 5:
		case 6:
		case 7:
		case 8:
			return HIT;
		case 9:
			if (dealercard >= 7)
				return HIT;
			else return DOUBLE;
		case 10:
			if (dealercard < 10)
				return DOUBLE;
			else return HIT;
		case 11:
			return DOUBLE;
		case 12:
			if (dealercard >= 4 && dealercard <= 6)
				return STAND;
			else return HIT;
		case 13:
		case 14:
		case 15:
		case 16:
			if (dealercard > 6)
				return HIT;
			else return STAND;
		default:
			return STAND;


	}

}
The above compiles but it still has mistakes as I'm still not sure if the int array passed is going to trim the face card values to 10.
It appears you've gotten rid of your Card class. You actually had a good start on it (5th post).
The one suggestion I had regarding you Card class was to provide a value() function. This would simplify having to check whether the rank is > 10.

Since you didn't post your strategy.h header or main(), I can't compile and try the above code.

Lines 8-18: Consider using enums instead of defines.

You also might want to consider a Hand class. A Hand holds some numbers of Cards. std::vector is a suitable way of holding a variable number of cards in a Hand.
I did, and whipped out a very C like program that was very hard to follow ( sort of like the code above). While looking for some samples of Blackjack games written in C++, I stumbled on a PDF file called Beginning C++ throgh game programming. It is excellent instruction and rationally explains the advantages of using vectors and the other containers. So I'm going through that PDF which ends with a blackjack game.

When I get there, I'm going to try to adapt the game so it can seat computer players that play at different skill levels. But that what I've been doing the last few days, going through that PDF.
"You also might want to consider a Hand class. A Hand holds some numbers of Cards. std::vector is a suitable way of holding a variable number of cards in a Hand."


The PDF I'm studying explains iterators and the Standard Template Library I haven't gotten to the class sections yet with derived classes and polymorphism, but if its explained as well as the stuff in the first 5 chapters, I think I'll finally have a handle on this.

I'm definitely going to go back to the classes and I'm going to break that strategy code into more functions to make it more readable and so parts aren't redundant.
Last edited on
Lines 8-18: Consider using enums instead of defines.


That's a good idea as they are not going to change as DECKS might.

Since you didn't post your strategy.h header or main(), I can't compile and try the above code.


Oh it was all full of errors. But the biggest problem was I could not get the program to compile as separate files. I had to put everything into one file to compile it. I have to create a simple multi file program to see where the problem is. But the strategy was full of errors ( not just syntax, but logic errors). I had to hard code card values to trace them through the decision switches. It started feeling very much like spaghetti code. That's when I decided I'm going to break things down into more functions. Easier to debug and easier to read.

Thanks for the help so far. It'll probably be a week or so , but I'm going to post what I hope is a better version of this - maybe move it to the regular c++ forum. I want to have different betting systems for the computer players too( Martingale , Oscar etc.).

Thanks again.
Topic archived. No new replies allowed.