Blackjack Game Class¶
The game offers a large number of decisions to a player. This is different from Roulette, where the player’s choices are limited to a list of bets to place.
In Blackjack Game Analysis we’ll look at the game and how the state of play is going to be managed.
In Blackjack Collaboration we’ll look at the various player interactions. In Insurance Collaboration we’ll look at the insurance bet. In Filling the Hands we’ll look at the hit vs. stand decision. There are some additional decisions – like splitting – which require more interaction. We’ll look at this in Hand-Specific Decisions.
We’d like to segregate dealer rules from the rest of the game. This allows us to alter how a dealer fills their hand without breaking anything else. We’ll look at this in Dealer Rules.
This will require a stub class for a Blackjack Player. We’ll look at this design in BlackjackPlayer Class.
We’ll tweak the design for Card in order to determine
if insurance should be offered. This covered in Card Rework.
We’ll also revisit the fundamental relationship between Game, Hand and Player. We’ll invert our viewpoint from the Player containing a number of Hands to the Hands sharing a common Player. This is the subject of Hand Rework.
We’ll provide the design for the game in BlackjackGame Class. In Blackjack Game Deliverables we’ll enumerate all of the deliverables.
Blackjack Game Analysis¶
The sequence of operations in the game of Blackjack is quite complex. We can describe the game in either of two modes: as a sequential procedure or as a series of state changes.
- A sequential description means that the state is identified by the step that is next in the sequence. 
- The state change description involves a stream of events that change the sateof the game. We used this type of approach to describe Craps, see Craps Game Overview. 
Additionally, we need to look at the various collaborations of the Game. We also need to address the question of handling the dealer’s rules.
Maintaining State. The sequential description of state, where the current state is defined by the step that is next, is the default description of state in many programming languages. While it seems obvious beyond repeating, it is important to note that each statement in a method changes the state of the application; either by changing state of the object that contains the method, or invoking methods of other, collaborating objects. In the case of an active class, this description of state as next statement is adequate. In the case of a passive class, this description of state doesn’t work out well because passive classes have their state changed by collaborating objects. For passive objects, instance variables and state objects are a useful way to track state changes.
In the case of Roulette, the cycle of betting and the game procedure were a simple sequence of actions. In the case of Craps, however, the game was only loosely tied to each the cycle of betting and throwing the dice. For Craps, the game state a passive part of the cycle of play. In the case of Blackjack, the cycle of betting and game procedure seem more like Roulette.
Most of a game of Blackjack is sequential in nature: the initial
offers of even money, insurance and splitting the hands are optional
steps that happen in a defined order. When filling the player’s Hand instances,
there are some minor sub-states and state changes. When all
of the player’s Hand instances are bust or standing pat, the dealer
fills their hand.  Finally,  the hands are  resolved with no more player
intervention.  There is a sequence to these steps that doesn’t seem
to benefit from the :strong:State design pattern.
Most of the game appears to be a sequence of offers from the
Game instance to the BlackjackPlayer instance; these are offers
to place bets, or accept cards, or a combination of the two, for each of
the player’s Hand instances.
Blackjack Collaboration¶
In Craps and Roulette, the Player object was the primary
collaborator with the game. In Blackjack, however, focus shifts from the Player intance
to the individual Hand objects. This changes the responsibilities of a BlackjackPlayer:
the Hand object can delegate certain offers to the BlackjackPlayer instance
for a response. The BlackjackPlayer object become a plug-in
strategy to the Hand instances, providing responses to offers of
insurance, even money, splitting, doubling-down, hitting and standing
pat. The BlackjackPlayer object’s response will change the states
of the the various Hand instances in play. Some state changes involve getting a card,
and others involve placing a bet, and some involve a combination of the two.
Most of the time, there is a one-to-one relationship between the BlackjackPlayer instance
and the Hand instance in play. This changes where there is a split
and multiple Hand instances are shared by a single BlackjackPlayer instance.
We’ll use the procedure definition in A Walkthrough.
Following this procedure, we see the following methods that a Hand object
and a BlackjackPlayer object will need to respond to. These are the various
offers from the BlackjackGame class. The first portion of the
game involves the BlackjackPlayer object responding, the second portion
invovles one or more Hand instances responding.
The collaboration is so intensive, it seems helpful to depict it in a swimlane table.
This table shows the operations each object must perform.
This will allow us to expand on the responsibiltiies of the Hand
and BlackjackTable clases as well as define the interface for BlackjackPlayer class.
| BlackjackGame class | Hand class | BlackjackPlayer class | BlackjackTable class | 
|---|---|---|---|
| calls BlackjackPlayer placeBet | creates empty Hand, creates initial Ante Bet | accepts the ante bet, associates with the Hand | |
| gets the initial Hand; deal 2 cards to Hand | add cards | returns the initial Hand | |
| deal 2 cards to dealer’s Hand | add cards | ||
| gets up card from dealer’s Hand; if this card requires insurance, do the insurance procedure | return up card | ||
| iterate through all Hand instances; is the given Hand splittable? | return true if two cards of the same rank | returns a list iterator | |
| if the Hand is splittable, offer a split bet | get the BlackjackPlayer response; return it to the game | to split: create a split bet, and an empty Hand; return the new Hand | accept the split bet for the new Hand | 
| if splitting, move card and deal cards; continue looking for split offers | take a card out; add a card | ||
| iterate through all Hand; if the Hand is less than 21, do the fill-hand procedure | returns a list iterator | ||
| while the dealer’s point value is 16 or less, deal another card | return point value of the Hand; add a card | ||
| if the dealer busts, iterate through all Hand instances resolving the ante as a winner | return point value of the Hand | returns a list iterator | resolve bet as winner and remove | 
| if the dealer does not bust, iterate through all Hand instances comparing against the dealer’s points, determining win, loss or push | return point value of the hand | returns a list iterator | resolve bet and remove | 
There are a few common variation in this procedure for play. We’ll set them aside for now, but will visit them in Variant Game Rules.
Insurance Collaboration¶
The insurance procedure involves additional interaction between Game
and the the Player’s initial Hand. The
following is done only if the dealer is showing an ace.
| BlackjackGame class | Hand class | BlackjackPlayer class | BlackjackTable class | 
|---|---|---|---|
| if BlackjackPlayer Hand imstamce is blackjack: offer even money | return true if 2 cards, soft 21 | to accept, return true | |
| if BlackjackPlayer accepted even money offer: change bet, resolve; end of game | update bet; resolve and remove bet | ||
| offer insurance | to accept, create new bet; return true | accept insurance bet | |
| if BlackjackPlayer accepted insurance offer: check dealer’s hand; if blackjack, insurance wins, ante loses, game over; otherwise insurance loses | return point value | resolve and remove bet | 
Filling the Hands¶
The procedure for filling each Hand involves additional
interaction between Game and the the Player’s initial
Hand. An Iterator used for perform the
following procedure for each individual player Hand.
| BlackjackGame class | Hand class | BlackjackPlayer class | BlackjackTable class | 
|---|---|---|---|
| if BlackjackPlayer’s Hand instance is blackjack: resolve ante bet | return true if 2 cards, soft 21 | resolve and remove bet | |
| while points less than 21, offer play options of double or hit; rejecting both offers is a stand. | return point value; pass offers to player | to double, increase the bet for this hand and return true; to hit, return true | update bet | 
| if over 21, the hand is a bust | return point value | resolve the ante as a loss | 
There is some variation in this procedure for filling Hand instances.
The most common variation only allows a double-down when the Hand
has two cards.
Hand-Specific Decisions¶
Some of the offers are directly to the BlackjackPlayer instance,
while others require informing the BlackjackPlayer object which of the
player’s Hand instances is being referenced.
How do we identify a specific hand?
- One choice is to have the - BlackjackGameobject make the offer to the- Handobject. The- Handinstance can pass the offer to the- BlackjackPlayerobject; the- Handincludes a reference to itself.
- An alternative is to have the - BlackjackGameobject make the offer directly to the- BlackjackPlayerobject, including a reference to the relevant- Handinstance.
While the difference is
minor, it seems slightly more sensible for the BlackjackGame object
to make offers directly to the BlackjackPlayer object, including
a reference to the relevant Hand instance.
Dealer Rules¶
In a sense, the dealer can be viewed as a special player. They have a fixed set of rules for hitting and standing. They are not actually offered an insurance bet, nor can they split or double down.
However, the dealer does participate in the hand-filling phase of the game, deciding to hit or stand pat.
The dealer’s rules are quite simple.  Should the Dealer be a
special subclass of the BlackjackPlayer class; one that implements
only the dealer’s rules?
Or, should the Dealer be a feature of the :class:BlackjackGame` class? In this case, the Game would maintain the dealer’s Hand and execute the card-filling algorithm.
Using an subclass of the BlackjackPlayer class is an example
of Very Large Hammer design pattern.  We only want a few
features of the BlackjackPlayer class, why drive a small nail
with a huge hammer?
Refactoring.
To avoid over-engineering these classes, we could refactor the BlackjackPlayer class into
two components.  One component is an object that handles hand-filling, and the other component
is an object that handles betting strategies.
The dealer would only use the hand-filling component of a player.
Mutability. We can look at features that are likely to change. The dealer hand-filling rules seem well-established throughout the industry.
Further, a change to the hand-filling rules of the dealer would change the nature of the game enough that we would be hard-pressed to call in Blackjack. A different hand-filling rule would constitute a new kind of game.
We’re confident, then, that the dealer’s hand can be a feature of the
BlackjackGame class.
BlackjackPlayer Class¶
- 
class BlackjackPlayer¶
- The - BlackjackPlayerclass is a subclass of- Playerthat responds to the various queries and interactions with the game of Blackjack.
Fields¶
Constructors¶
- 
BlackjackPlayer.__init__(self, table: Table) → None¶
- Parameters
- table ( - BlackjackTable) – The table on which bets are placed
 - Uses the superclass to construct a basic - Player. Uses the- newGame()to create an empty List fot the hands.
Methods¶
- 
BlackjackPlayer.placeBets(self) → None¶
- Creates an empty - Handand adds it to the List of- Handinstances.- Creates a new ante Bet. Updates the - Tablewith this- Beton the initial- Hand.
- 
BlackjackPlayer.getFirstHand(self) → None¶
- Returns the initial - Hand. This is used by the pre-split parts of the Blackjack game, where the player only has a single- Hand.
- 
BlackjackPlayer.__iter__(self) → Iterator[Hand]¶
- Returns an iterator over the List of - Handinstances this player is currently holding.
- 
BlackjackPlayer.evenMoney(self, hand: Hand) → bool¶
- Parameters
- hand ( - Hand) – the hand which is offered even money
 - Returns - Trueif this Player accepts the even money offer. The superclass always rejects this offer.
- 
BlackjackPlayer.insurance(self, hand: Hand) → bool¶
- Parameters
- hand ( - Hand) – the hand which is offered insurance
 - Returns - Trueif this Player accepts the insurance offer. In addition to returning true, the Player must also create the Insurance- Betand place it on the- BlackjackTable. The superclass always rejects this offer.
- 
BlackjackPlayer.split(self, hand: Hand) → Hand¶
- Parameters
- hand ( - Hand) – the hand which is offered an opportunity to split
 - If the hand has two cards of the same rank, it can be split. Different players will have different rules for determine if the hand should be split ot not. - If the player’s rules determine that it wil accepting the split offer for the given - Hand,- hand, then the player will- Create a new Ante bet for this hand. 
- Create a new one-card - Handfrom the given- handand return that new hand.
 - If the player’s rules determine that it will not accept the split offer, then - Noneis returned.- If the hand is split, adding cards to each of the resulting hands is the responsibility of the Game. Each hand will be played out independently. 
- 
BlackjackPlayer.doubleDown(self, hand: Hand) → bool¶
- Parameters
- hand ( - Hand) – the hand which is offered an opportunity to double down
 - Returns - Trueif this Player accepts the double offer for this- Hand. The Player must also update the- Betassociated with this- Hand. This superclass always rejects this offer.
- 
BlackjackPlayer.hit(self, hand) → bool¶
- Parameters
- hand ( - Hand) – the hand which is offered an opportunity to hit
 - Returns - Trueif this Player accepts the hit offer for this- Hand. The superclass accepts this offer if the hand is 16 or less, and rejects this offer if the hand is 17 more more. This mimics the dealer’s rules.- Failing to hit and failing to double down means the player is standing pat. 
- 
BlackjackPlayer.__str__(self) → str¶
- Displays the current state of the player, and the various hands. 
Card Rework¶
The Card class must provide the :class:BlackjackGame` class some information required to
offer insurance bets.
We’ll need to add an offerInsurance() method on the Card class.
The Card superclass must respond with False.  This means that
the FaceCard subclass can inherit this and also respond with False.
The AceCard subclass, however, must respond with True to
this method.
Hand Rework¶
The Hand class should retain some additional hand-specific information.
Since some games allow resplitting of split hands, it’s helpful to
record whether or not a player has declined or accepted the offer of a split.
Fields¶
- 
Hand.player¶
- Holds a reference to the - Playerwho owns this hand. Each of the various offers from the- Gameare delegated to the- Player.
- 
Hand.splitDeclined¶
- Set to - Trueif split was declined for a splittable hand. Also set to- Trueif the hand is not splittable. The split procedure will be done when all hands return- Truefor split declined.
BlackjackGame Class¶
- 
class BlackjackGame¶
- BlackjackGameis a subclass of- Gamethat manages the sequence of actions that define the game of Blackjack.- Note that a single cycle of play is one complete Blackjack game from the initial ante to the final resolution of all bets. Shuffling is implied before the first game and performed as needed. 
Fields¶
Constructors¶
- 
BlackjackGame.__init__(self, shoe: Shoe, table: BlackjackTable) → None¶
- Parameters
- shoe ( - Shoe) – The dealer’s shoe, populated with the proper number of decks
- table ( - BlackjackTable) – The table on which bets are placed
 
 - Constructs a new - BlackjackGame, using a given- Shoefor dealing- Cardinstances and a- BlackjackTablefor recording- Betinstances that are associated with specific- Handinstances.
