Assignment 17

Task

Write a text-based video poker game.

Textbook: (3.8); 12.5; 7.7; 6.5
Concepts: (wrapper classes); generics; ArrayList; interfaces (Comparable)

Steps

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.

Step 1: 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.

Step 2: 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!)

Step 3: 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:

You may write whatever additional methods you need in this class.

Step 4: Testing 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.

Step 5: 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.)

Sample Output

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.

What to Submit

Upload your UsernameA17.java file to Tamarin. Be sure to include all the classes needed to run your program!

Grading [14 points]

1 - Compiles + Coding Standards
Your program compiles successfully (no errors). Your code follows Java coding standards.
1 - PlayingCard implements Comparable
The 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 ints) and defines public static final int constants for the suits, named CLUBS, SPADES, HEARTS, and DIAMONDS.

0.5 - Deck
You include a Deck and use it to generate the playing cards for your poker hand.
0.5 - ArrayList
You use an ArrayList somewhere in your code.
9 - PokerHand
You have a constructor that takes 5 PlayingCard parameters, building a hand of those cards (1.0). Includes a 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).
2 - UsernameA17
You print out the initial hand and the final hand (0.6). You allow the user to specify 0 to 3 cards to discard/replace using the integers 1 to 5, or 0 to stop entering numbers (0.6). You handle errors of bad input (0.4). You then print the correct payout (0.4).

FAQs

Tips
Something to consider: Video Poker vs Poker
Writing video poker is much easier than writing a regular poker game. For one thing, you don't have to worry about the artificial intelligence (AI) of designing a good betting strategy for the computer player. For another, comparing two hands is much more involved than just determining the type of a single hand. For example, imagine two player each have a pair. To determine the winner, you'd then need to determine (and compare) the value of each of those pairs. Then, on a tie, you'd have to find the high card (not in the pair) of each hand and compare those two values (which could also be a tie, requiring further comparisons).
Is there any demo code?
Here is an example we didn't get to in Section 001 that compares using an array to using an ArrayList. Note the use of the Integer wrapper class with the <generics>: ReadingInNumbers.java

Also, here I made HighScore.java (demo from A16) implement Comparable.

Is Was there a bug in the sample output?
Yes, there was. (Thanks to the student that pointed this out!) It has now been fixed above.

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. :)

My A16 submission wasn't perfect. Isn't that going to cause problems when I reuse those classes here for A17?
Probably not. Most of the things people miss on A16 are the finer requirements, such as: does a card properly get constructed as a Joker if the values given to the constructor are out of range; what happens if you call 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.

Should the Aces be sorted low in the case of a straight?
No. Aces should always be high. (That may not be as elegant, but it's easier to code if you don't have another special case to worry about.)
How do I get the Aces to be sorted high by compareTo?
Get your 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.
Where is the best place to use the ArrayList? I should use it to hold the cards in the PokerHand, right?
Remember that you only need to use an ArrayList once somewhere in your entire program. You can use more than one if you want to, but you only are required to have one.

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.