您的位置:首页 > 其它

OOD - blackjack

2016-03-20 23:37 176 查看


Blackjack - a real world OOD example

Dan
Fontanesi, 18 Jul 2007





4.87 (73 votes)
Rate this:vote
1vote
2vote
3vote
4vote
5
Learn OOD in .NET by examining a Blackjack game

Download source files - 839 Kb

Download demo files - 953 Kb

Download Blackjack 2005 - 1,083.0 KB




Introduction

When I first posted this application back in 2002, I challenged everyone to improve it and provided a list of enhancements I thought were needed. Nobody took me up on the challenge so I finally got back to adding some of those features myself.

First among those was insurance. Whenever the dealer shows an ace, the players are given the opportunity to buy insurance which usually costs half the original bet. The dealer then looks at his hole card and, if he has Blackjack, you are insured and lose nothing.
If he does not have Blackjack, you lose your insurance bet and play continues as usual. This feature was missing from the original game and if the dealer had blackjack, you just lost immediately. Of course, if the dealer has an ace in the hole, you'll still
lose immediately...sorry, that's the rules.

Then I found an article called AquaButton (see Readme.doc for credits) which subclassed the button control and made it glow when it was the default button. I thought this would be cool if the button for the 'correct' move glowed to show the user what to do.
But I also wanted my button to be able to take images so I wrote my own version of the button. Feel free to use this button on its own in your applications.

If you snooped at the code carefully, you would have noticed that there was a 'Draw' method in the Strategy class that was never used. This method could create a graph of the correct moves. Anyone who's been to Vegas has probably seen one of these; They even
hand them out right at the tables and it is legal to refer to it during play. My version is available by right-clicking on the playing field and selecting the 'Strategy Window' option from the popup menu. You'll notice that the graph changes for each player
depending on the strategy chosen. And if the player is using the High-Low strategy, the graph can change depending on the card count (High-Low is the only strategy that does this).

Player controls have been moved to a popup menu because I added so many that the little form window became unmanageable. Right-click on each player circle to get player-specific settings. Right-click anywhere else to get general settings like the strategy window.

Initial player setup has been moved from the code to the app.config file so you can set the initial number of players, methods and strategies

The code has also been cleaned up a lot. I first wrote this game to learn .NET windows forms programming (I did mostly web stuff then). And since I was learning, I tried to use every feature and nuance just to see how it worked. A lot of that stuff wasn't really
needed and made the code more difficult to figure out and maintain. So I've streamlined it quite a bit.

Here is the original article:

When programmers start creating object oriented designs, several questions pop up consistently:

How do I know what objects to create?

What properties should my objects have?

What methods do I need to create?

How do I know when to overload an operator?

How do I structure my classes for inheritance?

Etc.


The Objects

Let's take a look at a real world example and a fun one as well. The game Blackjack lends itself well to object oriented design because it has physical objects that can be modeled in object-oriented code, i.e. players, a dealer, cards, etc.

These objects have relationships to one another as well. Players have hands that have cards. The dealer also has a hand that has cards. And there's a shoe from which the cards are dealt into the hands.

Hide Copy Code
public class Player
public class Dealer
public class Hand
public class Card
// A shoe is just many decks of cards, usually 6 in Las Vegas
public class Shoe


For our Blackjack game, we're going to have computer-controlled players as well as human ones. For that, we'll have to have a strategy that the computer players use. So we can create another object, albeit not a physical one, called
Strategy
that
takes some input and gives advice on what move to make. The
Strategy
object is going to belong to the
Player
objects
and each player will need an array of
Hand
objects (players can split pairs so they may have more than one
hand).

Hide Copy Code
public class Player
{
private Strategy plyrStrategy;
private Hand[] hands;
_


A hand is just an array of
Card
objects:

Hide Copy Code
public class Hand
{
private Card[] cards;
_


A shoe is also just an array of
Card
objects:

Hide Copy Code
public class Shoe
{
private Card[] cards;
…


Now when we deal the cards, we just go around the table taking cards from the
Shoe
object and adding them
to the
Hand
objects for each of the players and the dealer.

Hide Copy Code
for( int k=0; k<2; k++ )
{
foreach( Player player in players )
{
player.GetHands()[0].Add( shoe.Next() );
}
dealer.Hand.Add(shoe.Next() );
}


Inheriting Interfaces

When a player splits a pair of aces, each ace receives only one more card:

Hide Copy Code
if( CurrentPlayer.CurrentHand[0].FaceValue  == Card.CardType.Ace )
{
NextCard();
NextHand();
NextPlayer();
}


Nice code huh? Well that's because there is a lot of supporting code underneath this, particularly to implement the line:

Hide Copy Code
if( CurrentPlayer.CurrentHand[0].FaceValue == Card.CardType.Ace )


How does the compiler know what
CurrentHand[0]
means? To use this kind of syntax, we must implement the
IList
interface.
This is the same interface used by the
ArrayList
class and others that you might be familiar with. This
is easily done by changing our class declaration slightly:

Hide Copy Code
public class Hand : IList


Now there's a little more work to do. When you inherit an interface, you must provide the implementation for all the methods of that interface. For
IList
,
we need to add:

Hide Copy Code
IsFixedSize
IsReadOnly
Add
Clear
Contains
IndexOf
Insert
Remove
RemoveAt


But the most important method to implement is called
Item
and it looks like this:

Hide Copy Code
Object IList.this[int index]
{
get { return cards[index]; }
set { cards[index] = (Card)value; }
}


This allows us to use array syntax like
CurrentHand[0]
which really means nothing until we tell the compiler
that this means the card at position 0 in the array of cards in the hand. Without implementing
IList
, we
would probably have to write something like
CurrentHand.GetCard(0)
which isn't nearly as cool!


What methods do I create?

Notice that the players and the dealer are responsible for drawing their own hands. This makes it convenient to add code to the form's
Paint
event
like this:

Hide Copy Code
dealer.DrawHand( drawingSurface, showDealerDownCard );
foreach( Player player in players
{
player.DrawHands( drawingSurface );
}


The players and dealer then loop through each hand, asking the cards to draw themselves:

Hide Copy Code
foreach( Hand hand in hands )
{
foreach( Card card in hand )
{
card.Draw( drawingSurface );
}
}


Sometimes it's easier to envision the code you would like to write and then model your objects to allow it.


Summary

Going back to the design of the objects, you might be wondering why the
Dealer
and the
Player
objects
don't inherit from some common object. Well, you could do that. But I felt the dealer and the players didn't have enough in common to justify it. The dealer can only have one hand, has no bank, no bet, no strategy, no card counting. This will have to be a
judgment call on your part and that's why they pay you the big bucks.

You might also wonder where the
Deck
object is. Shouldn't the
Shoe
be
composed of many
Deck
objects which are composed of many
Card
objects?
That may be the case in the real world, but this is an example of where the real world and OOD might better part ways. A
Deck
object
would have just introduced an unneeded layer of complexity. The shoe is easier to implement as an array of cards, though it must be a multiple of the number of cards in a deck (52).

Take a look at the code for this article. This is a full-featured Blackjack game with strategies and graphics and even card counting. But don't let it intimidate you. It really just boils down to the few objects outlined above with a lot of fancy code added
to make the game more appealing.

Have fun with this game. Take a look at the Readme.doc file for ideas on how you could improve this application.


License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: