Click here to Skip to main content
15,860,859 members
Articles / Programming Languages / C#
Article

Blackjack - a real world OOD example

Rate me:
Please Sign up or sign in to vote.
4.87/5 (47 votes)
18 Jul 20076 min read 235.4K   9.6K   153   27
Learn OOD in .NET by examining a Blackjack game

Image 1

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.

C#
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).

C#
public class Player
{
    private Strategy plyrStrategy;
    private Hand[] hands;
    _

A hand is just an array of Card objects:

C#
public class Hand
{
    private Card[] cards;
    _

A shoe is also just an array of Card objects:

C#
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.

C#
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:

C#
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:

C#
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:

C#
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:

C#
IsFixedSize
IsReadOnly
Add
Clear
Contains
IndexOf
Insert
Remove
RemoveAt

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

C#
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:

C#
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:

C#
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.

A list of licenses authors might use can be found here


Written By
Web Developer
United States United States
I'm a software engineer and consultant working in San Diego, California. I began using .NET during the early alpha releases since I worked for a Microsoft subsidiary then, and now I've focused my career on .NET technologies.

There are a lot of .NET sites out there now, but The Code Project is still top of the heap.

Comments and Discussions

 
SuggestionBlackjack Sample Project for Visual Studio (C#) Pin
NavinBiz27-Dec-13 1:07
NavinBiz27-Dec-13 1:07 
QuestionThis is awesome. Pin
JoeMoralli4-Jul-11 4:56
JoeMoralli4-Jul-11 4:56 
Generalproblem, suggestions Pin
spneumann2-Jan-11 7:02
spneumann2-Jan-11 7:02 
GeneralExcellent example! Pin
carl engerer6-Jul-09 0:43
carl engerer6-Jul-09 0:43 
News*** Important bug fix that corrects the running count *** Pin
troyf_satx9-Nov-08 11:35
troyf_satx9-Nov-08 11:35 
GeneralWill not compile Pin
drdavef21-Jul-08 5:10
drdavef21-Jul-08 5:10 
GeneralExtremely impressed Pin
Johnny J.24-Jul-07 21:17
professionalJohnny J.24-Jul-07 21:17 
GeneralVery Nice Pin
Paul Conrad19-Jul-07 13:39
professionalPaul Conrad19-Jul-07 13:39 
GeneralNice. Pin
NormDroid18-Jul-07 20:48
professionalNormDroid18-Jul-07 20:48 
GeneralCannot Compile Gives Errors Pin
shanshek113-Feb-07 12:35
shanshek113-Feb-07 12:35 
GeneralRe: Cannot Compile Gives Errors Pin
dantheman23-Feb-07 6:38
dantheman23-Feb-07 6:38 
QuestionRe: Cannot Compile Gives Errors Pin
arotal5-Jul-07 23:01
arotal5-Jul-07 23:01 
GeneralRe: Cannot Compile Gives Errors Pin
Dan Fontanesi18-Jul-07 4:03
Dan Fontanesi18-Jul-07 4:03 
GeneralGreat App Pin
mycoolcode9-Feb-07 6:48
mycoolcode9-Feb-07 6:48 
GeneralGood Job Pin
rroostan1-Sep-06 12:01
rroostan1-Sep-06 12:01 
GeneralGraphics Pin
nlecren5-Aug-04 3:33
nlecren5-Aug-04 3:33 
GeneralRe: Graphics Pin
dantheman10-Sep-04 7:08
dantheman10-Sep-04 7:08 
GeneralGreat App Pin
Scott Elder15-Jun-04 14:46
Scott Elder15-Jun-04 14:46 
GeneralRe: Great App Pin
Dan Fontanesi17-Jun-04 6:58
Dan Fontanesi17-Jun-04 6:58 
GeneralInteresting Pin
Ryan Beesley28-May-03 20:39
Ryan Beesley28-May-03 20:39 
GeneralNice Job! Pin
joan_fl20-May-03 5:44
joan_fl20-May-03 5:44 
GeneralUML Design Patterns Pin
Selena_0119-Dec-02 0:25
sussSelena_0119-Dec-02 0:25 
GeneralRe: UML Design Patterns Pin
Dan Fontanesi19-Dec-02 7:58
Dan Fontanesi19-Dec-02 7:58 
GeneralRe: UML Design Patterns Pin
Anonymous5-May-04 3:36
Anonymous5-May-04 3:36 
GeneralBrillant!! Pin
Anonymous6-Nov-02 5:37
Anonymous6-Nov-02 5:37 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.