zondag 16 december 2007

CardGames.dll Demystified

Recently I discovered that a lot of people are searching for answers on the mysterious CardGames.dll file, found in the system32 folder of any Windows Vista installation.

As I already suspected, this file acts as a resource container and does not contain or expose functionality to the outside world.

I downloaded a tool called XN Resource Editor to take an extensive look at the contents of CardGames.dll.

First thing I noticed is the root of the resources: It consists of Version information and a folder called DATA. Under DATA the following structure can be found:

  • DATA
    various XML files.

    • Animations
      various XML files describing the animations available.
    • Audio
      XML file describing the various sound files.

      • Sfx
        various WMA sound files.

    • Backgrounds
      XML, JPG and PNG files, combined to backgrounds of the different card games.
    • Decks
      XML and PNG files describing the different decks available.
    • DialogMce
      XML and PNG files for User Interface building.
    • Layouts
      XML files for User Interface layout of different card games.
    • Sheets
      CAB and JPG files with the different decks available.
    • Tips
      XML files with tooltip information and game help.

      • Styles

        • Green
        • Red
        • White

      • Freecell
      • Hearts
      • Solitaire
      • SpiderSolitaire


dinsdag 20 november 2007

Card Masquerade

I've found some interesting resources on the Internet on evaluating Poker hands. I chose to use Cactus Kev's method. He uses a single 32 bit int to store the cards rank bitmap, suit, rank and rank prime number. See the site itself for the surprising details!

I had to adjust the Card class to accomodate for the int though. Luckily we have unit tests in place to quickly review the changes. The exported members have not changed, but the internals have been rewritten to directly write to and read from the int bitmask. This way we can quickly implement the hand evaluator.

I will not tire you with the bitwise operations I do, just download the solution below and take a peek at the Card class. If you think what I do could be done better, feel free and let me know :).

For the hand evaluator itself I have found some articles on combinatorial operations and permutations, for that is exactly what we need. Who said Poker is a simple game?

Download entire solution

zondag 18 november 2007

Dealing The Cards

One of the most important tasks of the dealer is to deal the cards to either the board or the players. Every player gets one card from the dealer and after the first card is dealt to every player at the table, the same procedure is repeated. This way we end up each player having two pocket cards.

Before the flop, turn and river is dealt, a card has to be burned. This means that we remove the top card from the deck. The flop consists of three cards, unlike the turn and the river which are only one card.

What information can we extract from these rules? Obviously, we need to create a Player class and a Board class. Hierarchically the Board and Player classes both have a list of Card classes. The Board class has a list of Player classes. The dealer is the head of the Board class.

Besides that, it should be possible for the Dealer class to burn a card and deal cards in various stages of the hand.

I'll not explain every addition and change, but take some excerpts from the changes. To see every change, download the entire solution below.

First of all, I will show you the cardburning mechanism. It's no complicated matter, just remove the first item in the list:
private void BurnCard()
{
if (cards == null)
{
throw new InvalidOperationException();
}

cards.RemoveAt(0);
}

To make the dealer the head of the board, I have changed the constructor of the Dealer class to accept the Board class. Also I have encorporated an enum for defining the stage of the hand in de Dealer class.

Below I will show you how to deal the cards to the players and the board:
public void Deal(StageEnum stage)
{
if (cards == null)
{
throw new InvalidOperationException();
}

if (board == null)
{
throw new InvalidOperationException();
}

if (board.Players == null || board.Players.Count < 2)
{
throw new InvalidOperationException();
}

int iCardsToDeal = 0;
switch (stage)
{
case StageEnum.PreFlop:
Deal(board.Players, 2);
break;

case StageEnum.Flop:
Deal(board, 3);
break;

case StageEnum.Turn:
Deal(board, 1);
break;

case StageEnum.River:
Deal(board, 1);
break;
}
}

private void Deal(List players, int cardCount)
{
for (int i = 0; i < cardCount; i++)
{
foreach (Player p in players)
{
p.Cards.Add(cards[0]);
cards.RemoveAt(0);
}
}
}

private void Deal(Board board, int cardCount)
{
BurnCard();
board.Cards.AddRange(cards.GetRange(0, cardCount));
cards.RemoveRange(0, cardCount);
}

That was easy :-). In the next post I will discuss how to evaluate the hands and determine the winner!

Download entire solution

donderdag 15 november 2007

Revamped Looks

Hi, I have nothing much to add today, but the fact that I revamped the looks of the blog :). Hope you like it!

woensdag 14 november 2007

Shuffle Things Up

From this day forward I will post the changes in source in a zip file. This is much easier if you are confused about the code. Scroll down to the end of this entry to find the link.

Also, I would like to mention that the usage of this code is restricted for personal and educational purposes, unless you give me credit for it.

Today I have implemented the Dealer service. This class has the responsibility to hold the Card classes, shuffle the deck and distribute the Cards to either the players or the board.

