Table of Contents
Between Player and
Game, we have a
chicken-and-egg design problem.
In this chapter, we'll describe the design for
Game in detail. However, in order to create the
deliverables, we have to create a version of
Player that we can use just to get started. In
the long run, we'll need to create a sophisticated hierarchy of players.
Rather than digress too far, we'll create a simple player,
Pssenger57 (they always bet on black), which will
be the basis for further design in later chapters.
The RouletteGame's responsibility is to
cycle through the various steps of the game procedure, getting bets
from the player, spinning the wheel and resolving the bets. This is an
active class that makes use of the classes we
have built so far. The hallmark of an active class is longer or more
complex methods. This is distinct from most of the classes we have
considered so far, which have relatively trivial methods that are
little more than getters and setters of instance variables.
The sequence of operations in one round of the game is the following.
Procedure 10.1. A Single Round of Roulette
Place Bets
Notify the Player to create
Bets. The real work of placing bets is
delegated to the Player class. Note that
the money is committed at this point; they player's stake should
be reduced as part of creating a
Bet.
Spin Wheel
Get the next spin of the Wheel,
giving the winning Bin,
w.
Resolve All Bets
For each Bet,
b placed by the
Player:
Winner?
If Bet
b's Outcome is in
the winning Bin,
w, then notify the
Player that Bet
b was a winner and update the
Player's stake.
Loser?
If Bet
b's Outcome is not
in the winning Bin,
w, then notify the
Player that Bet
b was a loser. This allows the
Player to update the betting amount for
the next round.
Matching Algorithm. This class has the responsibility for matching the collection
of Outcomes in the Bin
of the Wheel with the collection of
Outcomes of the Bets
on the Table. We have two collections that
must be matched: Bin and
Table. We'll need to structure a loop or
nested loops to compare individual elements from these two
collections.
We could use a loop to visit each Outcome
in the winning Bin. For each
Outcome, we would then visit each of the
Bets contained by the
Table. A Bet's
Outcome that matches the
Bin's Outcome is a
winner and is paid off. The other bets are losers. This involves two
nested loops: one to visit the winning Outcomes
of a Bin and one to visit the
Bets of a Table.
The alternative is to visit each Bet
contained by the Table. Since the winning
Bin is defined by a
Set, we can exploit set membership
methods to test for presence or absence of an
Bet's Outcome in that
Bin's Set. If
the Bin contains the
Outcome, the Bet is a
winner; otherwise the Bet is a loser. This only
requires a single loop to visit the Bets of a
Table.
Player Interface. The Game collaborates with
Player. We have a “chicken and
egg” problem in decomposing the relationship between these
classes. We note that the Player is really a
complete hierarchy of subclasses, each of which provides a different
betting strategy. For the purposes of making the
Game work, we can develop our unit tests with
a stub for Player that simply places a single
kind of Bet. We'll call this player
“Passenger57” because it always bets on Black. In
several future exercises, we'll revisit this design to make more
sophisticated players.
For some additional design considerations, see the sidebar Additional Design Considerations. This provides some more advanced game options that our current design can be made to support. We'll leave this as an exercise for the more advanced student.