Sunday, April 5, 2015

Creating a PokerBot using a C# WinForms Application Part3

Before we start diving into too much more code I want to take a step back and give the code a little more structure. Building a good foundation will make it easier as things move forward and the bot becomes more complex.

I'll start by creating a new class called CardDetection.cs. I'm going to put any functions and variables related to the bot's Card Detection into this class. This class is going to be static because there is never going to be a need to create multiple instances of Card Detection. I'm going to move the SearchBitmap and CaptureApplication functions that were shown earlier into this class. So far in the CardDetection.cs class we have:


static class CardDetection
{
     public static Bitmap CaptureApplication(string procName)

     public static bool SearchBitmap(Bitmap bigBmp, Bitmap smallBmp)

     private class User32      //Used by the Capture Application Function
}

My ultimate goal for this class is to have functions that can be called by the main Form to return the information of what cards are currently in play. To reduce all the complexity of capturing bitmaps, searching through them, and matching appropriate cards to their comparisons to a single line of code that simply returns the cards that are on the table.

So first off, I'd like to create a Card.cs class. This will be a simple class that contains a Suit and a Rank variable, but will be used to pass Card Information around the program whenever it is needed. Unlike the CardDetection class, this class will not be static, as there will need to be multiple card variables in use by the program. In addition to the Card class, I'll create some Enums:

public enum Suit
{
    NotFound = 0,
    Diamonds = 1,
    Hearts = 2,
    Clubs = 3,
    Spades = 4,
}

public enum Rank
{
    NotFound = 0,
    Two = 2,
    Three = 3,
    Four = 4,
    Five = 5,
    Six = 6,
    Seven = 7,
    Eight = 8,
    Nine = 9,
    Ten = 10,
    Jack = 11,
    Queen = 12,
    King = 13,
    Ace = 14,
}

The Card.cs Class looks like this:

class Card
{
    public Suit Suit { get; private set; }
    public Rank Rank { get; private set; }

    public Card(Suit suit, Rank rank)
    {
        Suit = suit;
        Rank = rank;
    }
}

Here is an example of how the Card variable can now be used in the program:

//Define your hand, an array of 2 Cards.
Card[] YourHand = new Card[2];

//Define the first Card in your hand, the Ace of Spaces
YourHand[0] = new Card(Suit.Spades, Rank.Ace);

//Define the second Card in your hand, the Ace of Diamonds
YourHand[1] = new Card(Suit.Diamonds, Rank.Ace);

Now that we have the Card class setup, we can continue working on the CardDetection class. I mentioned earilier it will be better to narrow down the areas on the table where the program is looking for cards to make the searching quicker and more efficient. To do this we will put a function in to return a Bitmap of a partial area of the Poker Stars screen defined by a rectagle. The function is shown below:

private static Bitmap CopyPartialBitmap(Bitmap srcBitmap, Rectangle section)
{
     // Create the new bitmap and associated graphics object
     Bitmap bmp = new Bitmap(section.Width, section.Height);
     Graphics g = Graphics.FromImage(bmp);

     // Draw the specified section of the source bitmap to the new one
     g.DrawImage(srcBitmap, 0, 0, section, GraphicsUnit.Pixel);

     // Clean up
     g.Dispose();

     // Return the bitmap
     return bmp;
}

Now we would need to define some rectangles on the Pokerstars window to narrow where we are going to search for cards. The picture below shows on orange rectangle defining where to look for your cards, and a red rectangle defining where to look for community cards:

I created two functions in the CardDetection class that capture a bitmap of the two rectangles above:

private static Bitmap CaptureYourHandImage()
{
    return CopyPartialBitmap(CaptureApplication("PokerStars"), new Rectangle(352, 365, 90, 53));
}

private static Bitmap CaptureCommunityCardsImage()
{
    return CopyPartialBitmap(CaptureApplication("PokerStars"), new Rectangle(262, 204, 282, 74));
}


Next post we will look at combining the elements laid out in this post and create functions that simply return Card[] by searching through the newly defined card windows against all 52 card bitmaps to determine which cards (if any) are there.

2 comments: