On-line Guides
All Guides
eBook Store
iOS / Android
Linux for Beginners
Office Productivity
Linux Installation
Linux Security
Linux Utilities
Linux Virtualization
Linux Kernel
Programming
Scripting Languages
Development Tools
Web Development
GUI Toolkits/Desktop
Databases
Mail Systems
openSolaris
Eclipse Documentation
Techotopia.com
Virtuatopia.com

How To Guides
Virtualization
Linux Security
Linux Filesystems
Web Servers
Graphics & Desktop
PC Hardware
Windows
Problem Solutions

## Design Pattern Exercises

### Alternate Counting Strategy

A simple card counting strategy in Blackjack is to score +1 for cards of rank 3 to 7, 0 for cards of rank 2, 8 and 9 and -1 for cards 10 to King and Ace. The updates to the `Card` class hierarchy are shown in the text.

Create a subclass of `CardFactory`, which replaces `newCard` with a version that creates the correct subclass of `Card`, based on the rank.

### Six Reds

A common strategy in Roulette is to wait until six reds in a row are spun and then start betting on only black. There are three player betting states: waiting, counting and betting.

A full simulation will require a `RouletteGame` class to spin the wheel and resolve bets, a `Wheel` object to produce a sequence of random spins, and a `Table` to hold the individual bets. We'd also need a class to represent the `Bet`s. We'll skim over the full game and try to focus on the player and player states.

A `Player` has a stake which is their current pool of money. The `RouletteGame` offers the `Player` an opportunity to bet, and informs the player of the resulting spin of the wheel. The `Player` uses a `SixRedsState` to count reds and bet on black.

The various `SixRedsState` classes have two methods, a `bet` method decides to bet or not bet, and an `outcome` method that records the outcome of the previous spin. Each class implements these methods differently, because each class represents a different state of the player's betting policy.

counting

In the counting state, the player is counting the number of reds in a row. If a red was spun and the count is < 6, add one to a red counter and stay in this state. If a red is spun and the count is = 6, add one to a red counter and transition to the betting state. If black or green is spun, reset the count to zero.

betting

In the betting state, the player is betting on black. In a more advanced version, the player would also increase their bet for each red count over six. If a red was spun, add one to a red counter and stay in the betting state. If black was spun, transition to the counting state. If green was spun, transition to the counting state.

### Caution

We'll focus on the `SixRedsState` design. We won't spend time on the actual betting or payouts. For now, we can simply log wins and losses with a print statement.

First, build a simple `Player` class, that has the following methods.

__init__( self, stake )

Sets the player's initial stake. For now, we won't do much with this. In other player strategies, however, this may influence the betting.

More importantly, this will set the initial betting state of Counting.

__str__( self )

Returns a string that includes the current stake and state information for the player.

getBet( self )

This will use the current state to determine what bet (if any) to place.

outcome( self, spin )

This will provide the color information to the current state. It will also update the player's betting state with a state object returned the current state. Generally, each state will simple return a copy of itself. However, the counting state object will return a betting state object when six reds have been seen in a row.

Second, create a rudimentary `RouletteGame` that looks something like the following.

__init__( self, player )

A `RouletteGame` is given a `Player` instance when it is constructed.

__str__( self )

It's not clear what we'd display. Maybe the player?

play1Round( self )

The `play1Round` method gets a bet from the `Player` object, spins the wheel, and reports the spin back to the `Player` object. A more complete simulation would also resolve the bets, and increase the player's stake with any winnings.

Note that calling the `Player`'s `outcome` method does two things. First, it provides the spin to the player

playRounds( self, rounds=12 )

The `playRounds` is a simple loop that calls `self.` `play1Round` as many times as required.

For guidance on designing the `Wheel` used by the `RouletteGame`, see the section called “Class Variables” and the section called “Function Definition: The def and return Statements”.

State Class Hierarchy. The best approach is to get the essential features of `RouletteGame`, `Wheel` and `Player` to work. Rather than write a complete version of the player's `getBet` and `outcome` methods, we can use simple place-holder methods that simply print out the status information. Once we have these objects collaborating, then the three states can be introduced.

The superclass, `SixRedsState`, as well as the two subclasses, would all be similar to the following.

__init__( self, player )

The superclass initialization saves the player object. Some subclasses will initialize a count to zero.

__str__( self )

The superclass `__str__` method should return a `NotImplemented` value, to indicate that the superclass was used improperly.

getBet( self )

The `getBet` either returns `None` in the waiting and counting states, or returns a bet on red in the betting state. The superclass can return `None`, since that's a handy default behavior.

outcome( self, spin )

The `outcome` method is given a tuple with a number and a color. Based on the rules given above, each subclass of `SixRedsState` will do slightly different things. The superclass can return `NotImplemented`.

We need to create two subclasses of `SixRedState`:

SixRedCounting

