CrapsPlayer Class¶
The numerous variations on CrapsPlayer, all of which reflect different
betting strategies, are the heart of this application. In Roulette Game Class,
we roughed out a stub class for Player, and refined it in
Player Class. We will further refine this to create
a definition of the CrapsPlayer class for use in simulating
the complex stateful game of Craps.
In Craps Player Analysis we’ll look at the general responsibilities and collaborators of a player. Since we’ve already examined many features of the game, we can focus on the player and revising the roughed-out version we created earlier.
We’ll present the details of the design in three parts:
CrapsPlayer Design covers the superclass features,
CrapsPlayerPass Subclass covers a subclass which only bets the pass line, and
Craps Martingale Subclass covers a player who uses Martingale betting.
In Craps Player Deliverables we’ll detail the deliverables for this chapter.
Craps Player Analysis¶
We have built enough infrastructure that we can begin to add a variety of players and see how their betting strategies work. Each player has betting algorithm that we will evaluate by looking at the player’s stake to see how much they win, and when they stop playing because they’ve run out of time or gone broke.
As a practical matter, the house edge means players will eventually go broke. It’s mostly a question of how long they can play before they’ve run out of money.
The CrapsPlayer class has the responsibility to create bets and manage
the amount of their stake. To create bets, the player must create legal
bets from known Outcome instances and stay within table limits. To
manage their stake, the player must deduct the price of a bet when it is
created, accept winnings or pushes, report on the current value of the
stake, and leave the table when they are out of money.
We have an interface that was roughed out as part of the design of
the CrapsGame
and CrapsTable classes. In designing the CrapsGame class, we
put a placeBets() method in the CrapsPlayer class to
place all bets. We expected the CrapsPlayer class to create Bet
instances and use the CrapsTable.placeBet() method
to save the individual Bet instances.
In an earlier exercise, we built a stub version of the CrapsPlayer class
in order to test the Game class. See CrapsPlayer Class Stub.
When we finish creating the final superclass, CrapsPlayer,
we will also revise our CrapsPlayerStub to be more
complete, and rerun our unit tests to be sure the expanded
design still handles the basic test cases correctly.
Our objective is to have a new abstract CrapsPlayer class,
with a concrete subclass that follows the Martingale system, using
simple Pass Line bets and behind the line odds bets.
We’ll defer some of the design required to collect detailed measurements
for statistical analysis. In this first release, we’ll simply place
bets. Most of the Simulator class we built for
Roulette should be applicable to Craps without significant modification.
Some Basic Features.
Our basic CrapsPlayer class will place a Pass Line bet and a Pass
Line Odds bet. This requires the player to interact with the CrapsTable
or the CrapsGame class to place bets legally. On a come out roll,
only the Pass Line will be legal. After that, a single Pass Line Odds
bet can be placed. This leads to three betting rules:
Come Out Roll. Condition: No Pass Line Bet is currently placed and only the Pass Line bet is legal. Action: Place a Pass Line bet.
First Point Roll. Condition: No odds bets is currently placed and odds bets are legal. Action: Place a Pass Line Odds bet.
Other Point Roll. Condition: An odds bets is currently placed. Action: Do Nothing.
Beyond simply placing Pass Line and Pass Line Odds bets, we can use a
Martingale or a Cancellation betting system to increase the bet on each
loss, and decrease the amount on a win. Since we have two
different bets in play – a single bet created on the come out roll, a
second odds bet if possible – the simple Martingale system doesn’t work
well. In some casinos, the behind the line odds bet can be double the
pass line bet, or even 10 times the pass line bet, leading to some potentially
complex betting strategies. For example, the CrapsPlayer could apply the Martingale
system only to the odds bet, leaving the pass line bet at the table
minimum. We’ll set this complexity aside for the moment, build a simple
player first.
CrapsPlayer Design¶
The CrapsPlayer class is a subclass of an abstract Player class.
It places bets in Craps. This is also an abstract class, with no actual body for the Player.placeBets()
method. However, this subclass does implement the basic win() and
lose() methods used by all of its subclasses.
Since this is a subclass of a common player definition, we inherit
several useful features. Most of the features of Player are
repeated here. The student should refactor the common code out of
the CrapsPlayer class into the common superclass shared by
the CrapsPlayer and RoulettePlayer classes.
Fields¶
-
CrapsPlayer.stake¶ The player’s current stake. Initialized to the player’s starting budget.
-
CrapsPlayer.roundsToGo¶ The number of rounds left to play. Initialized by the overall simulation control to the maximum number of rounds to play. In Roulette, this is spins. In Craps, this is the number of throws of the dice, which may be a large number of quick games or a small number of long-running games. In Craps, this is the number of cards played, which may be large number of hands or small number of multi-card hands.
-
CrapsPlayer.table The
CrapsTableused to place individualBetinstances.
Constructors¶
-
CrapsPlayer.__init__(self, table: CrapsTable) → None - Parameters
table (
CrapsTable) – The table
Constructs the
CrapsPlayerinstance with a specificCrapsTableobject for placingBetinstances.
Methods¶
-
CrapsPlayer.playing(self) → bool¶ Returns
Truewhile the player is still active. A player with a stake of zero will be inactive. Because of the indefinite duration of a craps game, a player will only become inactive after theirroundsToGois zero and they have no more active bets. This method, then, must check theCrapsTableinstance to see when all the bets are fully resolved. Additionally, the player’s betting rules should stop placing new bets when theroundsToGois zero.
-
CrapsPlayer.placeBets(self) → bool¶ Updates the
CrapsTableinstance with the variousBetinstances.When designing the
CrapsTableclass, we decided that we needed to deduct the price of the bet from the stake when the bet is created. See the Roulette Table Roulette Table Analysis for more information on the timing of this deduction, and the Craps Bet Bet Analysis for more information on the price of a bet.
-
CrapsPlayer.win(self, bet: Bet) → None¶ - Parameters
bet (
Bet) – that was a winner
Notification from the
CrapsGameobject that theBetinstance was a winner. The amount of money won is available viaBet.winAmount().
CrapsPlayerPass Subclass¶
CrapsPlayerPass is a CrapsPlayer who places a
Pass Line bet in Craps.
Craps Martingale Subclass¶
-
class
CrapsMartingale The
CrapsMartingaleclass is a subclass ofCrapsPlayerwho places bets in Craps. This player doubles their Pass Line Odds bet on every loss and resets their Pass Line Odds bet to a base amount on each win.
Fields¶
-
CrapsPlayer.lossCount¶ The number of losses. This is the number of times to double the pass line odds bet.
-
CrapsPlayer.betMultiple¶ The the bet multiplier, based on the number of losses. This starts at 1, and is reset to 1 on each win. It is doubled in each loss. This is always set so that
.
Methods¶
-
CrapsPlayer.placeBets(self) → bool If no Pass Line bet is present, this will update the
Tablewith a bet on the Pass Line at the base bet amount.If no Pass Line Odds bet is present, this will update the
Tableobject with a Pass Line Odds bet. The amount is the base amount times thebetMultiple.Otherwise, this method does not place an additional bet.
-
CrapsPlayer.win(self, bet: Bet) → None - Parameters
bet (Bet) – that was a winner
Uses the superclass
win()method to update the stake with an amount won. This method then resets thelossCountto zero, and resets thebetMultipleto1.
-
CrapsPlayer.lose(self, bet: Bet) → None - Parameters
bet (
Bet) – that was a loser
Increments
lossCountby1and doublesbetMultiple.
Craps Player Deliverables¶
There are six deliverables for this exercise.
The
CrapsPlayerabstract superclass. Since this class doesn’t have a body for theplaceBets()method, it can’t be unit tested directly.A
CrapsPlayerPassclass that is a proper subclass of theCrapsPlayerclass, but simply places bets on Pass Line until the stake is exhausted.A unit test class for the
CrapsPlayerPassclass. This test should synthesize a fixed list ofOutcomeinstances,Throwinstances, and calls aCrapsPlayerPassinstance with various sequences of craps, naturals and points to assure that the pass line bet is made appropriately.The
CrapsMartingalesubclass of theCrapsPlayerclass.A unit test class for the
CrapsMartingaleclass. This test should synthesize a fixed list ofOutcomeinstances,Throwobjects, and calls aCrapsMartingaleinstance with various sequences of craps, naturals and points to assure that the bet doubles appropriately on each loss, and is reset on each win.The unit test class for the
CrapsGameclass should still work with the newCrapsPlayerPassclass. Using a non-random generator for theDiceinstance, this should be able to confirm correct operation of theCrapsGameclass for a number of bets.
Looking Forward¶
Once we have the basics of a player, we can do some design cleanup and refactoring of the code. We have a large number of classes, and there are some areas of overlap and commonality that suggest possible simplifications. In the next chapter we’ll refactor some more of the application class hierarchy.