Methods¶
- 
BlackjackGame.cycle(self) → None¶
- A single game of Blackjack. This steps through the following sequence of operations. - Call - BlackjackPlayer.newGame()to reset the player. Call- BlackjackPlayer.getFirstHand()to get the initial, empty- Hand. Call- Hand.add()to deal two cards into the player’s initial hand.
- Reset the dealer’s hand and deal two cards. 
- Call - BlackjackGame.hand.getUpCard()to get the dealer’s up card. If this card returns- Truefor the- Card.offerInsurance(), then use the- insurance()method.- Only an instance fo the subclass - AceCardwill return true for- offerInstance(). All other- Cardclasses will return false.
- Iterate through all - Handinstances, assuring that no hand it splittable, or split has been declined for all hands. If a hand is splittable and split has not previously been declined, call the- Hand’s- split()method.- If the - split()method returns a new hand, deal an additional Card to the original hand and the new split hand.
- Iterate through all - Handinstances calling the- fillHand()method to check for blackjack, deal cards and check for a bust. This loop will finish with the hand either busted or standing pat.
- While the dealer’s hand value is 16 or less, deal another card. This loop will finish with the dealer either busted or standing pat. 
- If the dealer’s hand value is bust, resolve all ante bets as winners. The - OutcomeAnteshould be able to do this evaluation for a given- Handcompared against the dealer’s bust.
- Iterate through all hands with unresolved bets, and compare the hand total against the dealer’s total. The - OutcomeAnteshould be able to handle comparing the player’s hand and dealer’s total to determine the correct odds.
 - Note that there can be some variations to the steps in this cycle. A single, very long method body is a bad design. One of the key places where new functionality can be inserted is the final step determining of winning hands after the player and dealer’s hands have been filled and neither player has gone bust. 