Create a new Class Library and call it Poker.Services. Add a new class called Dealer. Implement the next two functions in the Dealer class to initialize the deck of cards and shuffle.
private void InitializeCards()
{
cards = new List<Card>();
for (int i = 0; i < 13; i++)
{
for (int j = 0; j < 4; j++)
{
cards.Add(new Card((Card.SuitEnum)j, (Card.ValueEnum)i));
}
}
}

private void ShuffleCards()
{
List<Card> c = new List<Card>();

Random rnd = new Random();
for (int i = 0; i < 52; i++)
{
int cpos = rnd.Next(0, cards.Count);
c.Add(cards[cpos]);
cards.RemoveAt(cpos);
}

cards = c;
}

To initialize the class, create this constructor:
private List<Card> cards = null;

public List<Card> Cards
{
get { return this.cards; }
set { this.cards = value; }
}

public Dealer()
{
InitializeCards();
ShuffleCards();
}

To test the Dealer service, we have to create a new instance of the Dealer class and count the cards. Also, there should be four cards of each value: one for every suit. Create a new Class Library called Poker.Services.Tests and add a new class DealerTests. Add a reference to the nunit.framework assembly and mark the DealerTests class with [TestFixture].

Create a new function TestDeckConsistency which accepts a generic List of type Card:
public void TestDeckConsistency(List<Card> c)
{
Assert.AreEqual(52, c.Count);

for (int i = 0; i < 13; i++)
{
int counter = 0;
for (int j = 0; j < 52; j++)
{
if (c[j].Value == (Card.ValueEnum)i)
{
counter++;
}
}

Assert.AreEqual(4, counter);
}
}

Add a new test function to call this with a list of cards:
[Test]
public void Dealer_NewCardDeck_52Cards4OfEachValue()
{
Dealer d = new Dealer();
TestDeckConsistency(d.Cards);
}

Done. We now have a working dealer, which shuffles the cards. Click on the link below to download the entire solution, which includes a modified version of the form: it displays the shuffled cards.

Download entire solution

Using Cards.dll or CardGames.dll

It is possible to use the cards.dll for drawing the cards. See Code Project - Drawing Cards with Cards.dll by Mike Kitchen for details.

The reason why I don't use this dll is that I work on Windows Vista. Windows Vista does not have the dll mentioned. I found another possibility, CardGames.dll in the Windows System32 folder, but I could not find how to use it, nor does it export functions?

As far as I can see the CardGames.dll is a resource container and does not have any functionality embedded but behavior XML of each cardgame shipped with Windows Vista.

If any of you know how to use the latter dll, please let me know.

UPDATE: I have unraveled the mysteries around CardGames.dll, read CardGames.dll Demystified!

dinsdag 13 november 2007

A First Look At The Cards

On a website [url: CPSC 124, Spring 2006 - Lab 12: Arrays] I have found a picture of the playing cards we can use. It consists of one picture with 13 playing cards in a row, starting with the Ace and ending with the King. Every row has a distinct suit. An extra row was added with the back of the card and two jokers.

To support this image I had to refactor the Card class we created in the last post. This was done in 5 minutes, thanks to the unit testing.

The two enums have been changed to inherently support the image:
public enum SuitEnum
{
Clubs
, Diamonds
, Hearts
, Spades
}

public enum ValueEnum
{
Ace
, _2
, _3
, _4
, _5
, _6
, _7
, _8
, _9
, _10
, Jack
, Queen
, King
}

Also, the ToString() function was modified to support the changes:
public override string ToString()
{
string tempString = string.Empty;

switch (this.value)
{
case ValueEnum._10:
tempString = "T";
break;

case ValueEnum.Jack:
tempString = "J";
break;

case ValueEnum.Queen:
tempString = "Q";
break;

case ValueEnum.King:
tempString = "K";
break;

case ValueEnum.Ace:
tempString = "A";
break;

default:
tempString = ((int)this.value + 1).ToString();
break;
}

switch (this.suit)
{
case SuitEnum.Clubs:
tempString += "c";
break;

case SuitEnum.Diamonds:
tempString += "d";
break;

case SuitEnum.Hearts:
tempString += "h";
break;

case SuitEnum.Spades:
tempString += "s";
break;
}

return tempString;
}

Run the unit tests, and see: the tests succeed!

Next, create a new C# Windows Application called Poker.WinApp, add a reference to Poker.Common and add the image to the file. Click the image to view the properties and make the Build Action: Embedded Resource.

Add a new function to the form:
private Bitmap getCard(Card c)
{
Assembly a = Assembly.GetExecutingAssembly();
using (Image img = Image.FromStream(a.GetManifestResourceStream("Poker.WinApp.cards.png")))
{
using (Bitmap bmp = new Bitmap(img))
{
int w = bmp.Width / 13;
int h = bmp.Height / 5;
int posX = (int)c.Value * w;
int posY = (int)c.Suit * h;

return bmp.Clone(new Rectangle(posX, posY, w, h), System.Drawing.Imaging.PixelFormat.DontCare);
}
}
}

To test this, add a button and a picturebox to the form and add the following code to the Click event of the button:
Card c = new Card(Card.SuitEnum.Diamonds, Card.ValueEnum._6);
this.pictureBox1.Image = getCard(c);

Start the WinApp, click the button and voila!