For this project, you will implement member functions of two C++ classes that can be used to play the game of poker. In object-oriented design, the classes should model things in the problem domain. In this situation, the two classes that you will work with are Card (which models a single playing card) and PokerHand (which models a five-card poker hand).
Card is the simpler class. It has just two data members. One stores the suit of the playing card and another stores the point value. Besides the constructors, the Card class only has accessors and a member function to print the card to standard output.
The PokerHand class is more complicated. First, it has an array of five Card objects. There is a member function to print a PokerHand and a member function to get the rank of a PokerHand. There is also a member function that compares two PokerHand objects and figures out which one is better according to the rules of poker. (If you are not familiar with poker, please see the list of poker hands.) There are several more member functions of PokerHand that you will have to implement. (See below.)
C++ class definitions include data members and member functions. They can also include type definitions and constants. For example, in the definition of the Card class, we have:
This defines a new type called cSuit. Variables of type cSuit can be assigned a constant value like Clubs. (Please see the section on enumeration types in your textbook.) For example, the data member in Card that holds the suit of a card is declared as:
Note that within the class definition or within the body of a member function, you may use cSuit, Invalid, Clubs, Diamonds, ... without any qualification. Outside the class definition and the body of a member function, you must use Card::cSuit, Card::Clubs... For example, even in the implementation of the Card class, the return value of accessor function for m_suit, must be declared as:
Similarly, there is a type definition for the point value of a card. These are stored as an unsigned int.
In the PokerHand class, we also have a type definition for an enumeration type:
Again, within the PokerHand class definition and within the body of PokerHand member functions, variables that store the rank of a poker hand should be declared using pRank. Outside, PokerHand::pRank should be used. Note that pRank variables hold int values and may be compared. For example,
In the PokerHand class, we also have the constant:
Your assignment is to implement the member functions of the Card class and the PokerHand class. The class definitions are given in separate files:
For the Card class, you are also provided with a skeleton for the implementation card.cpp that has the function declaration of each function. For the PokerHand class, you are given pokerhand.cpp that just has the default constructor and part of the alternate constructor implemented. You have to fill in the rest yourself.You have also been provided two main programs that use the Card and PokerHand classes: play5.cpp and play7.cpp. The main program in play5.cpp simply creates two five-card poker hands and uses the cmp() member function to compare them. The main program in play7.cpp is more elaborate and uses PokerHand member functions to determine which two cards should be dropped at the end of a game of seven-card stud. It tries all possible ways of dropping two cards from a hand of seven cards so that the remaining five cards form the best possible poker hand.
These two programs do not fully exercise the member functions that you will implement. They do not even call every function. You should write your own test programs to check the correctness of all of the functions. Even if your code compiles and runs with these two programs, it might not compile and run with the programs that we will use for grading. You are responsible for testing your own code.
The header file for each class has comments describing what each member function has to accomplish. We make some additional comments here:
For the Card class:
For the PokerHand class, there are some complications. First, it is much easier to determine the rank of a poker hand if the cards are sorted by points. For example, if you want to check if a hand is a Two Pair, there are only 3 possible patterns when the cards are sorted. A Two Pair hand must have a 2-2-1, 2-1-2 or 1-2-2 pattern. The 2-2-1 pattern means the first two cards are a pair with the same point value. The next two cards are a pair with a different (higher) point value. Finally, the last card is by itself and has a point value higher than the second pair. Because the cards are sorted, there are no other patterns possible to make a Two Pair. Since sorting is so useful, it should be done by the constructors. That way, all member functions can assume that the hand is already sorted.
Note that poker ranks are mutually exclusive. A Full House is not a Two Pair, even though there are two pairs in a Full House. Similarly, a Straight Flush is not a Straight and a Royal Flush is not a Straight Flush. Thus, if two poker hands have different ranks, we can quickly determine which hand is better. Your implementation should store the rank of the hand in the data member m_rank after it has been computed for the first time. This way you can avoid having to recompute the rank when the client calls getRank(). Before the rank has been computed, m_rank should hold the value NoRank. That is how you can tell if the rank has been computed previously. The constructors must make sure that m_rank is initialized to NoRank.
If two PokerHand objects have the same rank, your cmp() function should still determine which hand is better according to the rules of poker. A tie is possible, but this is not determined just by the rank. For example, if two hands are both Two Pair, the hand whose higher pair has higher point value wins. If that's a tie, then the hand whose lower pair has higher point value wins. If that's a tie, then the fifth card, the one that is not in any pair, is used to break the tie. If the fifth cards are once again tied, then the two hands are tied. Thus, to determine which of the Two Pair hands is better, we need three values: the point value of the higher pair, the point value of the lower pair and the point value of the last card. These three values can be determined easily when you first discovered that the rank of the hand is two pair. For example, when you check if the hand is a Two Pair with the 2-2-1 pattern, you can do the following:
Then, the cmp() function can use the data members m_firstPairPoints, m_secondPairPoints and m_lastCardPoints to determine which of two hands with rank of Two Pair is better.
Overall, we just need five data members to store this "additional information" in order the compare any two poker hands:
Full explanation for these data members are in pokerhand.h.
Here is a list of the member functions in PokerHand that you must implement:Note that cmp() compares the host object versus the otherHand object. The return value being negative, zero or positive indicates whether the host is worse than, tied with or better than otherHand, respectively. The cmp() function should not assume that the cards in the two hands come from the same deck of cards. For example, cmp() may be asked to compare two hands that both have 4 Aces. This is not possible for two competing hands in a poker game. However, the main program in play7.cpp may ask cmp() which of two hands with 4 Aces is better in order to determine which 2 out of 7 cards to drop.
Here are some issues to consider and pitfalls to avoid. (You should read these before coding!)
You do not need to submit card.h, play5.cpp or play7.cpp because those files should not have changed.
If you followed the directions in setting up shared directories, then you can copy your code to the submission directory with:
If you are submitting late, you need to copy to proj2-late1, or proj2-late2 instead of proj2. Make sure you understand the course late submission policy.