- 
BlackjackGame.insurance(self) → None¶
- Offers even money or insurance for a single game of blackjack. This steps through the following sequence of operations. - Get the player’s - BlackjackPlayer.getFirstHand(). Is it blackjack?- If the player holds blackjack, then call - BlackjackPlayer.evenMoney().- If the even money offer is accepted, then move the ante bet to even money at 1:1. Resolve the bet as a winner. The bet will be removed, and the game will be over. 
- Call - BlackjackPlayer.insurance(). If insurance declined, this method is done.
- If insurance was accepted by the player, then check the dealer’s hand. Is it blackjack? - If the dealer hold blackjack, the insurance bet is resolved as a winner, and the ante is a loser; the bets are removed and the game will be over. - If the dealer does not have blackjack, the insurance bet is resolved as a loser, and the ante remains. - If insurance was declined by the player, nothing is done. 
 
- 
BlackjackGame.fillHand(self, hand: Hand) → None¶
- Parameters
- hand (Hand) – the hand which is being filled 
 - Fills one of the player’s hands in a single game of Blackjack. This steps through the following sequence of operations. - While points are less than 21, call - BlackjackPlayer.doubleDown()to offer doubling down. If accepted, deal one card, filling is done.- If double down is declined, call - BlackjackPlayer.hit()to offer a hit. If accepted, deal one card. If both double down and hit are declined, filling is done, the player is standing pat.
