This page is part of the Blackjack Lab.
A BlackjackHand
represents a player’s or dealer’s hand. Responsibilities include returning the numeric value, determining if another card can be added, and returning calculated information (ex: isBlackjack
, isBust
).
Start files:
Solutions are at the bottom of this page.
Provided code
Constants
The public
constant MAX_HAND_VALUE
represents the maximum value that a Blackjack hand can have without busting (21
). The constant is public because it is intended for use both inside and outside BlackjackHand
.
The private
constants ADDITIONAL_ACE_VALUE
and NUM_CARDS_FOR_BLACKJACK
are intended for use only inside BlackjackHand
. Depending on your algorithm for getNumericalValue
, you may or may not use ADDITIONAL_ACE_VALUE
.
Instance variable
A Blackjack hand consists of at least 2, and often more cards. The ArrayList<BlackjackCard> cards
stores the cards.
BlackjackHand
constructor
A Blackjack hand starts with 2 cards. The constructor accepts the 2 cards as parameters. The constructor initializes the cards
list and adds the parameters to it.
It is very common for students to miss the first line of the constructor (cards = new ArrayList<BlackjackCard>();
). A constructor should initialize each instance variable. Adding values to a list is not the same as initializing the variable to point to a new list object.
addCard
method
addCard
throws an IllegalStateException
if the hand cannot accept another card. As in the BlackjackCard
constructor, throwing an exception when a method is called incorrectly makes errors in client code easier to identify.
When called with a valid state, addCard
adds card
to cards
.
getCards
method
getCards
returns a shallow copy of cards
. Returning a copy ensures that changes to the returned list do not affect the list to which the instance variable cards
refers.
A shallow copy of a list copies only the references to the objects. The objects themselves are not copied. See the Arrays of objects exercises for more on shallow vs deep copies. The examples use arrays; however, the functionality is the same for ArrayList
objects.
BlackjackCard
objects are immutable, so the shallow copy is sufficient.
getNumCards
method
Like the BlackjackCard
method isAce
, getNumCards
exists to make client code cleaner.
Client code could write:
playersHand.getCards().size()
or:
playersHand.getNumCards()
Code to be written
getNumericalValue
method
The value of a Blackjack hand is determined by the values of the cards in it. The BlackjackCard
method getNumericalValue
returns the correct value of every numbered card (the numbered value) and all face cards (10
).
Handling aces makes getNumericalValue
the most challenging method of BlackjackHand
. The BlackjackCard
method getNumericalValue
returns 1
for an ace. The BlackjackHand
method getNumericalValue
must account for any number of aces (0, 1, or more). Each ace counts as either 11
or 1
depending on what would make the better hand.
The test code extensively tests getNumericalValue
. Refer to the test code for example hands without and with aces and their values.
canAddCard
method
A card can be added to a Blackjack hand if the value is less than MAX_HAND_VALUE
(21
).
isBlackjack
and isBust
methods
The hand Blackjack is 21 on the first 2 cards (an ace and a 10 valued card).
(Supporting splitting is an extension to this lab. A 21 obtained with 2 cards after splitting is not a Blackjack.)
A hand is a bust if the value exceeds MAX_HAND_VALUE
(21
).
toString
method
toString
returns a string representation. Examples are provided in the Javadoc and in the test code.
Hints
getNumericalValue
method
The BlackjackCard
method getNumericalValue
returns 1
for an ace. It is not possible to have more than 1 ace in a hand that each count as 11. Count each ace as 1. Consider when the value ADDITIONAL_ACE_VALUE
(10
) should be added to the total.
toString
method
The BlackjackCard
method toString
returns the string representation for a single card. The BlackjackHand
method getNumericalValue
returns the hand’s value.
Solution code
getNumericalValue
method
public int getNumericalValue()
{
boolean containsAce = false;
int value = 0;
for (BlackjackCard card : cards)
{
value += card.getNumericalValue();
if (card.isAce())
containsAce = true;
}
if (containsAce &&
value + ADDITIONAL_ACE_VALUE <= MAX_HAND_VALUE)
value += ADDITIONAL_ACE_VALUE;
return value;
}
Each ace is counted as 1
during the traversal of cards
. The variable containsAce
starts as false
and is set to true
if at least 1 ace is in the hand. (The number of aces in the hand doesn’t matter.)
If the hand contains at least 1 ace and adding ADDITIONAL_ACE_VALUE
would help, ADDITIONAL_ACE_VALUE
is added. Adding ADDITIONAL_ACE_VALUE
would help if doing so would not cause the value to exceed MAX_HAND_VALUE
.
An enhanced for loop is appropriate here, though not required. See Enhanced for loop exercises for additional details.
canAddCard
method
public boolean canAddCard()
{
return getNumericalValue() < MAX_HAND_VALUE;
}
isBlackjack
and isBust
methods
public boolean isBlackjack()
{
return cards.size() == NUM_CARDS_FOR_BLACKJACK &&
getNumericalValue() == MAX_HAND_VALUE;
}
public boolean isBust()
{
return getNumericalValue() > MAX_HAND_VALUE;
}
toString
method
public String toString()
{
String result = "";
for (BlackjackCard card : cards)
result += card.toString() + " ";
return result + "(" + getNumericalValue() + ")";
}