Lab 10 -- Blackjack

In this lab, you will write a program which plays the card game of Blackjack.  The program will present a GUI interface (see the screenshots at the bottom of this writeup) which will allow an interactive user to play a game of Blackjack against the computer, which will act as the dealer.

To implement the game, you'll write a group of classes to model important components of the game:
Each one of these classes is written as a separate .java file, so you'll be creating four separate files:
I've provided the class (BlackJackGUI.java) which implements the GUI interface ( lab10.jar ).  You won't need to modify this class at all.  Your code will need to interface with BlackJackGUI's code, so make sure that you follow the specifications carefully.

Rules of the game

The objective of the game is to accumulate the hand with the highest value not exceeding 21.  A hand is evaluated as follows:
A hand with an ace and a 10-point card is a Blackjack, the best possible hand.

Play of the game

The dealer deals two cards to each player and to himself.  (In our case, we will just have one player, the interactive user.)  The dealer shows one of his cards face up, the other is kept face down.

Each player then has the opportunity to request additional cards from the dealer.  The player has the choice of requesting a Hit; that is, an additional card, or to Stand; that is, to finish his turn keeping his hand as it is.

Eventually, the player either busts (i.e., exceeds 21) or stands pat.  A bust is an automatic loss.  If the player stands without busting, the dealer then plays his hand.  The dealer has the same choices (hit or stand) that the other players do, but typical casino rules dictate that the dealer must take hits until the value of his hand reaches 17 or higher, and must stand with a value of 17 or higher.  (An alternative is that the dealer hits on a "soft" 17; that is, one consisting of an ace and a six.)  If the dealer busts, the player wins. Otherwise, the hand with the highest value wins.  If the dealer's hand and the player's hand have the same value, the game is a "push" (a tie game), and the player's bet is returned.  (Note:  A hand with Blackjack beats a hand with a non-Blackjack 21.)


Writing the classes

Next, I'll describe the classes you need to write:

The Card class

The Card class is used to model a playing card.  A Card is defined by two values:  a suit (clubs, diamonds, hearts, or spades) and a rank (ace, two, three, etc.). These can be stored as private integer instance variables using the following codes:

suit
code
clubs
0
diamonds
1
hearts
2
spades
3

rank code
ace
1
two
2
three
3
four
4
five
5
six
6
seven
7
eight
8
nine
9
ten
10
jack
11
queen
12
king
13



Write the following public methods for Card:

1.    Card(int suit, int rank);  A constructor to initialize the suit and rank of a card.

2.    int valueOf();  This method returns the value of the Card in the game of BlackJack.  (Ace=1, Two=2, ... , Ten=10, Jack=10, Queen=10, King=10).

3.    String toString();  This method should return a String representing the Card, in the form

Ace of Hearts
Three of Diamonds
King of Clubs

etc.

Suggestion:  Set up static final arrays of the suit names and rank names.  For example,

private static final String[] suits = { "Clubs", "Diamonds", "Hearts", "Spades" };

A suit name can then be obtained from the suits array by using the suit code as an index.  Ranks can be handled in the same way.

4.   public static void main(String[] args);  For testing only, write a main method which creates two or three cards and writes them to System.out.
 

The Deck class

The Deck class represents a deck of 52 playing cards.  It has one private instance variables:  an ArrayList of Cards.
Deck has the following public methods:

1.    Deck();  A constructor which initializes a deck of playing cards in order by suit and then rank.  The constructor instantiates 52 cards and stores them in its ArrayList, starting with the ace of clubs, two of clubs, three of clubs, ... , king of clubs, ace of diamonds, two of diamonds, etc.

2.    void shuffle();  Shuffles a deck of cards.  Here's one way to shuffle a deck:  Pick any two cards at random, and then swap them in the deck.  By itself, this won't shuffle the cards very much.  So, repeat it, say 1000 times.  The deck should be well shuffled by then.

You can use a Random object to generate random numbers.  Recall that the method nextInt(N) returns a random integer in the range 0..N-1.

3.    boolean hasNextCard();  Returns true if and only if there remain undealt cards in the deck; that is, if the ArrayList is not empty.

4.    Card nextCard();  Returns the next card from the top of the deck.  This can be accomplished by removing the 0th Card from the ArrayList and returning it to the caller.

5.    static void main(String[] args);  For testing purposes, write a main method which creates a deck, shuffles it, and then displays all 52 of its cards, one per line.


The Hand class

In the game of Blackjack, a player is dealt 2 cards initially.  After that, the player may request being "hit" with additional cards.  The objective is to obtain a hand whose value is as close as possible to 21, without going over 21.  (A hand with a value greater than 21 is a "bust", and automatically loses the game.)

To model a Blackjack hand, you can use an ArrayList (declared as a private instance variable) to store the cards held in the hand.  Then write the following methods:

1.    Hand();  A constructor to initialize an empty Hand.

2.    void add(Card card);  Add a Card to the Hand.  This method can just call the add method of the Hand's ArrayList.

3.    Card getTopCard();  Returns the first Card in the Hand; that is, the 0th Card.

4.    int valueOf();  Compute the value of the Hand.  The value of the Hand is the sum of the values of the cards in the Hand.  An ace can be counted as 1 or 11.  You should count an ace as 11, unless that would cause the value of the Hand to exceed 21; in that case, count the ace as 1.

5.    boolean hasBlackJack();  A Hand has BlackJack if it contains an ace and a 10-point card; that is, it is a two-card hand with a value of 21.

6.    boolean isBusted();  A Hand is busted if its value exceeds 21.

