Craps Solution Overview¶
We will present a survey of the classes gleaned from the general problem statement in Preliminary Survey of Classes. In Preliminary Craps Class Structure we’ll describe some potential class definitions.
Given this survey of the candidate classes, we will then do a walk-through to refine the definitions. We’ll show this in A Walk-Through of Craps. We can use assure ourselves that we have a reasonable architecture. We will make some changes to the preliminary class list, revising and expanding on our survey.
We will also include a number of questions and answers in Craps Solution Questions and Answers. This should help clarify the design presentation and set the stage for the various development exercises in the chapters that follow.
Preliminary Survey of Classes¶
We have divided up the responsibilities to provide a starting point for the development effort. The central principle behind the allocation of responsibility is to encapsulate the information or algorithm into a class. In reading the background information and the problem statement, we noticed a number of nouns that seemed to be important parts of the Craps game.
Dice
Bet
Table
Point
Proposition
Number
Odds
Player
House
The following table summarizes some of the classes and responsibilities that we can identify from the problem statement. This is not the complete list of classes we need to build. As we work through the exercises, we’ll discover additional classes and rework some of these classes more than once.
We also have a legacy of classes available from the Roulette solution. We would like to build on this infrastructure as much as possible.
Preliminary Craps Class Structure¶
- Outcome
Responsibilities
A name for a particular betting opportunity. Most outcomes have fixed odds, but the behind the line odds bets have odds that depend on a point value.
Collaborators
Collected by a
Tableobject into the available bets for thePlayer; used byGameinstance to compute the amount won from the amount that was bet.- Dice
Responsibilities
Selects any winning propositions as well as next state of the game.
Collaborators
Used by the overall
Gameinstance to get a next set of winningOutcomeinstances, as well as change the state of theGameinstance.- Table
Responsibilities
A collection of bets placed on
Outcomeinstances by aPlayer. This isolates the set of possible bets and the management of the amounts currently at risk on each bet. This also serves as the interface between thePlayerand the other elements of the game.Collaborators
Collects the
Outcomeinstances; used byPlayerto place a bet amount on a specificOutcomeobjects; used byGameinstance to compute the amount won from the amount that was bet.- Player
Responsibilities
Places bets on
Outcomeinstances, updates the stake with amounts won and lost. This is the most important responsibility in the application, since we expect to update the algorithms this class uses to place different kinds of bets. Clearly, we need to cleanly encapsulate thePlayerclass, so that changes to this class have no ripple effect in other classes of the application.Collaborators
Uses
Tableobject to placeBetinstances on preferredOutcomeinstances; used byGameobject to record wins and losses.- Game
Responsibilities
Runs the game: gets bets from
Playerobject, throws theDiceobjects, updates the state of the game, collects losing bets, pays winning bets. This encapsulates the basic sequence of play into a single class. The overall statistical analysis is based on playing a finite number of games and seeing the final value of thePlayerobject’s stake.Collaborators
A Walk-through of Craps¶
A good preliminary task is to review these responsibilities to confirm that a complete cycle of play is possible. This will help provide some design details for each class. It will also provide some insight into classes that may be missing from this overview. A good way to structure this task is to do a CRC walk-through. For more information on this technique see A Walk-Through of Roulette.
The basic processing outline is the responsibility of the Game
class. To start, locate the Game card.
Our preliminary note was that this class “Runs the game.” The responsibilities section has a summary of five steps involved in running the game.
The first step is “gets bets from
Player.” Find thePlayercard.Does a
Playerinstance collaborate with aGameinstance to place bets? Note that the game state influences the allowed bets. DoesGameinstance collaborate withPlayerinstance to provide the state information? If not, add this information to one or both cards.The
Gameobject’s second step is to throw theDiceobjects. Is this collaboration on theDicecard?The
Gameobject’s third step is to update the state of the game. While the state appears to be internal to theGameclass, requiring no collaboration, we note that thePlayerinstance needs to know the state, and therefore should collaborate with theGameclass. Be sure this collaboration is documented.The
Gameobject’s fourth and fifth steps are to pay winning bets and collect losing bets. Does theGameinstance collaborate with theTableobject to get the working bets? If not, update the collaborations.
Something we’ll need to consider is the complex relationship between the
dice, the number rolled on the dice, the game state and the various
bets. In Roulette, a Wheel instance picked a random Bin object;
the bin had a simple list of winning Outcome instances.
All Bet instances on other Outcome instances were losers. In Craps,
however, we find that we have game bets that are based on changes to the
game state, not simply the number on the dice. The random outcome is
used to resolve one-roll proposition bets, resolve hardways bets, change
the game state, and resolve game bets. It is not a simple Outcome collection.
We also note that the house moves Come Line (and Don’t Come) bets from
the Come Line to the numbered spaces. In effect, the bet is changed from a generic
Outcome instance to a more specific Outcome instance.
This means that a Bet object has a kind of state change.
The parallels the the Game instance’s
state change and any possible Player instance state change.
Important
Stateful Objects
Many interesting applications involve stateful objects. Everything that has a state or status or attributes that change, is stateful. State changes are almost universally accompanied by rules that determine legal changes, events that precipitate changes, and actions that accompany a state change.
Stateful objects must be taken very seriously. The consequence of ignoring state change complications is software that performs invalid or unexpected state transitions.
A walk-through gives an overview of the interactions among the objects in the working application. You may uncover additional design ideas from this walk-through. The most important outcome of the walk-through is a clear sense of the responsibilities and the collaborations required to create the necessary application behavior.
Craps Solution Questions and Answers¶
Why is the Outcome class distinct? Each object that is an
instance of the Outcome class is merely a number from 2 to 12.
We have complex interdependency between the dice, the game states, the bets and outcomes. An outcome has different meanings in different game states: sometimes a 7 is an immediate winner, other times it as an immediate loser. Clearly, we need to isolate these various rules into separate objects to be sure that we have captured them accurately without any confusion, gaps or conflicts.
We can foresee three general kinds of
Outcomeclasses: the propositions that are resolved by a single throw of the dice, the hardways that are resolved periodically, and the game bets which are resolved when a point is made or missed. Some of the outcomes are only available in certain game states.The alternative is deeply nested if-statements. Multiple objects introduce some additional details in the form of class declarations, but objects have the advantage of clearly isolating responsibilities. Clear, narrow responsibilities makes us more confident that our design will work properly. If-statements only conflate all of the various conditions into a tangle that includes a huge risk of missing an important and rare condition.
See the discussion under Design Decision – Object Identity for more discussion on object identity and why each Outcome is a separate object.
What is the real difference between the classes Dice and Wheel?
Don’t they both represent simple collections with random selection?
Perhaps. At the present time, the distinction appears to be in the initialization. A
Wheelinstance is a collection ofBinobjects. TheDiceobject has 36 outcomes, each with a number of meanings.Generally, we are slow to merge classes together without evidence that they are really the same thing. In this case, they appear very similar, so we will note the similarities and differences as we work through the design details. There is a fine line between putting too many things together and splitting too many things apart.
Generally, the bigger mistake seems to be conflating too many distinct things, and resolving the differences through complex if-statements and other hidden processing logic.