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:
- playing card
- card deck
- a player's hand
- a game of Blackjack
Each one of these classes is written as a separate .java file, so
you'll be creating four separate files:
- Card.java
- Deck.java
- Hand.java
- BlackJack.java
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:
- The value of a hand is the sum of the values of the cards in the
hand.
- The values of cards are:
- Two through Ten are counted at their face values.
- Jack, Queen and King have a value of 10.
- An Ace has a value of either 1 or 11, at the player's
discretion.
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:
- Enable the Play button (and disable the Hit and Stand buttons).
- When the user presses Play, create a new deck, shuffle it, and
deal hands to the player and the dealer.
- Display the player's hand and the dealer's top card.
- If either the player or the dealer has Blackjack, go ahead to
step 7 to finish the game.
- If neither has Blackjack, enable the Hit and Stand buttons,
and disable the Play button.
- 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:
- The player presses Stand,
- The player busts by exceeding 21, or
- The player hits 21 exactly
Any of these conditions ends the player's turn.
- 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:
- If the player has a bust hand, that hand
is a loser.
- If both players have Blackjack, the game is a push.
- Otherwise, if either the player or the dealer has Blackjack,
that hand is a winner.
- 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.
- 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:
- If the dealer has a bust hand, the dealer loses.
- Otherwise, if the values of the two hands are the same, the
game is a push.
- Otherwise, the winner is the hand with the highest value.
- 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.