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

BlackjackHand.java

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() + ")";
}

Comments

Comment on Blackjack Lab