In this state, the `getBet` method returns `None`; this behavior is defined by the superclass, so we don't need to implement this method. The `outcome` method checks the spin. If it is Red, this object increments the count by one. If it is black it resets the count to zero. If the count is six, return an instance of `SixRedBetting`. Otherwise, return `self` as the next state.

SixRedBetting

In this state, the `getBet` method returns a bet on Black; for now, this can be the string `"Black"`. The `outcome` method checks the spin. If it is Red, this object increments the count by one and returns `self`. If the spin is black it returns an instance of `SixRedCounting`. This will stop the betting and start counting.

Once we have the various states designed, the `Player` can then be revised to initialize itself with an instance of the wating class, and then delegate the `getBet` request from the game to the state object, and delegate the `outcome` information from the game to the state object.

### Roulette Wheel Alternatives

There are several possible implementations of the basic Roulette wheel. One variation simply uses `random.randrange` to generate numbers in the range of 0 to 37, and treats 37 as double zero. To separate double zero from zero, it's best to use character string results.

Another strategy is to create a sequence of 38 strings ('00', '0', '1', etc.) and use `random.choice` to pick a number from the sequence.

Create a superclass for `WheelStrategy` and two subclasses with these variant algorithms.

Create a class for `Wheel` which uses an instance of `WheelStrategy` to get the basic number. This class for `Wheel` should also determine whether the number is red, black or green. The `Wheel` class `spin` function should return a tuple with the number and the color.

Create a simple test program to create an instance of `Wheel` with an instance of `WheelStrategy`. Collect 1000 spins and print the frequency distribution.

### Shuffling Alternatives

Shuffling rearranges a deck or shoe of multiple decks; there are many possible algorithms. First, you will need a `Card` class to keep basic rank and suit information. Next, you will need a basic `Deck` class to hold cards. See the section called “Playing Cards and Decks” for additional details.

We looked at shuffling in an earlier exercise, but packaged it as part of the `Deck` class, not as a separate strategy. See the section called “Advanced Class Definition Exercises”. We can rework those exercises to separate shuffing from `Deck`.

The `Deck` class must have a `shuffle` function; but this should simply call a method of the shuffle strategy object. Because the `Deck` is a collection of `Card`s, the `Deck` object should be passed to the shuffle strategy. The call would like something like this:

```class Deck( object ):

Other parts of Deck

def shuffle( self ):
self.shuffleStrategy.shuffle( self )
```

Create a superclass for shuffle strategies. Create a subclass for each of the following algorithms:

• For each card position in the deck, exchange it with a card position selected randomly

• For even-numbered card position (positions 0, 2, 4, 6, etc.) exchange it with an odd-numbered card position, selected randomly (random.choice from 1, 3, 5, 7, 9, etc.)

• Swap two randomly-selected positions; do this 52 times

Create a simple test program that creates a `Deck` with each of the available a `Shuffle` strategy objects.

### Shuffling Quality

An open issue in the shuffling exercise is the statistical quality of the shuffling actually performed. Statistical tests of random sequences are subtle, and more advanced than we can cover in this set of exercises. What we want to test is that each card is equally likely to land in each position of the deck.

We can create a dictionary, with the key of each card, and the item associated with that key is a list of positions in which the card occured. We can evaluate a shuffle algorithm as follows.

Procedure 23.1. Test A Shuffle

1. Setup

Create a `Deck`.

Create an empty dictionary, `positions` for recording card positions.

For each `Card` in the `Deck`, insert the `Card` in the `positions` dictionary; the value associated with the `Card` is a unique empty `list` used to record the positions at which this `Card` is found.

2. For Each Strategy. Perform the following evaluation for an instance of each `Shuffle` class, `s`.

1. Create Deck. Set the `Deck`'s current shuffle strategy to `s`.

2. Shuffle. Shuffle the `Deck`.

3. Record Positions. For each card in the deck.

1. Record Position. Locate the `Card`'s position list in the `positions` dictionary; append the position of this `Card` to the list in the `positions` dictionary.

4. Chi-Squared. The chi-squared statistical test can be used to compare the actual frequency histogram to the expected frequency histogram. If you shuffle each deck 520 times, a given card should appear in each of the positions approximately 10 times. Ideally, the distribution is close to flat, but not exactly.

The chi-squared test compares sequence of actual frequencies, a , and a sequence of expected frequencies, e . It returns the chi-squared metric for the comparison of these two sequences. Both sequences must be the same length and represent frequencies in the same order.

Equation 23.1. Chi-Squared

We can use the built-in `zip` function to interleave the two lists, creating a sequence of tuples of ```( actual , expected )```. This sequence of tuples can be used with the multiple-assignment for loop to assign a value from actual to one variable, and a value from expected to another variable. This allows a simple, elegant for statement to drive the basic comparison function.

 Published under the terms of the Open Publication License Design by Interspire