Adding Intelligence To Your Bot

Editing the Code

The file you need to edit is TexasHoldEm.cs

The main method of interest is:

CalculateMove()

This receives a package of game state information, including the players’ stack sizes, bets so far, the round of betting and what cards you have and are on the board.

From this information, it is your task to decide two things:
1. If you would like to fold
2. If not, what bet size you would like to make

You specify your decisions by calling ClientMoved with the move package - TexasHoldEmMove

In order to fold, set the Fold parameter to true.

Use the BetSize parameter to specify your bet size.

If you set Fold to true, BetSize is ignored.

For example:

TexasHoldEmMove move = new TexasHoldEmMove();
move.Fold = true;
move.BetSize = 20; // Ignored
ClientMoved(move);

Case Study

Let’s say we would like to implement the following strategy:
1. Our default move is to just check or call (bet the minimum allowed)
2. Randomly, 33% of the time we will increase this bet by a raise of between 20 and 100
3. If the round is PreFlop and it is our first bet: If we have a pair we raise an additional random amount between 100 and 200, but if we have a hand in the lowest 25% of hand values by rank, we will fold.
4. If on the Flop or the Turn we have four cards to a flush, we go all-in
5. If we are playing the particular bot “Barney01”, we will double our bet.

We will use the built in helper method IsPair() to determine if our hole cards are a pair.
There is also a helper method called IsFourCardFlush() which can take 5 or 6 arguments.
The RangeRand method returns a random number, optionally rounded down to a round number
The code looks like the following:

    Thread.Sleep(ThinkingTime); // Slow game down so human user can see progress
 
    TexasHoldEmMove move = new TexasHoldEmMove(); // Default bet when no special cases are identified:
    move.BetSize = minBet; // Just call
 
    if (RangeRand(0, 2) == 0) // 1/3 of the time, raise
        move.BetSize += RangeRand(20, 119, 20); // 20,40,60,80 or 100 with equal likeliness
 
    if ((round == TexasHoldEmRound.Preflop) && isOurFirstBetOfRound) // It is our first bet of the round
        if (playerHand.IsPair())
            move.BetSize += RangeRand(100, 219, 20);
        else if (playerHand.HoleRank() < 169 / 4) // There are 169 distinct starting hands
            move.Fold = true;
 
    // Go all-in if it is Flop or Turn round and I have four cards to a flush
    List<Card> myCards = playerHand;
    myCards.AddRange(boardCards);
    if ((round == TexasHoldEmRound.Flop) || (round == TexasHoldEmRound.Turn))
        if (myCards.IsFourCardFlush())
            move.BetSize = maxBet;
 
    // Barney01 is tolerant of big raises
    if (opponentId=="Barney01")
        move.BetSize*=2; // If we bet more than maxBet, server rounds it down
 
    ClientMoved(move);

Helper Values and Methods

Various shorter names and functions are available to you to speed up your development.

Helper Values

int minBet; // The minimum bet allowed
int maxBet; // The maximum bet allowed
string opponentId; // The bot id used by the opponent player
Card hole1, hole2; // Our hole cards
Card flop1, flop2, flop3; // The flop cards
Card turn; // The turn card
Card river; // The river card
List<Card> boardCards; // All board cards (a list of 0 to 5 Card objects depending on the round)
List<Card> playerHand; // Your hole cards, always precisely 2 cards
TexasHoldEmRound roundThe betting round
bool isOurFirstBetOfRound; // Is this the first time we have bet in this round?
int dealNumber; // Which deal number we are on, starting from 1
int dealCount; // The maximum number of deals which will be played in this game
int smallBlind; // The amount of the small blind - always 10 currently
int bigBlind; // The amount of the big blind - always 20 currently
bool isDealer; // Are we the dealer this deal
int opponentRoundBetTotal; // The total of the opponent's bets during this round
int opponentStack; // The opponent's remaining stack
int playerRoundBetTotal; // The total of our bets during this round
int playerStack; // Our remaining stack
int potAfterPreviousRound; // The pot size at the end of the previous round
// The total pot size at any point in time is potAfterPreviousRound + opponentRoundBetTotal + playerRoundBetTotal

Hand Analysis Methods

Helper methods generally operate as a method to a list of cards, for example:

bool isPairInHole=playerHand.IsPair(); // playerHand is the Helper Value - a List of Cards containing the player's hole cards
 
List<Card> flopCards = new List<Card>(){flop1, flop2, flop3};
bool isPairOnFlop = flopCards.IsPair())

They may operate on lists of various lengths where logical. For example, IsPair would work on lists of at least 2 cards, while IsStraight needs a minimum of 5 cards. However providing an invalid or illogical length list will not cause an exception, just a negative result. The methods will ignore any null cards sent through.

Available methods are:

IsPair()
IsTwoPair()
IsThreeOfAKind()
IsStraight()
IsFlush()
IsFullHouse()
IsFourOfAKind()
IsStraightFlush()
IsFourCardFlush()
IsFourCardStraight()
IsSuitedConnector() // Call with two cards only. True if cards are same suit and sequential, for example 4 spades, 5 spades
IsHiddenPair() // True if you have a pair with one card in the hole and one on the board

Hand Ranking Methods

Assist you in assessing the strength of a set of cards

// HandRank() - On a list of from 5 to 7 cards, returns the rank of the best possible poker hand,
// from 1 for a seven high (76432) to 7462 for a royal straight flush (AKQJTs). There are 7642 distinct poker hands.
 
// HandRankDesc(int HandRank); // Returns a human readable description of the HandRank
 
// Example:
 
List<Card> myCards = playerHand;
myCards.AddRange(boardCards);
int myHandRank = myCards.HandRank();
System.Windows.Forms.MessageBox.Show("My hand rank is "+myHandRank+" description:"+HankRankDesc(myHandRank));
 
// HoleRank() - Takes two cards only, returns rank of hole cards – for example 0 for a 3,2 offsuit, 168 for a pair of aces
// (Rank based on % of time winning against a random other hand heads up. In heads up play, 32o is the worst hand rather than the infamous 72o for a ring game)
 
double percentHoleRank = 100.0*playerHand.HoleRank()/168.00; // playerHand is our hole cards.  Here we calculate the percentile value of our hole cards - 0 is bad, 100 is good

Other Helper Methods

int RangeRand(int min, int max);
int RangeRand(int min, int max, int roundTo);
// Generates a random number between min and max and optionally rounds it down to the nearest multiple of roundTo.
 
card.IsPictureOrAce(); // Operates on a Card object. Is the passed card either Jack, Queen, King or Ace
card.IsPictureOrAceOrTen(); // Is the passed card either Ten, Jack, Queen, King or Ace

Advanced

Also you may like to edit the method:

ProcessGameState()

This is called after any bet is made by either player. The function displays the state of the game on the client screen, then only if the IsMover flag is set, it calls CalculateMove(). To maximise your efficiency, you may like to do some processing here while your opponent calculates their move. Note there is a Thread.Sleep in this method which pauses the client for a short time so that the user can see the result of the deal. Example:

protected override void ProcessGameState(TexasHoldEmGameState state)
{
    Show the user the current game state
 
    Desk.ShowMove(state);
 
    if (state.IsMover)
        CalculateMove(state).Wait();
    else
        ; // Could do some additional processing here while opponent thinks
 
    // Wait a little bit to show the user the final cards of the round
    if (state.Round == TexasHoldEmRound.Showdown)
        Thread.Sleep(ThinkingTime * 3);
}

Suggested reading…

Poker Primer

Bot Strategy

Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License