// --------------------------------------------------------------------------- // Blackjack // Plays a simple version of the casino game of blackjack; for 1 - 7 players // // TODO: Update these comments. Include name, date, description // --------------------------------------------------------------------------- // Include file for cout, cin, etc (iostream) // Include file for using std::string and file for std::vector // Include file for using std algorithms (algorithm) // Include file for using time for seeding random number generator (ctime) XXXXXX using namespace std; // --------------------------------------------------------------------------- // --------------------------------------------------------------------------- class Card { public: enum rank {ACE = 1, TWO, THREE, FOUR, FIVE, SIX, SEVEN, EIGHT, NINE, TEN, JACK, QUEEN, KING}; // TODO: created an enumrated type of CLUBS, DIAMONDS, HEARTS, SPADES enum suit {XXXXX //overloading << operator so can send Card object to standard output friend ostream& operator<<(ostream& os, const Card& aCard); Card(rank r = ACE, suit s = SPADES, bool ifu = true); // TODO: is ifu a good var name? //returns the value of a card, 1 - 11 int GetValue() const; //flips a card; if face up, becomes face down and vice versa void Flip(); private: rank m_Rank; suit m_Suit; bool m_IsFaceUp; }; // --------------------------------------------------------------------------- // --------------------------------------------------------------------------- Card::Card(rank r, suit s, bool ifu): m_Rank(r), m_Suit(s), m_IsFaceUp(ifu) { // nothing more to do } // --------------------------------------------------------------------------- // --------------------------------------------------------------------------- int Card::GetValue() const { //if a cards is face down, its value is 0 int value = 0; if (m_IsFaceUp) { //value is number showing on card value = m_Rank; //value is 10 for face cards (m_Rank for face cards is greater than 10) if (value > 10) { value = XXXXXXXX; } } return value; } // --------------------------------------------------------------------------- // --------------------------------------------------------------------------- void Card::Flip() { m_IsFaceUp = XXXXXXXXXX; // TODO: make it not what it is (true becomes false, false becomes true) } // --------------------------------------------------------------------------- // --------------------------------------------------------------------------- // --------------------------------------------------------------------------- class Hand { public: Hand(); virtual ~Hand(); //adds a card to the hand void Add(Card* pCard); //clears hand of all cards void Clear(); //gets hand total value, intelligently treats aces as 1 or 11 int GetTotal() const; protected: vector m_Cards; }; // --------------------------------------------------------------------------- // --------------------------------------------------------------------------- Hand::Hand() { XXXXXXXXX; // TODO: reserve 7 cards by calling m_Cards's reserve function } // --------------------------------------------------------------------------- // --------------------------------------------------------------------------- Hand::~Hand() { Clear(); } // --------------------------------------------------------------------------- // --------------------------------------------------------------------------- void Hand::Add(Card* pCard) { m_Cards.push_back(XXXXXX); // TODO: push pCard onto the m_Cards vector } // --------------------------------------------------------------------------- // --------------------------------------------------------------------------- void Hand::Clear() { //iterate through vector, freeing all memory on the heap vector::iterator iter = m_Cards.begin(); for (iter = m_Cards.begin(); iter != m_Cards.end(); ++iter) { // Notice iter is a reference to a pointer // so dereference it before deleting: "delete *iter" do not "delete iter" XXXXXX; /// TODO delete *iter and set it to NULL *iter = NULL; } //clear vector of pointers m_Cards.clear(); } // --------------------------------------------------------------------------- // --------------------------------------------------------------------------- int Hand::GetTotal() const { //if no cards in hand, return 0 if (XXXXXXX) // TODO: check if m_Cards empty function returns true { return 0; } //if a first card has value of 0, then card is face down; return 0 if (m_Cards[0] XXXXXX GetValue() == 0) // TODO: change the X's to a period or an arrow? that is the question { return 0; } //add up card values, treat each Ace as 1 int total = 0; vector::const_iterator iter; for (iter = m_Cards.begin(); iter != m_Cards.end(); ++iter) { total += (*iter)->GetValue(); } //determine if hand contains an Ace bool containsAce = false; for (iter = m_Cards.begin(); iter != m_Cards.end(); ++iter) { if ((*iter)->GetValue() == Card::ACE) { containsAce = true; } } //if hand contains Ace and total is low enough, treat Ace as 11 if (containsAce && total <= 11) { //add only 10 since we've already added 1 for the Ace total += 10; } return total; } // --------------------------------------------------------------------------- // --------------------------------------------------------------------------- // --------------------------------------------------------------------------- // --------------------------------------------------------------------------- class GenericPlayer : public Hand { friend ostream& operator<<(ostream& os, const GenericPlayer& aGenericPlayer); public: GenericPlayer(const string& name = ""); virtual ~GenericPlayer(); //indicates whether or not generic player wants to keep hitting virtual bool IsHitting() const = 0; //returns whether generic player has busted - has a total greater than 21 bool IsBusted() const; //announces that the generic player busts void Bust() const; protected: string m_Name; }; // --------------------------------------------------------------------------- // --------------------------------------------------------------------------- GenericPlayer::GenericPlayer(const string& name): XXXXXXX // TODO use an initialization list to set m_Name = name { // nothing more to do } // --------------------------------------------------------------------------- // --------------------------------------------------------------------------- GenericPlayer::~GenericPlayer() { // nothing to be done, do need this function though } // --------------------------------------------------------------------------- // --------------------------------------------------------------------------- bool GenericPlayer::IsBusted() const { return (XXXXXXXXX); // TODO: if GetTotal() > 21 return true, else return false } // --------------------------------------------------------------------------- // --------------------------------------------------------------------------- void GenericPlayer::Bust() const { cout << m_Name << " busts.\n"; } // --------------------------------------------------------------------------- // --------------------------------------------------------------------------- // --------------------------------------------------------------------------- // --------------------------------------------------------------------------- // --------------------------------------------------------------------------- class Player : public GenericPlayer { public: Player(const string& name = ""); virtual ~Player(); //returns whether or not the player wants another hit virtual bool IsHitting() const; //announces that the player wins void Win() const; //announces that the player loses void Lose() const; //announces that the player pushes void Push() const; }; // --------------------------------------------------------------------------- // --------------------------------------------------------------------------- Player::Player(const string& name): GenericPlayer(name) { // nothing more to do } // --------------------------------------------------------------------------- // --------------------------------------------------------------------------- Player::~Player() { // nothing required, but function is needed } // --------------------------------------------------------------------------- // Player::IsHitting() const returns a boolean // --------------------------------------------------------------------------- XXXXXXXXX { cout << m_Name << ", do you want a hit? (Y/N): "; char response; cin >> response; return (response == 'y' || response == 'Y'); } // --------------------------------------------------------------------------- // --------------------------------------------------------------------------- void Player::Win() const { cout << m_Name << " wins.\n"; } // --------------------------------------------------------------------------- // --------------------------------------------------------------------------- void Player::Lose() const { cout << m_Name << " loses.\n"; } // --------------------------------------------------------------------------- // --------------------------------------------------------------------------- void Player::Push() const { cout << m_Name << " pushes.\n"; } // --------------------------------------------------------------------------- // --------------------------------------------------------------------------- // --------------------------------------------------------------------------- // --------------------------------------------------------------------------- // --------------------------------------------------------------------------- class House : public GenericPlayer { public: House(const string& name = "House"); virtual ~House(); //indicates whether house is hitting - will always hit on 16 or less virtual bool IsHitting() const; //flips over first card void FlipFirstCard(); }; // --------------------------------------------------------------------------- // --------------------------------------------------------------------------- House::House(const string& name): GenericPlayer(name) { // nothing more to do } // --------------------------------------------------------------------------- // --------------------------------------------------------------------------- House::~House() { // no memory to free } // --------------------------------------------------------------------------- // --------------------------------------------------------------------------- bool House::IsHitting() const { return (GetTotal() <= XXXXXX); // TODO: if GetTotal() <= 16 return true else false } // --------------------------------------------------------------------------- // --------------------------------------------------------------------------- void House::FlipFirstCard() { if (!(m_Cards.empty())) { m_Cards[0]->Flip(); } else { cout << "No card to flip!\n"; } } // --------------------------------------------------------------------------- // --------------------------------------------------------------------------- // --------------------------------------------------------------------------- // --------------------------------------------------------------------------- class Deck : public Hand { public: Deck(); virtual ~Deck(); //create a standard deck of 52 cards void Populate(); //shuffle cards void Shuffle(); //deal one card to a hand void Deal(Hand& aHand); //give additional cards to a generic player void AdditionalCards(GenericPlayer& aGenericPlayer); }; // --------------------------------------------------------------------------- // --------------------------------------------------------------------------- Deck::Deck() { m_Cards.reserve(XXXXXXXX); // TODO: reserve 52 cards Populate(); } // --------------------------------------------------------------------------- // --------------------------------------------------------------------------- Deck::~Deck() { // no memory to free } // --------------------------------------------------------------------------- // --------------------------------------------------------------------------- void Deck::Populate() { Clear(); //create standard deck for (int s = Card::CLUBS; s <= Card::SPADES; ++s) { for (int r = Card::ACE; r <= Card::KING; ++r) { Add(new Card(static_cast(r), static_cast(s))); } } } // --------------------------------------------------------------------------- // --------------------------------------------------------------------------- void Deck::Shuffle() { random_shuffle(m_Cards.begin(), m_Cards.end()); } // --------------------------------------------------------------------------- // --------------------------------------------------------------------------- void Deck::Deal(Hand& aHand) { if (!m_Cards.empty()) { aHand.Add( XXXXXXX ); // TODO: Add the card that is at the 'top' of the deck: m_Cards.back() m_Cards.pop_back(); // Remove the card at the top of the deck (aside top = back of the deck) } else { cout << "Out of cards. Unable to deal."; } } // --------------------------------------------------------------------------- // --------------------------------------------------------------------------- void Deck::AdditionalCards(GenericPlayer& aGenericPlayer) { cout << endl; //continue to deal a card as long as generic player isn't busted and //wants another hit while ( !(aGenericPlayer.IsBusted()) && aGenericPlayer.IsHitting() ) { Deal(aGenericPlayer); cout << aGenericPlayer << endl; if (aGenericPlayer.IsBusted()) { aGenericPlayer.Bust(); } } } // --------------------------------------------------------------------------- // --------------------------------------------------------------------------- // --------------------------------------------------------------------------- // --------------------------------------------------------------------------- // --------------------------------------------------------------------------- class Game { public: Game(const vector& names); ~Game(); //plays the game of blackjack void Play(); private: Deck m_Deck; House m_House; vector m_Players; // TODO: declare a vector of type Player, named m_Players }; // --------------------------------------------------------------------------- // --------------------------------------------------------------------------- Game::Game(const vector& names) { //create a vector of players from a vector of names vector::const_iterator pName; for (pName = names.begin(); pName != names.end(); ++pName) { m_Players.push_back(Player(*pName)); } //seed the random number generator srand(static_cast(time(0))); m_Deck.Populate(); // Populates the deck using deck's Populate function XXXXXXX; // TODO: Shuffle the deck using deck's Shuffle function } // --------------------------------------------------------------------------- // --------------------------------------------------------------------------- Game::~Game() { // nothing needed } // --------------------------------------------------------------------------- // --------------------------------------------------------------------------- void Game::Play() { //deal initial 2 cards to everyone vector::iterator pPlayer; for (int i = 0; i < 2; ++i) { for (pPlayer = m_Players.begin(); pPlayer != m_Players.end(); ++pPlayer) { m_Deck.Deal(*pPlayer); } m_Deck.Deal(m_House); } //hide house's first card m_House.FlipFirstCard(); //display everyone's hand for (pPlayer = m_Players.begin(); pPlayer != m_Players.end(); ++pPlayer) { cout << *pPlayer << endl; } cout << m_House << endl; //deal additional cards to players for (pPlayer = m_Players.begin(); pPlayer != m_Players.end(); ++pPlayer) { m_Deck.AdditionalCards(*pPlayer); } //reveal house's first card m_House.FlipFirstCard(); cout << endl << m_House; //deal additional cards to house m_Deck.AdditionalCards(m_House); if (m_House.IsBusted()) { //everyone still playing wins for (pPlayer = m_Players.begin(); pPlayer != m_Players.end(); ++pPlayer) { if ( !(pPlayer->IsBusted()) ) { pPlayer->Win(); // call the pPlayer win function (notice arrow usage) } } } else { //compare each player still playing to house for (pPlayer = m_Players.begin(); pPlayer != m_Players.end(); ++pPlayer) { if ( !(pPlayer->IsBusted()) ) { if (pPlayer->GetTotal() > m_House.GetTotal()) { XXXXXXXX; // TODO: call the pPlayer Win function use an arrow -> } else if (pPlayer->GetTotal() < m_House.GetTotal()) { pPlayer->Lose(); } else { pPlayer->Push(); // Could also make player Lose depends on rules you want to implement } } } // end for } // end else //remove everyone's cards for (pPlayer = m_Players.begin(); pPlayer != m_Players.end(); ++pPlayer) { pPlayer->Clear(); } m_House.Clear(); } // --------------------------------------------------------------------------- // --------------------------------------------------------------------------- // --------------------------------------------------------------------------- // --------------------------------------------------------------------------- // --------------------------------------------------------------------------- // GLOBAL function prototypes // --------------------------------------------------------------------------- ostream& operator<<(ostream& os, const Card& aCard); ostream& operator<<(ostream& os, const GenericPlayer& aGenericPlayer); // --------------------------------------------------------------------------- // --------------------------------------------------------------------------- // --------------------------------------------------------------------------- // main - it all begins here // --------------------------------------------------------------------------- int main() { cout << "\t\tWelcome to Blackjack!\n\n"; XXXXXXX; // declare a variable named numPlayers of type int, initialized to zero while (numPlayers < 1 || numPlayers > 7) { cout << "How many players? (1 - 7): "; cin >> numPlayers; } vector names; // TODO: create a vector of type string string name; for (int i = 0; i < numPlayers; ++i) { cout << "Enter player name: "; cin >> name; names.push_back(name); } cout << endl; //the game loop Game aGame(names); char again = 'y'; while (again != 'n' && again != 'N') { XXXXXXX; // TODO: call aGame's Play() function cout << "\nDo you want to play again? (Y/N): "; cin >> again; } return 0; } // --------------------------------------------------------------------------- // GLOBAL functions follow // --------------------------------------------------------------------------- // --------------------------------------------------------------------------- // --------------------------------------------------------------------------- // --------------------------------------------------------------------------- //overloads << operator so Card object can be sent to cout // --------------------------------------------------------------------------- ostream& operator<<(ostream& os, const Card& aCard) { const string RANKS[] = {"0", "A", "2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K"}; const string SUITS[] = {"c", "d", "h", "s"}; if (aCard.m_IsFaceUp) { os << RANKS[aCard.m_Rank] << SUITS[aCard.m_Suit]; } else { os << "XX"; } return os; } // --------------------------------------------------------------------------- //overloads << operator so a GenericPlayer object can be sent to cout // --------------------------------------------------------------------------- ostream& operator<<(ostream& os, const GenericPlayer& aGenericPlayer) { os << aGenericPlayer.m_Name << ":\t"; vector::const_iterator pCard; if (!aGenericPlayer.m_Cards.empty()) { for (pCard = aGenericPlayer.m_Cards.begin(); pCard != aGenericPlayer.m_Cards.end(); ++pCard) { os << *(*pCard) << "\t"; } if (aGenericPlayer.GetTotal() != 0) { cout << "(" << aGenericPlayer.GetTotal() << ")"; } } else { os << ""; } return os; } // --------------------------------------------------------------------------- // file ends