Home | Notes | Projects > Console Blackjack
An interactive console Blackjack game implemented using Objecct-Oriented Design (OOD) and programming (OOP) in C++
To experience Object-Oriented Design process in a software development process.
Generate
UML class diagram
UML sequence diagram
To get familiar with Object-Oriented Programming concepts.
4 pillars of OOP - Encapsulation, Inheritance, Polymorphism, Abstraction
[!] Note: Demonstration video is to be uploaded.
In the meantime, following snapshots will give you an idea how it looks!
Operating System
Ubuntu 22.04.1 LTS (Kernel version: 5.15.0-52-generic)
Compiler
GCC version 11.3.0 (Ubuntu 11.3.0-1ubuntu1~22.04)
Debugger
GDB version 12.0.90 (Ubuntu 12.0.90-0ubuntu1)
[!] Note: This application compiles and runs on both Linux and Windows operating systems.
Sequence Diagram run()
Sequence Diagram init()
Sequence Diagram play()
Sequence Diagram reset()
main_Blackjack.cpp (Test Driver)
xxxxxxxxxx
181//========================================================================================
2// File Name : main_Backjack.cpp
3// Description : OOP C++ BlackJack Program - Driver
4// Author : Kyungjae Lee
5// History : 11/08/2022 - File created.
6//========================================================================================
7
8
9
10
11int main(int argc, char *argv[])
12{
13 BlackJack blackjack;
14
15 blackjack.run();
16
17 return 0;
18}
Blackjack.hpp
xxxxxxxxxx
1741//========================================================================================
2// File Name : BlackJack.hpp
3// Description : OOP C++ BlackJack Program - BlackJack class implementation
4// Author : Kyungjae Lee
5// History : 11/03/2022 - File created.
6//========================================================================================
7
8
9
10
11
12
13
14
15
16
17
18class BlackJack
19{
20public:
21 BlackJack();
22 ~BlackJack();
23 void init();
24 void play();
25 void reset();
26 void run();
27 void printResult(const int) const;
28
29private:
30 Dealer dealer;
31 Player player;
32};
33
34// default constructor
35BlackJack::BlackJack()
36{
37 // empty
38}
39
40// destructor
41BlackJack::~BlackJack()
42{
43 // empty
44}
45
46// initializes the Blackjack game
47void BlackJack::init()
48{
49 // screen clear for Windows OS
50
51 std::system("cls");
52
53 std::system("clear");
54
55
56 dealer.printMsg("OK, let's begin!");
57
58 // dealer deals initial hand
59 for (int i = 0; i < 2; ++i)
60 {
61 dealer.addCard(dealer.deal());
62 player.addCard(dealer.deal());
63 }
64
65 // print the dealer's hand (top card only) and palyer's hand
66 std::cout << "Dealer's top card: "; dealer.printTopCard(); std::cout << std::endl;
67 std::cout << "Your initial hand: "; player.printHand(); std::cout << std::endl;
68}
69
70// plays the Blackjack game
71void BlackJack::play()
72{
73 // ask the player to choose between hit or stay
74 dealer.printQuestion("Q. Hit or stay?");
75 dealer.takeInput(player, "hit", "stay");
76
77 while (player.getAnswer() == "hit")
78 {
79 // dealer deals another card to the player
80 player.addCard(dealer.deal());
81
82 // print the dealer's hand (top card only) and palyer's hand
83 std::cout << "Dealer's top card: "; dealer.printTopCard(); std::cout << std::endl;
84 std::cout << "Your current hand: "; player.printHand(); std::cout << std::endl;
85
86 // if the player goes bust
87 if (player.isBust())
88 {
89 player.setResult(LOOSE); // set the player's game result as LOOSE
90 break;
91 }
92
93 // ask the user to choose between hit or stay
94 dealer.printQuestion("Q. Hit or stay?");
95 dealer.takeInput(player, "hit", "stay");
96 }
97
98 // if the player stays
99 if (player.getResult() != LOOSE)
100 {
101 std::cout << "Dealer's current hand: "; dealer.printHand(); std::cout << std::endl;
102
103 // if dealer's hand value totals to less than 17
104 if (dealer.getHandValue() < 17)
105 {
106 std::cout << "Dealer's hand totals to less than 17. "
107 << "Dealing him/herself another card." << std::endl;
108
109 dealer.addCard(dealer.deal()); // deal him/herself another card
110
111 // print the dealer's updated hand
112 std::cout << "Dealer's updated hand: "; dealer.printHand(); std::cout << std::endl;
113 }
114
115 // if the dealer goes bust
116 if (dealer.isBust())
117 player.setResult(WIN); // set the player's game result to WIN
118 // if both dealer and player is alive, compare hands and set player's game result
119 // accordingly
120 else
121 player.setResult(dealer.compareHands(player));
122 }
123
124 // print the game result
125 std::cout << std::endl; printResult(player.getResult()); std::cout << std::endl;
126}
127
128// resets the card deck and player's game result for (potentially) the next game
129void BlackJack::reset()
130{
131 dealer.resetDeck(player);
132 player.setResult(DEFAULT_RESULT); // DEFAULT_RESULT is any value that is not -1, 0, 1
133}
134
135// runs the Blackjack game
136void BlackJack::run()
137{
138 // print the welcome message
139 dealer.printMsg("***** Welcome to KJ's Console Casino! *****");
140 dealer.printQuestion("Q. Would you like to play a game of Blackjack?");
141 dealer.takeInput(player, "yes", "no");
142
143 while (player.getAnswer() == "yes")
144 {
145 init();
146 play();
147 reset();
148
149 // ask the player if he/she wants to play the game again and read in the input
150 dealer.printQuestion("Q. Would you like to play another round?");
151 dealer.takeInput(player, "yes", "no");
152 }
153
154 // print the goodbye message
155 dealer.printMsg("***** Thanks for Playing! Good Bye~ *****");
156}
157
158// prints the game result
159void BlackJack::printResult(const int result) const
160{
161 int value;
162 std::cout << "Game has ended!" << std::endl;
163 std::cout << "Dealer's hand: "; dealer.printHand(); std::cout << std::endl;
164 std::cout << "Your hand : "; player.printHand(); std::cout << std::endl;
165
166 if (result == WIN)
167 std::cout << ">>> You win!" << std::endl;
168 else if (result == TIE)
169 std::cout << ">>> It's a tie!" << std::endl;
170 else
171 std::cout << ">>> You lost!" << std::endl;
172}
173
174
Participants.hpp
xxxxxxxxxx
1741//========================================================================================
2// File Name : BlackJack.hpp
3// Description : OOP C++ BlackJack Program - BlackJack class implementation
4// Author : Kyungjae Lee
5// History : 11/03/2022 - File created.
6//========================================================================================
7
8
9
10
11
12
13
14
15
16
17
18class BlackJack
19{
20public:
21 BlackJack();
22 ~BlackJack();
23 void init();
24 void play();
25 void reset();
26 void run();
27 void printResult(const int) const;
28
29private:
30 Dealer dealer;
31 Player player;
32};
33
34// default constructor
35BlackJack::BlackJack()
36{
37 // empty
38}
39
40// destructor
41BlackJack::~BlackJack()
42{
43 // empty
44}
45
46// initializes the Blackjack game
47void BlackJack::init()
48{
49 // screen clear for Windows OS
50
51 std::system("cls");
52
53 std::system("clear");
54
55
56 dealer.printMsg("OK, let's begin!");
57
58 // dealer deals initial hand
59 for (int i = 0; i < 2; ++i)
60 {
61 dealer.addCard(dealer.deal());
62 player.addCard(dealer.deal());
63 }
64
65 // print the dealer's hand (top card only) and palyer's hand
66 std::cout << "Dealer's top card: "; dealer.printTopCard(); std::cout << std::endl;
67 std::cout << "Your initial hand: "; player.printHand(); std::cout << std::endl;
68}
69
70// plays the Blackjack game
71void BlackJack::play()
72{
73 // ask the player to choose between hit or stay
74 dealer.printQuestion("Q. Hit or stay?");
75 dealer.takeInput(player, "hit", "stay");
76
77 while (player.getAnswer() == "hit")
78 {
79 // dealer deals another card to the player
80 player.addCard(dealer.deal());
81
82 // print the dealer's hand (top card only) and palyer's hand
83 std::cout << "Dealer's top card: "; dealer.printTopCard(); std::cout << std::endl;
84 std::cout << "Your current hand: "; player.printHand(); std::cout << std::endl;
85
86 // if the player goes bust
87 if (player.isBust())
88 {
89 player.setResult(LOOSE); // set the player's game result as LOOSE
90 break;
91 }
92
93 // ask the user to choose between hit or stay
94 dealer.printQuestion("Q. Hit or stay?");
95 dealer.takeInput(player, "hit", "stay");
96 }
97
98 // if the player stays
99 if (player.getResult() != LOOSE)
100 {
101 std::cout << "Dealer's current hand: "; dealer.printHand(); std::cout << std::endl;
102
103 // if dealer's hand value totals to less than 17
104 if (dealer.getHandValue() < 17)
105 {
106 std::cout << "Dealer's hand totals to less than 17. "
107 << "Dealing him/herself another card." << std::endl;
108
109 dealer.addCard(dealer.deal()); // deal him/herself another card
110
111 // print the dealer's updated hand
112 std::cout << "Dealer's updated hand: "; dealer.printHand(); std::cout << std::endl;
113 }
114
115 // if the dealer goes bust
116 if (dealer.isBust())
117 player.setResult(WIN); // set the player's game result to WIN
118 // if both dealer and player is alive, compare hands and set player's game result
119 // accordingly
120 else
121 player.setResult(dealer.compareHands(player));
122 }
123
124 // print the game result
125 std::cout << std::endl; printResult(player.getResult()); std::cout << std::endl;
126}
127
128// resets the card deck and player's game result for (potentially) the next game
129void BlackJack::reset()
130{
131 dealer.resetDeck(player);
132 player.setResult(DEFAULT_RESULT); // DEFAULT_RESULT is any value that is not -1, 0, 1
133}
134
135// runs the Blackjack game
136void BlackJack::run()
137{
138 // print the welcome message
139 dealer.printMsg("***** Welcome to KJ's Console Casino! *****");
140 dealer.printQuestion("Q. Would you like to play a game of Blackjack?");
141 dealer.takeInput(player, "yes", "no");
142
143 while (player.getAnswer() == "yes")
144 {
145 init();
146 play();
147 reset();
148
149 // ask the player if he/she wants to play the game again and read in the input
150 dealer.printQuestion("Q. Would you like to play another round?");
151 dealer.takeInput(player, "yes", "no");
152 }
153
154 // print the goodbye message
155 dealer.printMsg("***** Thanks for Playing! Good Bye~ *****");
156}
157
158// prints the game result
159void BlackJack::printResult(const int result) const
160{
161 int value;
162 std::cout << "Game has ended!" << std::endl;
163 std::cout << "Dealer's hand: "; dealer.printHand(); std::cout << std::endl;
164 std::cout << "Your hand : "; player.printHand(); std::cout << std::endl;
165
166 if (result == WIN)
167 std::cout << ">>> You win!" << std::endl;
168 else if (result == TIE)
169 std::cout << ">>> It's a tie!" << std::endl;
170 else
171 std::cout << ">>> You lost!" << std::endl;
172}
173
174
Dealer.hpp
xxxxxxxxxx
1331//========================================================================================
2// File Name : Dealer.hpp
3// Description : OOP C++ BlackJack Program - Dealer class implementation
4// - Dealer class is a derived class of Participant class
5// Author : Kyungjae Lee
6// History : 11/03/2022 - File created.
7// 11/08/2022 - Text processor functionality separated to independent
8// module.
9//========================================================================================
10
11
12
13
14
15
16
17
18
19class Dealer : public Participant
20{
21public:
22 Dealer();
23 ~Dealer();
24 Card* deal();
25 void printTopCard() const;
26 int compareHands(Player&) const;
27 void resetDeck(Player&);
28 void printMsg(const std::string&) const;
29 void printQuestion(const std::string&) const;
30 void printClarificationMsg(const std::string&, const std::string&) const;
31 void takeInput(Player&, const std::string&, const std::string&);
32
33private:
34 CardDeck deck;
35 TextProcessor textProc; // processes player's natural language text input
36};
37
38// default constructor
39Dealer::Dealer()
40 : deck()
41{
42 // empty
43}
44
45// destructor
46Dealer::~Dealer()
47{
48 // empty
49}
50
51// deals (returns) the top card of the card deck
52// - receiver of the dealt card should process the card from its end
53Card* Dealer::deal()
54{
55 Card *pcard = deck.topCard();
56 deck.popTopCard();
57
58 return pcard;
59}
60
61// prints the top card to the screen
62void Dealer::printTopCard() const
63{
64 hand.front()->print(); std::cout << ".";
65}
66
67// compares the dealer's hand with the player's hand and returns the result
68int Dealer::compareHands(Player& player) const
69{
70 if (player.getHandValue() > getHandValue())
71 return 1;
72 else if (player.getHandValue() == getHandValue())
73 return 0;
74 else
75 return -1;
76}
77
78// resets the card deck
79void Dealer::resetDeck(Player& player)
80{
81 for (Card* pcard : player.hand)
82 deck.addBottom(pcard);
83
84 for (Card* pcard : hand)
85 deck.addBottom(pcard);
86
87 player.hand.clear();
88 hand.clear();
89
90 deck.shuffle();
91}
92
93// prints the passed message to the screen (non-question type)
94void Dealer::printMsg(const std::string& message) const
95{
96 std::cout << message << std::endl;
97}
98
99// prints the passed question to the screen (question type)
100void Dealer::printQuestion(const std::string& question) const
101{
102 std::cout << question << std::endl << "> ";
103}
104
105// prints the clarification message to the screen
106// - this should be called when the processed answer of the player does not match any
107// keywords registered in the textMap
108void Dealer::printClarificationMsg(const std::string& expected1,
109 const std::string& expected2) const
110{
111 std::cout << "Q. I'm sorry, was that a " << expected1 << " or " << expected2 << "?"
112 << std::endl << "> ";
113}
114
115// takes the player's input and processes it
116void Dealer::takeInput(Player& player, const std::string& expected1,
117 const std::string& expected2)
118{
119 std::string input;
120 std::getline(std::cin, input);
121
122 // asks for player's input repeatedly until the input is recognized by processText()
123 while ((input = textProc.processText(input, expected1, expected2)) == "TEXT NOT RECOGNIZABLE")
124 {
125 printClarificationMsg(expected1, expected2);
126 std::getline(std::cin, input);
127 }
128
129 // sets the player's member variable 'answer' to the recognized and processed input
130 player.setAnswer(input);
131}
132
133
Player.hpp
xxxxxxxxxx
711//========================================================================================
2// File Name : Player.hpp
3// Description : OOP C++ BlackJack Program - Player class implementation
4// - Player class is a derived class of Participant class
5// Author : Kyungjae Lee
6// History : 11/03/2022 - File created.
7//========================================================================================
8
9
10
11
12
13
14
15// can be any value that is not -1(loose), 0(tie), or win(1)
16
17class Player : public Participant
18{
19public:
20 Player();
21 ~Player();
22 void setAnswer(std::string);
23 const std::string getAnswer() const;
24 void setResult(int);
25 const int getResult() const;
26
27private:
28 std::string answer; // stores the player's answer to the dealer's question
29 int result; // stores the player's game result (win, tie, loose)
30
31 friend class Dealer; // enables dealer's access to player's hand when resetting
32};
33
34// default constructor
35Player::Player()
36 : result(DEFAULT_RESULT)
37{
38 // empty
39}
40
41// destructor
42Player::~Player()
43{
44 // empty
45}
46
47// sets the player's answer to the passed string
48void Player::setAnswer(std::string answer)
49{
50 this->answer = answer;
51}
52
53// gets the player's answer
54const std::string Player::getAnswer() const
55{
56 return answer;
57}
58
59// sets the player's game result to the passed integer value
60void Player::setResult(int result)
61{
62 this->result = result;
63}
64
65// gets the player's game result
66const int Player::getResult() const
67{
68 return result;
69}
70
71
Card.hpp
xxxxxxxxxx
991//========================================================================================
2// File Name : Card.hpp
3// Description : OOP C++ BlackJack Program - Card class implementation
4// Author : Kyungjae Lee
5// History : 11/03/2022 - File created.
6//========================================================================================
7
8
9
10
11class Card
12{
13public:
14 enum Suits {
15 HEARTS, DIAMONDS, CLUBS, SPADES
16 };
17 enum Ranks {
18 TWO = 2, THREE, FOUR, FIVE, SIX, SEVEN, EIGHT, NINE, TEN, JACK, QUEEN, KING, ACE
19 };
20 Card(Ranks, Suits);
21 ~Card();
22 Ranks getRank() const;
23 Suits getSuit() const;
24 int getValue() const;
25 void print() const;
26
27private:
28 Ranks rank;
29 Suits suit;
30 int value;
31};
32
33// parameterized constructor
34Card::Card(Ranks r, Suits s)
35 : rank(r), suit(s)
36{
37 // empty
38}
39
40// destructor
41Card::~Card()
42{
43 // empty
44}
45
46// gets the rank of the card
47Card::Ranks Card::getRank() const
48{
49 return rank;
50}
51
52// gets the suit of the card
53Card::Suits Card::getSuit() const
54{
55 return suit;
56}
57
58// gets the value of the card
59int Card::getValue() const
60{
61 if (rank <= TEN)
62 return rank;
63 else if (rank == JACK)
64 return 10;
65 else if (rank == QUEEN)
66 return 10;
67 else if (rank == KING)
68 return 10;
69 else
70 return 11; // ACE will be evaluted to 1 if necessary by the participants
71}
72
73// prints the card to the screen
74void Card::print() const
75{
76 if (rank <= TEN)
77 std::cout << rank;
78 else if (rank == JACK)
79 std::cout << "Jack";
80 else if (rank == QUEEN)
81 std::cout << "Queen";
82 else if (rank == KING)
83 std::cout << "King";
84 else
85 std::cout << "Ace";
86
87 std:: cout << "-of-";
88
89 if (suit == HEARTS)
90 std::cout << "Hearts";
91 else if (suit == DIAMONDS)
92 std::cout << "Diamonds";
93 else if (suit == CLUBS)
94 std::cout << "Clubs";
95 else
96 std::cout << "Spades";
97}
98
99
CardDeck.hpp
xxxxxxxxxx
781//========================================================================================
2// File Name : CardDeck.hpp
3// Description : OOP C++ BlackJack Program - CardDeck class implementation
4// Author : Kyungjae Lee
5// History : 11/03/2022 - File created.
6//========================================================================================
7
8
9
10
11
12// shuffle
13// default_randome_engine
14// time
15
16
17
18class CardDeck
19{
20public:
21 CardDeck();
22 ~CardDeck();
23 void shuffle();
24 Card* topCard();
25 void popTopCard();
26 void addBottom(Card*);
27
28private:
29 std::deque<Card*> deck;
30};
31
32// default constructor
33CardDeck::CardDeck()
34 : deck()
35{
36 for (int r = 2; r <= 14; ++r)
37 {
38 for (int s = 0; s <= 3; ++s)
39 deck.push_back(new Card(static_cast<Card::Ranks>(r), static_cast<Card::Suits>(s)));
40 }
41
42 shuffle();
43}
44
45// destructor
46CardDeck::~CardDeck()
47{
48 for (Card* pcard : deck)
49 delete pcard;
50
51 deck.clear();
52}
53
54// shuffles the card deck
55void CardDeck::shuffle()
56{
57 std::shuffle(deck.begin(), deck.end(), std::default_random_engine(time(NULL)));
58}
59
60// returns the top card in the deck
61Card* CardDeck::topCard()
62{
63 return deck.front();
64}
65
66// removes the top card from the card deck
67void CardDeck::popTopCard()
68{
69 deck.pop_front();
70}
71
72// add the passed card to the bottom of the card deck
73void CardDeck::addBottom(Card* pcard)
74{
75 return deck.push_back(pcard);
76}
77
78
TextProcessor.hpp
xxxxxxxxxx
1021//========================================================================================
2// File Name : TextProcessor.hpp
3// Description : OOP C++ BlackJack Program - TextProcessor class implementation
4// - TextProcessor processes player's natural language input text
5// Author : Kyungjae Lee
6// History : 11/08/2022 - File created.
7//========================================================================================
8
9
10
11
12
13
14
15class TextProcessor
16{
17public:
18 TextProcessor();
19 ~TextProcessor();
20 void buildTextMap();
21 std::string& processText(std::string&, const std::string&, const std::string&);
22
23private:
24 std::unordered_map<std::string, std::string> textMap;
25};
26
27// default constructor
28TextProcessor::TextProcessor()
29 : textMap()
30{
31 buildTextMap();
32}
33
34// destructor
35TextProcessor::~TextProcessor()
36{
37 // empty
38}
39
40// builds the textMap
41// - this textMap will be used for natural language processing
42void TextProcessor::buildTextMap()
43{
44 textMap["yes"] = "yes";
45 textMap["y"] = "yes";
46 textMap["sure"] = "yes";
47 textMap["yeah"] = "yes";
48 textMap["yeap"] = "yes";
49 textMap["yup"] = "yes";
50 textMap["please"] = "yes";
51 textMap["of course"] = "yes";
52 textMap["nope"] = "no";
53 textMap["nah"] = "no";
54 textMap["no"] = "no";
55 textMap["n"] = "no";
56 textMap["hit"] = "hit";
57 textMap["h"] = "hit";
58 textMap["stay"] = "stay";
59 textMap["stop"] = "stay";
60 textMap["s"] = "stay";
61}
62
63// processes the natural language passed as a string, returns the processing result
64// - takes the user input string, matches it with the expected answers registered in the
65// textMap, returns the processed answer if the match was successful,
66// "TEXT NOT RECOGNIZABLE" otherwise
67std::string& TextProcessor::processText(std::string& input, const std::string& expected1,
68 const std::string& expected2)
69{
70 std::vector<std::string> tokens;
71 std::string token;
72
73 // switch all characters of the input string to lower case
74 for (auto& ch : input)
75 ch = tolower(ch);
76
77 std::stringstream ss(input);
78
79 // tokenize the input string, search each token for its match in the textMap
80 while (getline(ss, token, ' '))
81 tokens.push_back(token);
82
83 // if matched, return the matched string's pre-defined meaning
84 for (auto tok : tokens)
85 {
86 if (textMap.find(tok) != textMap.end())
87 {
88 input = textMap[tok];
89 break;
90 }
91 }
92
93 // if the processed input matches any of the expected strings
94 if (input == expected1 || input == expected2)
95 return input; // return the input
96
97 // if the processed input does not match any of the expected strings
98 input = "TEXT NOT RECOGNIZABLE"; // signal the caller
99 return input;
100}
101
102