// // WAR card game // // Described in Chapter 2 of // Data Structures in C++ using the STL // Published by Addison-Wesley, 1997 // Written by Tim Budd, budd@cs.orst.edu // Oregon State University // # include //# include #include using namespace std; enum suits {diamond, club, heart, spade}; class Card { public: // constructors Card ( ); // initialize a card with default values Card (suits, int); // initialize a card with given values // data fields int rank; // hold rank of card suits suit; // hold suit of card }; Card::Card ( ) // initialize a new Card // default value is the ace of spades { rank = 1; suit = spade; } Card::Card (suits sv, int rv) // initialize a new Card using the argument values { rank = rv; suit = sv; } bool operator == (Card & leftCard, Card & rightCard) { // determine if the first card is equal to the second - uses rank only if (leftCard.rank == rightCard.rank) { return true; } else { return false; } return true; // should never be executed } bool operator > (Card & leftCard, Card & rightCard) { // determine if the first card is greater than the second - uses rank only if (leftCard == rightCard) { return false; } else if (leftCard.rank == 1) { // ace (and not both aces) return true; } else if (rightCard.rank == 1) { // ace (and not both aces) return false; } else if (leftCard.rank > rightCard.rank) { // aces out of way - so higher rank means better card return true; } else { // second card is better return false; } return true; // should never be executed } bool operator < (Card & leftCard, Card & rightCard) { // first is less than if it is not equal to and not greater than if (leftCard == rightCard) { return false; } if (leftCard > rightCard) { return false; } return true; // true if not either of the above } ostream & operator << (ostream & out, Card & aCard) // output a textual representation of a Card { // first output rank switch (aCard.rank) { case 1: out << "Ace"; break; case 11: out << "Jack"; break; case 12: out << "Queen"; break; case 13: out << "King"; break; default: // output number out << aCard.rank; break; } // then output suit switch (aCard.suit) { case diamond: out << " of Diamonds"; break; case spade: out << " of Spades"; break; case heart: out << " of Hearts"; break; case club: out << " of Clubs"; break; } return out; } class randomInteger { public: unsigned int operator () (unsigned int); } randomizer; unsigned int randomInteger::operator () (unsigned int max) { // rand return random integer // convert to unsigned to make positive // take remainder to put in range unsigned int rval = rand(); return rval % max; } class Deck { public: // constructor Deck ( ); // operations void shuffle ( ) { random_shuffle (cards, cards+52, randomizer); } bool isEmpty ( ) { return topCard <= 0; } Card draw ( ); // show whole deck to check things out void Show (); protected: Card cards[52]; int topCard; }; Deck::Deck ( ) // initialize a deck by creating all 52 cards { topCard = 0; for (int i = 1; i <= 13; i++) { Card c1(diamond, i), c2(spade, i), c3(heart, i), c4(club, i); cards[topCard++] = c1; cards[topCard++] = c2; cards[topCard++] = c3; cards[topCard++] = c4; } } Card Deck::draw ( ) // return one card from the end of the deck { if (! isEmpty()) return cards[--topCard]; else { // otherwise return ace of spades Card spadeAce(spade, 1); return spadeAce; } } void Deck::Show() { cout << endl << "Deck: (topCard " << topCard << "): "; for (int j = 0;j < 52;j++){ cout << cards[j] << " | "; } cout << endl; return; } class Player { public: // constructor Player (Deck &); // operations Card draw ( ); void addPoints (int); int score (); void replaceCard (Deck &); protected: Card myCards[3]; int myScore; int removedCard; }; Player::Player (Deck & aDeck) // initialize the data fields for a player { myScore = 0; for (int i = 0; i < 3; i++) myCards[i] = aDeck.draw(); removedCard = 0; } Card Player::draw ( ) // return a random card from our hand { removedCard = randomizer(3); return myCards[removedCard]; } void Player::addPoints (int howMany) // add the given number of points to the current score { myScore += howMany; } int Player::score ( ) // return the current score { return myScore; } void Player::replaceCard (Deck & aDeck) // replace last card played with new card { myCards[removedCard] = aDeck.draw(); } // just for demonstration purposes void testmain() { Card cardOne; Card cardTwo(diamond,7); cout << "Card one: "; cout << cardOne.rank << " " << cardOne.suit << endl; cout << "Card two: "; cout << cardTwo.rank << " " << cardTwo.suit << endl; return; } // just for demonstration purposes void bettermain() { Card cardOne; Card cardTwo(diamond,7); cout << "Card one: " << cardOne << endl; cout << "Card two: " << cardTwo << endl; return; } void trydeckmain() { Deck myDeck; myDeck.shuffle(); for (int j = 0;j < 52;j++){ cout << myDeck.draw() << " | "; } return; } // real main void main() { // MAR for the heck of it - try out the randomizer object cout << "Demo randomInteger () operator "; for (int i = 0; i < 100; i++){ cout << randomizer(52) << " "; } cout << endl; // MAR 1/25/00 - allow either stopping after each battle or wizzing through // MAR 2/2/00 - validate answer now char answ; do { cout << "Run fast? (y or n) " << flush; cin >> answ; } while ((answ != 'n') && (answ != 'N') && (answ != 'y') && (answ != 'Y')); // standardize answer if (answ == 'Y') { answ = 'y'; } Deck theDeck; // create and shuffle the deck theDeck.shuffle(); theDeck.Show(); Player player1(theDeck); // create the two Player player2(theDeck); // players // play until deck is empty // BUG discovered MAR 1/25/00 // only play til deck is empty even though players have 3 cards left while (! theDeck.isEmpty() ) { Card card1 = player1.draw(); cout << "Player 1 plays " << card1 << endl; Card card2 = player2.draw(); cout << "Player 2 plays " << card2 << endl; int points = 2; // initialize to default points for trick // *** this doesn't suitably deal with if the deck runs out of cards if (card1 == card2) { // tie // MAR 2/2/00 the above WAS card1.rank etc // while there are cards and tie not broken - try to break tie bool broken = false; while (! theDeck.isEmpty() && ! broken) { cout << "Players tie\n"; // now replace the cards previously drawn player1.replaceCard(theDeck); player2.replaceCard(theDeck); // burn 3 cards from each players hand for (int i = 0; i < 3; i++) { if (! theDeck.isEmpty() ) { // burn card from hand and replace it Card extra = player1.draw(); player1.replaceCard(theDeck); cout << " Player 1 upside down card: " << extra << endl; points++; } if (! theDeck.isEmpty() ) { // player 2 burn card from hand and replace it Card extra2 = player2.draw(); player2.replaceCard(theDeck); cout << " Player 2 upside down card: " << extra2 << endl; points++; } } // end for 3 // now play tie breakers Card tiecard1 = player1.draw(); cout << "Player 1 plays " << tiecard1 << endl; points++; Card tiecard2 = player2.draw(); cout << "Player 2 plays " << tiecard2 << endl; points++; // (note - if we have a winner - cards will be replaced // after exit from while loop; if we don't have a winner // cards will be replaced at top of the while loop // see if we have a winner if ( ! (tiecard1 == tiecard2)) { // tie broken broken = true; if (tiecard1 > tiecard2) { player1.addPoints(points); cout << "Player 1 wins round worth " << points << " points" << endl; } else { player2.addPoints(points); cout << "Player 2 wins round worth " << points << " points" << endl; } } // end if (if tie not broken we just continue looping) } // end while // old way 0 - just count 1 point for each player // tossed out on 2/2/00 //player1.addPoints(1); //player2.addPoints(1); //cout << "Players tie\n"; } // end if tie // BUG Discovered MAR 1/25/00 // Ace rank is 1 - so this makes ace lose to everything // My recommmend is to define an > operator for Card // MAR 2/2/00 the below test WAS card1.rank > card2.rank else if (card1 > card2) { player1.addPoints(2); cout << "Player 1 wins round\n"; } else { player2.addPoints(2); cout << "Player 2 wins round\n"; } // MAR 1/25/00 - as long as user didn't say run fast // wait so user can see results if (answ != 'y') { cout << "Enter a non-blank character to continue " << flush; char wait; cin >> wait; } // now replace the cards drawn player1.replaceCard(theDeck); player2.replaceCard(theDeck); } cout << "Player 1 score " << player1.score() << endl; cout << "Player 2 score " << player2.score() << endl; }