Section 3 - Returning to Cards
7B.3.1 Cards
Let's return to our card program. To get started, we want to place our classes in separate files, so start an empty console application and add two files: a Card.h header file and a Card.cpp source file. You will then have three files to work with: these two and your main file (based on the name of your project, mine is still Foothill).
Let's pour our Card and Deck classes into the two Card files:
CardSupport.h
// CS 2B - LOCEFF // CardSupport.h Header File #pragma once #include <iostream> #include <ctime> #include <string> #include <cctype> using namespace std; // class Card prototype ---------------------------------------- class Card { public: enum Suit { clubs, diamonds, hearts, spades }; private: char value; Suit suit; bool errorFlag; public: Card(char value = 'A', Suit suit = spades); string toString(); bool set(char value = 'A', Suit suit = spades); char getVal() { return value; } Suit getSuit() { return suit; } bool getErrorFlag() { return errorFlag; } bool equals(Card card); // helpers private: bool isValid(char value, Suit suit); }; // class Hand prototype ---------------------------------------- class Hand { public: // need this in-line for array declaration static const int MAX_CARDS_PER_HAND = 50; // that should be enough for any game private: Card myCards[MAX_CARDS_PER_HAND]; int numCards; public: Hand() { resetHand(); } // mutators void resetHand() { numCards = 0; } bool takeCard(Card card); Card playCard(); // accessors string toString(); int getNumCards() { return numCards; } Card inspectCard(int k); }; // class Deck prototype ---------------------------------------- class Deck { // six full decks is enough for about any game static const int MAX_CARDS_PER_DECK = 6 * 52; static Card masterPack[52]; // one 52-card master for initializing decks private: Card cards[MAX_CARDS_PER_DECK]; int topCard; int numPacks; public: Deck(int numPacks = 1); void init(int numPacks = 1); int getNumCards() { return topCard; } void shuffle(); Card dealCard(); Card inspectCard(int k); string toString(); private: static void allocateMasterPack(); bool floatLargestToTop(int top); void swap(Card &a, Card &b); };
CardSupport.cpp
// CS 2B - LOCEFF // CardSupport.cpp source file #include "CardSupport.h" // beginning of Card method definitions ---------------------------------------- // constructor Card::Card(char value, Suit suit) { // because mutator sets errorFlag, we don't have to test set(value, suit); } // stringizer string Card::toString() { string retVal; char strVal[2]; if (errorFlag) return "** illegal **"; // convert char to a CString, then string strVal[0] = value; strVal[1] = '\0'; retVal = string(strVal); if (suit == spades) retVal += " of Spades"; else if (suit == hearts) retVal += " of Hearts"; else if (suit == diamonds) retVal += " of Diamonds"; else if (suit == clubs) retVal += " of Clubs"; return retVal; } // mutator bool Card::set(char value, Suit suit) { char upVal; // convert to uppercase to simplify (may need to #include <cctype>) upVal = toupper((int)value); if ( !isValid(upVal, suit)) { errorFlag = true; return false; } // else implied errorFlag = false; this->value = upVal; this->suit = suit; return true; } // helper bool Card::isValid(char value, Suit suit) { char upVal; // convert to uppercase to simplify (need #include <cctype>) upVal = toupper((int)value); // check for validity if ( upVal == 'A' || upVal == 'K' || upVal == 'Q' || upVal == 'J' || upVal == 'T' || (upVal >= '2' && upVal <= '9') ) return true; else return false; } bool Card::equals(Card card) { if (this->value != card.value) return false; if (this->suit != card.suit) return false; if (this->errorFlag != card.errorFlag) return false; return true; } // end of Card method definitions ---------------------------------------- // beginning of Hand method definitions ---------------------------------------- bool Hand::takeCard(Card card) { if (numCards >= MAX_CARDS_PER_HAND) return false; // don't just assign: mutator assures active/undeleted myCards[numCards++].set( card.getVal(), card.getSuit() ); return true; } Card Hand::playCard() { // always play highest card in array. client will prepare this position. // in rare case that client tries to play from a spent hand, return error Card errorReturn(0, Card::spades); // in rare cases if (numCards == 0) return errorReturn; else return myCards[--numCards]; } Card Hand::inspectCard(int k) { // return copy of card at position k. // if client tries to access out-of-bounds card, return error Card errorReturn(0, Card::spades); // force errorFlag in return, in rare cases if (k < 0 || k >= numCards) return errorReturn; else return myCards[k]; } string Hand::toString() { int k; string retVal = "Hand = ( "; for (k = 0; k < numCards; k++) { retVal += myCards[k].toString(); if (k < numCards - 1) retVal += ", "; } retVal += " )"; return retVal; } // end of Hand method definitions ------------------------------------ // beginning of Deck method definitions ------------------------------ Card Deck::masterPack[52]; // static definition Deck::Deck(int numPacks) { // place cards in the deck, in perfect order allocateMasterPack(); init(numPacks); } void Deck::allocateMasterPack() { int k, j; Card::Suit st; char val; // we're in a static method; only needed once per program: good for whole class static bool firstTime = true; if ( !firstTime ) return; firstTime = false; // first load an array of cards with values for (k = 0; k < 4; k++) { // set the suit for this loop pass st = (Card::Suit)k; // now set all the values for this suit masterPack[13*k].set('A', st); for (val='2', j = 1; val<='9'; val++, j++) masterPack[13*k + j].set(val, st); masterPack[13*k+9].set('T', st); masterPack[13*k+10].set('J', st); masterPack[13*k+11].set('Q', st); masterPack[13*k+12].set('K', st); } } } // set deck from 1 to 6 packs, perfecly ordered void Deck::init(int numPacks) { int k, pack; if (numPacks < 1 || numPacks > 6) numPacks = 1; // when initing, reset the random num generator for shuffling srand(time(NULL)); // then transfer these values to our deck for (pack = 0; pack < numPacks; pack++) for (k = 0; k < 52; k++) cards[pack * 52 + k] = masterPack[k]; this->numPacks = numPacks; topCard = numPacks * 52; } void Deck::shuffle() { Card tempCard; int k, randInt; // topCard is size of deck for (k = 0; k < topCard; k++) { randInt = rand() % topCard; // swap cards k and randInt (sometimes k == randInt: okay) tempCard = cards[k]; cards[k] = cards[randInt]; cards[randInt] = tempCard; } } Card Deck::dealCard() { // always deal the topCard. Card errorReturn(0, Card::spades); // in rare cases if (topCard == 0) return errorReturn; else return cards[--topCard]; } Card Deck::inspectCard(int k) { // return copy of card at position k. // if client tries to access out-of-bounds card, return error Card errorReturn(0, Card::spades); // force errorFlag in return, in rare cases if (k < 0 || k >= topCard) return errorReturn; else return cards[k]; } // end of Hand method definitions ------------------------------------
Your Main .cpp file
This is just to make sure your project is working before we start monkeying with it:
// CS 2B - LOCEFF // Client driver for Card, Hand, Deck classes ============ #include "CardSupport.h" #define MAX_HANDS 10 // main client -------------------------------------------------------- int main() { int k, numHands; Deck deck(1); Hand hands[MAX_HANDS]; // get the input from the user -------------------------- do { cout << "How many hands? (1 - " << MAX_HANDS << ", please): "; cin >> numHands; } while (numHands < 1 || numHands > MAX_HANDS); // deal deck, unshuffled -------------------------------- while (deck.getNumCards() > 0) { for (k = 0; k < numHands; k++) { if (deck.getNumCards() == 0) break; hands[k].takeCard( deck.dealCard() ); } } cout << "Here are our hands, from unshuffled deck:" << endl; for (k = 0; k < numHands; k++) { cout << hands[k].toString() << endl << endl; } cout << endl; // restock, deal deck, shuffled -------------------------- deck.init(1); deck.shuffle(); // clear hands for (k = 0; k < numHands; k++) hands[k].resetHand(); while (deck.getNumCards() > 0) { for (k = 0; k < numHands; k++) { if (deck.getNumCards() == 0) break; hands[k].takeCard( deck.dealCard() ); } } cout << "Here are our hands, from SHUFFLED deck:" << endl; for (k = 0; k < numHands; k++) { cout << hands[k].toString() << endl << endl; } return 0; }
Get that working first. Also review it to make sure you remember how it all works.