This page is part of the Blackjack Lab.

Start file:

Blackjack part 2 uses the same Blackjack.java file as part 1 and involves writing the methods labeled // TODO implement (part 2).

Solutions are at the bottom of this page.

Provided code

Constants

Blackjack contains both public and private constants. The public constants that end in RESULT are returned by the getResult method and are used by the resolveBetsAndReset method. These constants are public so they can be used in Javadoc and so client classes can determine the round result.

The private constants are used throughout Blackjack.

Exceptions

As in part 1, several methods throw exceptions if run out of order. These exceptions are provided.

roundIsOver method

roundIsOver is used to ensure that getResult and resolveBetsAndReset are not run out of sequence. You do not need to edit or call roundIsOver.

Code to be written

reset method and constructor modification

reset resets the appropriate instance variables so that the player can place a new bet. It also resets shoe if enough cards have been used.

The constant SHOE_PENETRATION represents the percentage of cards in the shoe used before resetting the shoe. The constants DECKS and CARDS_PER_DECK allow calculation of the number of cards originally in the shoe.

The reset method duplicates some code from the constructor. The reset method should be called from the constructor to avoid duplicating code.

canHit method

The player can hit if the dealer does not have blackjack and the player’s hand allows another card to be added.

hit method

The hit method adds a card, dealt from shoe, to playersHand.

playDealersHand method

The dealer hits until the dealer’s hand value is at least DEALER_STAND_VALUE (17).

In a single player game, the dealer will not play out their hand if the player has Blackjack or has busted.

getResult method

getResult returns one of the constants ending in RESULT based on the result of the round.

resolveBetsAndReset method

resolveBetsAndReset pays the player any winnings, or returns the player’s bet on a push.

resolveBetsAndReset calls reset to reset for the next round.

Hints

reset method

The Shoe method cardsLeft returns the number of cards remaining in the shoe. The constants DECKS and CARDS_PER_DECK can be multiplied to determine the number of cards originally in the shoe.

canHit method

The BlackjackCard class has methods that check for the desired properties of both the player’s and dealer’s hands.

playDealersHand method

The dealer must play out their hand if the player’s hand value does not exceed BlackjackHand.MAX_HAND_VALUE and the player does not have Blackjack.

getResult method

Blackjack (21 with exactly 2 cards) beats all other hands, including a 21 that is not Blackjack. Blackjack pushes (ties) with Blackjack. Handle all combinations of player and/or dealer Blackjack first.

If the player busts, the player loses.

If the dealer busts (and the player does not), the player wins.

If none of the above occurs, the result is based on the hand values.

resolveBetsAndReset method

The constants ending in RESULT represent all possible results.

When the player pushes, they get their original bet back.

The constants ending in PAYOUT store the payouts as multiples of the player’s original bet. The PAYOUT constant multiples include the player’s original bet.

Solution code

Blackjack.java

The Java file above uses the Shoe class. The automated tester requires the TestShoe class.

Modified constructor and reset method

public Blackjack(double playersMoney)
{
    this.shoe = new Shoe(DECKS);
    this.playersMoney = playersMoney;
    reset();
}

private void reset()
{
    playersHand = null;
    playersBet = 0;
    dealersHand = null;

    if(shoe.cardsLeft() < DECKS * CARDS_PER_DECK * (1 - SHOE_PENETRATION))
        shoe.reset();
}

canHit method

public boolean canHit()
{
    if(playersHand == null)
        throw new IllegalStateException("Player has not yet bet.");
    
    return ! dealersHand.isBlackjack() && playersHand.canAddCard();
}

hit method

public void hit()
{
    if( ! canHit() )
        throw new IllegalStateException("canHit() must be true to hit");
    
    playersHand.addCard(shoe.dealCard());
}

playDealersHand method

public void playDealersHand()
{
    if(playersHand == null)
        throw new IllegalStateException("Player has not yet bet.");
    
    if(playersHand.getNumericalValue() <= BlackjackHand.MAX_HAND_VALUE &&
            ! playersHand.isBlackjack())
    {
        while(dealersHand.getNumericalValue() < DEALER_STAND_VALUE)
            dealersHand.addCard(shoe.dealCard());
    }
}

getResult method

public int getResult()
{
    if ( ! roundIsOver() )
        throw new IllegalStateException("Round is not yet over.");
    
    if(playersHand.isBlackjack() && dealersHand.isBlackjack())
        return PUSH_RESULT;

    if(playersHand.isBlackjack())
        return WIN_BJ_RESULT;

    if(dealersHand.isBlackjack())
        return LOSS_RESULT;
    
    if(playersHand.isBust())
        return LOSS_RESULT;

    if(dealersHand.isBust())
        return WIN_RESULT;

    int playersHandValue = playersHand.getNumericalValue();
    int dealersHandValue = dealersHand.getNumericalValue();
    
    if(playersHandValue > dealersHandValue)
        return WIN_RESULT;

    if(playersHandValue == dealersHandValue)
        return PUSH_RESULT;

    return LOSS_RESULT;
}

resolveBetsAndReset method

public void resolveBetsAndReset()
{
    if ( ! roundIsOver() )
        throw new IllegalStateException("Round is not yet over.");
    
    int result = getResult();
    
    if(result == PUSH_RESULT)
        playersMoney += playersBet;
    else if(result == WIN_RESULT)
        playersMoney += playersBet * WIN_PAYOUT;
    else if(result == WIN_BJ_RESULT)
        playersMoney += playersBet * WIN_BJ_PAYOUT;

    reset();
}

Comments

Comment on Blackjack Lab