Write a text-based video poker game.
Textbook: (3.8); 12.5; 7.7; 6.5
Concepts: (wrapper classes); generics; ArrayList; interfaces (Comparable
)
You are going to write a video poker game. This is basically a 5-card draw poker slot machine.
Your video poker game should take only one token/credit per hand. It should have the same payout rate as "Jacks or Better" when playing 1 credit. However, unlike Jacks or Better, any pair pays 1 token; also, you may only trade in up to 3 cards (not all 5, as in video poker).
You may need to review the different kinds of hands in poker.
There are also a number of requirements given below regarding some of the classes and methods you must have.
PlayingCard
Reuse this from A16. However, you must implement the Comparable
interface:
public class PlayingCard implements Comparable<PlayingCard> {
The compiler will then force you to add the following method:
public int compareTo(PlayingCard pc) {
This method should return a number < 0 if this
PlayingCard comes before the given PlayingCard (pc
), or > 0 if it comes after, or 0 if the two cards are the same. Aces should come after Kings (Aces high).
You are required to sort cards only by value. (That is, comparing an 8 of Spades
to an 8 of Hearts
can return 0.) Optional: However, it would be good practice to sort cards of the same value by suit so that this method returns 0 only on truly equal cards.
Don't make any changes other than adding this interface/method. Your PlayingCard should still work with your A16 program when you're done.
Deck
The cards of each hand of video poker should be generated as if from a Deck of cards. Therefore, you'll need to reuse your Deck class here. You should not need to make any changes, though. (Yay!)
PokerHand
You are required to write this class so that Tamarin can easily test your hand-checking code. Also, it will help you break the problem of determining the current poker hand into smaller chunks. You are required to have the following methods in this class:
public PokerHand(PlayingCard one, PlayingCard two, PlayingCard three,
PlayingCard four, PlayingCard five)
You must have this constructor that takes 5 playing cards.
Optional: You may write additional constructors if you want to. Examples include a default PokerHand()
constructor that creates an empty hand (which you can then use a separate add
method to add cards to), or a PokerHand(PlayingCard[] cards)
or PokerHand(ArrayList<PlayingCard> cards)
that takes an array/list of 5 cards.
public boolean isPair()
public boolean isTwoPair()
public boolean isThreeOfAKind()
public boolean isStraight()
public boolean isFlush()
public boolean isFullHouse()
public boolean isFourOfAKind()
public boolean isStraightFlush()
public boolean isRoyalFlush()
Remember that an Ace in a straight can be either high or low. It must be high in a royal flush.
Sometimes more than one test may match a given set of cards. In this case, you are only required to return true
from the test that matches the highest-scoring hand possible for the given cards. From the valid lower-scoring matches, you may return either true or false, depending on how you choose to implement your methods.
For example, suppose the current PokerHand
contains the cards: 5C 5S 5H 8S 9D
. This hand is a 3-of-a-kind, so the isThreeOfAKind()
method must return true
in this case. However, isPair()
may or may not return true
(it's up to you), as there is a pair in the hand but it is not the highest-scoring possible match. Every other test should return false
in this case, since no other matches are even possible.
public String toString()
This method should return a String representing the 5 cards currently in the hand. They should be in sorted order (low to high, Aces high). Playing cards should be displayed using integers for values between 2 and 10; face card values should be Jack, Queen, King, and Ace. For both suits and face cards, you may use only the first capital letter of the word instead of the whole word, if you wish. That is, your cards can be in the format used in A16 or else you can use the 2-character format shown in the sample output below.
You may write whatever additional methods you need in this class.
PokerHand
It is very easy to make subtle errors that cause runtime or logic errors in the is???
methods. (For example, I only got about 1/2 of them right on the first attempt; however, each error was easy to spot once I knew there was an error to look for.) Therefore, testing is essential. Since some of these hands happen very rarely in a real video poker game, this means writing some test code that constructs a variety of different possible hands and tests each method.
To help save you time, I have provided the following test code: PokerHandTester.java
I won't guarantee that it'll catch every possible error in your code, but it should catch most of them. Feel free to add additional tests if your implementation has a lot of logical branches that each need to be tested.
UsernameA17
Now you're finally ready to write the user interface!
Open a new deck, draw 5 cards, and form the user's initial hand. Print this in sorted order.
Then ask the user which cards (up to 3) they wish to discard. Your allowed input should be the integers 1 to 5 (each corresponding to one of the 5 cards in their hand) or 0 to stop discarding. Replace any discarded cards with new ones drawn from the deck.
Then print out the final hand and the corresponding payout (assuming an initial bet of 1 token):
Pair 1x TwoPair 2x ThreeOfAKind 3x Straight 4x Flush 6x FullHouse 9x FourOfAKind 25x StraightFlush 50x RoyalFlush 250x
Optional: You may have your program loop so that it plays multiple games. You could even keep a running total of tokens won/lost, if you wanted to. 13 Apr 2010: Actually, if you have not finished your program yet, please just make it play one hand. Since any "want to play again?" input is not standardized, Tamarin is not smart enough to handle it properly. (If you already did a loop, it's fine--your grade for that part be corrected by your human grader/TA.)
D:\TA\grading\A17>java ZtomaszeA17 --VIDEO POKER-- You have bet 1 token. This game follows standard 5-card draw poker rules. Make the best poker hand to earn the highest payout! Your current hand: 4S 8D 9H JC AD 1 2 3 4 5 You may discard up to 3 cards to draw the same number of new cards. Enter the index of a card you wish to discard (or 0 to stop): 8D You must enter an integer between 0 and 5. Please try again. Enter the index of a card you wish to discard (or 0 to stop): 2 Enter the index of a card you wish to discard (or 0 to stop): 2 You already selected that card to discard. Please choose a different card or enter 0 to stop discarding. Enter the index of a card you wish to discard (or 0 to stop): 1 Enter the index of a card you wish to discard (or 0 to stop): 9 You must enter an integer between 0 and 5. Please try again. Enter the index of a card you wish to discard (or 0 to stop): 3 You discard : 8 of Diamonds, 4 of Spades, 9 of Hearts. Your final hand: 4D JC QH AD AH You have a pair. You win 1 token. D:\TA\grading\A17>java ZtomaszeA17 --VIDEO POKER-- You have bet 1 token. This game follows standard 5-card draw poker rules. Make the best poker hand to earn the highest payout! Your current hand: 5S 6D 9C JC QD 1 2 3 4 5 You may discard up to 3 cards to draw the same number of new cards. Enter the index of a card you wish to discard (or 0 to stop): 0 You discard no cards. Your final hand: 5S 6D 9C JC QD You have only a high card. You lose. D:\TA\grading\A17>java ZtomaszeA17 --VIDEO POKER-- You have bet 1 token. This game follows standard 5-card draw poker rules. Make the best poker hand to earn the highest payout! Your current hand: 2D 3D 7D 8D AD 1 2 3 4 5 You may discard up to 3 cards to draw the same number of new cards. Enter the index of a card you wish to discard (or 0 to stop): 0 You discard no cards. Your final hand: 2D 3D 7D 8D AD You have a flush. You win 6 tokens. D:\TA\grading\A17>java ZtomaszeA17 --VIDEO POKER-- You have bet 1 token. This game follows standard 5-card draw poker rules. Make the best poker hand to earn the highest payout! Your current hand: 7D JD JC KH AD 1 2 3 4 5 You may discard up to 3 cards to draw the same number of new cards. Enter the index of a card you wish to discard (or 0 to stop): 1 Enter the index of a card you wish to discard (or 0 to stop): 4 Enter the index of a card you wish to discard (or 0 to stop): 5 You discard : 7 of Diamonds, King of Hearts, Ace of Diamonds. Your final hand: 2D 3C JD JH JC You have three of a kind. You win 3 tokens. D:\TA\grading\A17>java ZtomaszeA17 --VIDEO POKER-- You have bet 1 token. This game follows standard 5-card draw poker rules. Make the best poker hand to earn the highest payout! Your current hand: 2H 6D 9D 9S AD 1 2 3 4 5 You may discard up to 3 cards to draw the same number of new cards. Enter the index of a card you wish to discard (or 0 to stop): 1 Enter the index of a card you wish to discard (or 0 to stop): 4 Enter the index of a card you wish to discard (or 0 to stop): 0 You discard : 2 of Hearts, 9 of Spades. Your final hand: 2D 3D 6D 9D AD You have a flush. You win 6 tokens.
Upload your UsernameA17.java
file to Tamarin. Be sure to include all the classes needed to run your program!
PlayingCard
implements Comparable
compareTo
method should sort cards by value, with Aces high (after Kings).
Clarification (10 Apr 2010): It is assumed that your PlayingCard
also meets the requirements of A16, Part 1. In particular, it must have the specified constructor that takes a value and suit (both int
s) and defines public static final int
constants for the suits, named CLUBS
, SPADES
, HEARTS
, and DIAMONDS
.
Deck
ArrayList
ArrayList
somewhere in your code.
PokerHand
toString()
method that returns a String of the cards in sorted order (low to high, by value) (0.8). You have the 9 is???
methods specified above (0.8 each).
Username
A17
PlayingCard
implements Comparable
. If using an array to hold your cards, see java.util.Arrays
. If using an ArrayList, see java.util.Collections
.
is???
method to simply look for the specified poker hand. For example, isPair()
can return true
if it finds two cards with the same value, regardless of whether there are more than 2 cards with that value or what the remaining cards are in the hand.
isStraight()
and isFlush()
return true. However, remember how your methods work. If isPair()
also returns true on 3 of a kind, just calling isPair()
and isThreeOfAKind()
is not going to correctly detect a full house!
PokerHand
object, you are going to need one or more methods to let you later add, remove, or swap certain cards in the hand. (The alternative is to just keep the initial hand in an array or ArrayList until after the user has selected which cards to discard, and only then create a PokerHand
.)
toString()
method working, you can just return false;
from all your is???
methods to get PokerHand
to compile. Then you test it after writing each method to gradually change all the [FAIL]s to [PASS]es.
PokerHand
is worth 9 points, while the main program is only worth 2 points. If pressed for time, apply your attention accordingly.
PokerHand
(though a regular array may be easier); you could change your Deck implementation; you could use an ArrayList just to hold the numbers/indexes entered by the user; or you could find some other use for it.
Integer
wrapper class with the <generics>: ReadingInNumbers.java
Also, here I made HighScore.java (demo from A16) implement Comparable.
The error: In the first example, the discarded cards should be at positions 1, 2, and 3, but in fact cards at positions 1, 3 and 4 were being replaced instead.
The bug: I used an ArrayList
to hold the cards in my PokerHand
. I also put the original 5 cards into the PokerHand
. I correctly remembered to use the set
method so that the ArrayList indexes would not change while I printed and then replaced the necessary cards in a single for
loop. However, since the ArrayList
of cards was private in the PokerHand
class, I had written a public set
method in PokerHand
that just passed the given parameters on to the ArrayList's set
method and then sorted the hand afterwards. My thought when writing this set
method for PokerHand
was that I wanted to guarantee that the cards in the hand were always correctly sorted. But that meant that, when I was replacing cards in the for
loop, the indexes were occassionally changing after all if I replaced an early card with one that cause the others to shift up or down when the hand was sorted after each replacement.
The fix: I stopped sorting the hand each time I set
one of the cards to a new value.
The lesson: Everyone makes mistakes once in a while. :)
draw()
on an empty deck; can you construct an ordered deck; can you shuffle a partial deck; etc. These requirements exist in A16 so that your classes perform correctly in any context; however, you are probably not going to encounter these contexts in A17.
The most important thing is that your PlayingCard
constructor, two accessors, and toString()
methods work correctly for cards in a valid range (1 to 13 values and one of the four suit constants). Also, you need public static int
constants defined for the four suits.
compareTo
?
compareTo
method to sort cards into regular value order first, then worry about how to handle the Aces.
One option is to handle Aces separately in your compareTo code. For example:
if (this.value == ACE || pc.value == ACE) { //have at least one ace, maybe two, to deal with... //if two Aces, the cards are equal; //otherwise, the Ace card is greater than the other card }else { //just sort cards normally }
Alternately, you could consider the fact that you really just want to treat any Ace as having a value of 14 while sorting. You don't want to change the underlying card's value, though. (If you did that, then you'd have an illegal card and it would mess up all the rest of your code that assumes an ACE == 1
!) So use a temporary local variable to hold the value so you can change it if necessary:
leftValue = this.value; if (leftValue == ACE) { leftValue = 14; }Do the same for
rightValue
(which comes from pc.value
), then do your comparison normally using leftValue
and rightValue
.
ArrayList
? I should use it to hold the cards in the PokerHand
, right?
The main advantage of an ArrayList
over an array is when you are constructing a list of unknown length. For example, if you are reading in details from a user or something where you don't know how many elements you'll need before you start, an ArrayList is really handy!
This is not the case with a PokerHand
. In a PokerHand
, you should always have exactly 5 cards. (Well, I suppose you might discard some briefly, but you need to replace them again before doing anything else.)
Since you are probably more comfortable with arrays at this point, my general recommendation would be to use a PlayingCard[]
instance variable to hold your cards in PokerHand
. This way you don't have to wrestle with the new syntax/methods of ArrayList
while writing each of your 9 is???
methods. (Using an ArrayList here would be fine though; and it would certainly give you more practice using one!)
But, if you're not using an ArrayList within PokerHand
, where do you use it? My recommendation is to use an ArrayList<Integer>
in main
to store the card indices entered by the user. That is, they need to enter 0 to 3 numbers, but you don't know in advance just how many they'll enter. (You do know it won't be more than 3, so an array would work here too; but I'd go with an ArrayList.)
Another possibility is to use an ArrayList<PlayingCard>
in main to hold the initial hand. This is because, once you put the 5 cards into a PokerHand
, it may be hard to change those cards. So you could just have an ArrayList of them, sort the list, print them, and ask the user which cards to discard. Once you discard and replace those cards in the ArrayList, construct a new PokerHand with the 5 cards in the list. Then you can use the PokerHand is???
methods to determine what the final hand is.