Tuesday, May 30, 2006
Most Hold'em players know what Outs are. According to Wikipedia an out is:
[A]n out is any unseen card that, if drawn, will improve a player's hand to one that is likely to win
The question for the programmer is, is this definition sufficent to write a function that returns the cards that are outs?
Let's look at the two key points made by Wikipedia. They are:
- The hand must improve
- The new hand is likely to win.
Let's start by writing a function that meets the first criterion.
using System;
using HoldemHand;
// A first try at calculating outs
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
string pocket = "As Ac";
string board = "Kd 8h 9c";
// Calcuate the outs
ulong outsmask = Outs(Hand.ParseHand(pocket), Hand.ParseHand(board));
Console.WriteLine("[{0}] {1} : Outs Count {2}",
pocket, board, Hand.BitCount(outsmask));
// List the cards
foreach (string card in Hand.Cards(outsmask))
{
Console.Write("{0} ", card);
}
Console.WriteLine();
}
// Return a hand mask of the cards that improve our hand
static ulong Outs(ulong pocket, ulong board)
{
ulong retval = 0UL;
ulong hand = pocket board;
// Get original hand value
uint playerOrigHandVal = Hand.Evaluate(hand);
// Look ahead one card
foreach (ulong card in Hand.Hands(0UL, hand, 1))
{
// Get new hand value
uint playerNewHandVal = Hand.Evaluate(hand card);
// If the hand improved then we have an out
if (playerNewHandVal > playerOrigHandVal)
{
// Add card to outs mask
retval = card;
}
}
// return outs as a hand mask
return retval;
}
}
}
Passing this starting hand A♠ A♣, K♦ 8♥ 9♣ it into our new method returns the following outs:
- K♠, 9♠, 9♥, 8♠, K♥, 9♦, 8♦, K♣, 8♣ - Two pair
- A♥, A♦ - Trips
- Q♠, J♠, T♠, Q♥, J♥, T♥, Q♦, J♦, T♦, Q♣, J♣, T♣ - Improves Kicker
I think most people would agree that super-sizing your kicker probably doesn't help much here. I think most people would also agree that improving the board doesn't help either. So let's add two more rules:
- The hand must improve
- The new hand improvement must be better than an improved kicker
- The new combined hand must be stronger than the just the board
- The new hand is likely to win
The following example handle these new rules and allows opponent hands to be added.
using System;
using HoldemHand;
// A first try at calculating outs
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
string pocket = "As Ac";
string board = "Kd 8h 9c";
// Calcuate the outs
ulong outsmask = Outs(Hand.ParseHand(pocket), Hand.ParseHand(board));
Console.WriteLine("[{0}] {1} : Outs Count {2}",
pocket, board, Hand.BitCount(outsmask));
// List the cards
foreach (string card in Hand.Cards(outsmask))
{
Console.Write("{0} ", card);
}
Console.WriteLine();
}
// Return a hand mask of the cards that improve our hand
static ulong Outs(ulong pocket, ulong board, params ulong [] opponents)
{
ulong retval = 0UL;
// Get original hand value
uint playerOrigHandVal = Hand.Evaluate(pocket board);
// Look ahead one card
foreach (ulong card in Hand.Hands(0UL, board pocket, 1))
{
// Get new hand value
uint playerNewHandVal = Hand.Evaluate(pocket board card);
// Get new board value
uint boardHandVal = Hand.Evaluate(board card);
// Is the new hand better than the old one?
bool handImproved = playerNewHandVal > playerOrigHandVal &&
Hand.HandType(playerNewHandVal) > Hand.HandType(playerOrigHandVal);
// This compare ensures we move up in hand type.
bool handStrongerThanBoard =
Hand.HandType(playerNewHandVal) > Hand.HandType(boardHandVal);
// Check against opponents cards
bool handBeatAllOpponents = true;
if (handImproved && handStrongerThanBoard &&
opponents != null && opponents.Length > 0)
{
foreach (ulong opponent in opponents)
{
uint opponentHandVal = Hand.Evaluate(opponent board card);
if (opponentHandVal > playerNewHandVal)
{
handBeatAllOpponents = false;
break;
}
}
}
// If the hand improved then we have an out
if (handImproved && handStrongerThanBoard && handBeatAllOpponents)
{
// Add card to outs mask
retval = card;
}
}
// return outs as a hand mask
return retval;
}
}
}
Passing this starting hand A♠ A♣, K♦ 8♥ 9♣ to our new method produces following outs:
- K♠, 9♠, 9♥, 8♠, K♥, 9♦, 8♦, K♣, 8♣ - Two pair
- A♥, A♦ - Trips
This new method is certainly better than our first method. But we can still do better.
Stay tuned for more indepth discussion on improving our outs method.