7.    String toString();  Return a string showing the contents of the Hand.  The String should consist of the String representation of each Card in the Hand, separated by newline characters.  If the Hand has BlackJack,  append the word "BlackJack" to the String.  If the Hand is a bust, append the word "Bust" to the String.  For example,

"Ten of Clubs\nFive of Clubs\nNine of Hearts\n\nBust", which would appear as

Ten of Clubs
Five of Clubs
Nine of Hearts

Bust

7.    public static void main(String[] args);  Write a main method (for testing purposes) which creates a Deck, shuffles it, deals a Hand of three cards from it, and then displays the Hand and its value.


The BlackJackGUI class

I am providing the BlackJackGUI class, which provides a GUI JFrame for the application.  During a game, the GUI looks like this:

 

The frame contains two text areas (JTextArea) and three buttons (JButton).  The left text area is used to display the player's hand and its value.  The right text area is for the dealer's hand.  During play, only one of the dealer's two cards is visible to the player.  When the game is finished, the dealer's hand and its value are displayed in the same format as the one used for the player's hand.

During play, the Play button is disabled.  The Hit and Stand buttons are enabled, allowing the user to choose an avenue of play.

At the end of a game, the GUI looks like this:

 

The left text area displays the player's hand; the right text area displays the dealer's hand.  The text areas also display the value of each hand.  The outcome of the game (Win, Lose, or Push) is displayed in the player's text area.

The Play button is enabled when the program is started and when a game is completed, and allows the user to start a new game.  The Hit and Stand buttons are disabled.

The BlackJackGUI class provides the following public methods which can be called by the BlackJack class:

void displayPlayer(Hand hand);  // Display the player's hand in the player text area.  Call this method whenever there is a change in the player's hand.

void displayDealer(Hand hand);  // Display the dealer's hand in the dealer text area.  Call this method when a game is finished.

void displayDealerCard(Card card);  // Display the dealer's up card in the dealer text area.  Call this method at the beginning of a game.

void displayOutcome(String outcome);  // Appends the given outcome string to the player text area.  Call this method at the end of a game.

void enableHitAndStandButtons();  // Enables Hit and Stand and disables Play.  Call this method when it is the player's turn to play.

void enablePlayButton();  // Enables Play and disables Hit and Stand.  Call this method at the end of a game.

The BlackJackGUI class also has a public main method which creates an instance of the GUI and displays it on the screen.  However, its buttons are not connected to any actions.


The BlackJack class

The BlackJack class contains the logic for playing a game of Blackjack.  The class has instance variables to reference the frame (class BlackJackGUI), the card deck (class Deck), and the player's and dealer's hands (class Hand).

The basic logic that should be followed is:
  1. Enable the Play button (and disable the Hit and Stand buttons).
  2. When the user presses Play, create a new deck, shuffle it, and deal hands to the player and the dealer.
  3. Display the player's hand and the dealer's top card.
  4. If either the player or the dealer has Blackjack, go ahead to step 7 to finish the game.
  5. If neither has Blackjack, enable the Hit and Stand buttons, and disable the Play button.
  6. If the player wants a Hit, deal another card from the deck to the player.  Continue responding to Hit requests until one of the following occurs: Any of these conditions ends the player's turn.
  7. If either the player or the dealer has Blackjack, or if the player has busted, the outcome of the game can be determined as follows:
  8. If the game is not over, the dealer then plays.  Hit the dealer with additional cards until the dealer busts or until the dealer's hand has a value of 17 or higher. The game is now finished.
  9. When the game is finished, compare the value of the player's hand with that of the dealer.  Determine a winner with the following rules:
  10. Display Win, Lose, or Push in the player's text area.  Then go back to step 1.
Note:  Although this is the sequence of operations that the program will follow, you won't write this sequence of operations anywhere.  This is because the entire program is event driven; that is, all of these operations are triggered by mouse presses by the user on the Play, Hit, and Stand buttons.  In response to a button press, the program should carry out all the actions it can, until the next press.

The game logic can be written into the "actionPerformed" methods of the ActionListeners which correspond to the three GUI buttons.  Write the following three classes within BlackJack, using the same syntax you used in the image lab (lab 7).

class PlayAction contains the actions to be taken when the Play button is pressed.
class HitAction contains the actions to be taken when the Hit button is pressed.
class StandAction contains the actions to be taken when the Stand button is pressed.

In addition write a method

private void finishGame();

This method plays the dealer's hand (if necessary), determines the winner, and displays the outcome of the game.  Depending on how the game progresses, this method may be called from play, hit, or stand.

the main method

The main method of the BlackJack class is the main method of the entire application.  All it does is to create an instance of the BlackJack class.

the BlackJack constructor

You'll also need to write a constructor for the BlackJack class.  Its function is to create and initialize a BlackJackGUI.  Instantiate the GUI with the new operator, and then call its methods setPlayAction, setHitAction, and setStandAction, in order to connect the GUI buttons with the appropriate ActionListeners.  Then enable the play button and let the game begin!

Some enhancements (optional)

Here are some enhancements to the game that you can try to implement:

1.    Allow for more players.  You can set up an array of players, rather than just having a single player.  You'll need to modify the user interface, either by adding additional text areas, or by giving each player its own frame.

2.    Betting.  Allow players to bet on the game.  When the game is started, give the player a stake, say $100.  Then allow the player to bet a portion of that stake on the next game.  If the player loses the game, he loses his bet.  If the player wins the game, he gets his bet back, along with winnings equal to the bet amount.  If the game is a push, the player gets the bet back.