- If the points are over 21, the hand is bust, and is immediately resolved as a loser. The game is over. 
 
- 
BlackjackGame.__str__(self) → str¶
- Displays the current state of the game, including the player, and the various hands. 
Blackjack Game Deliverables¶
There are eight deliverables for this exercise.
- The stub - BlackjackPlayerclass.
- A class which performs a unit test of the - BlackjackPlayerclass. Since this player will mimic the dealer, hitting a 16 and standing on a 17, the unit test can provide a variety of- Hands and confirm which offers are accepted and rejected.
- The revised - Handclass.
- A class which performs a unit tests of the - Handclass. The unit test should create several instances of- Card,- FaceCardand- AceCard, and add these to instances of- Hand, to create various point totals. Since this version of- Handinteracts with a- BlackjackPlayer, additional offers of split, double, and hit can be made to the- Hand.
- The revised - Cardclass.
- Revised unit tests to exercise the - Card.offerInsurance()method.
- The revised - BlackjackGameclass.
- A class which performs a unit tests of the - BlackjackGameclass. The unit test will have to create a- Shoeinstance that produces cards in a known sequence, as well as- BlackjackPlayer. The- cycle()method, as described in the design, is too complex for unit testing, and needs to be decomposed into a number of simpler procedures.
Looking Forward¶
We have all of the components in place to start looking at player strategies. The player has a number of decisions during the game, plus a betting strategy decision based on the outcome of each game. We’ll set the betting aside for a moment and focus on the Blackjack rules. In the next chapter, we’ll build a simple player that is able to work with the game and table.
