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