If you've turned on a TV in the past five years you've seen those nifty win percentages they throw up on the screen in televised poker:

In this multi-part series we're going to build a poker calculator (with complete source code) capable of computing these sorts of win percentages or equities for any poker situation whatsoever...
...in a couple lines of code:

We'll also discuss the theory that goes into such a calculator:
Now: the above televised poker win percentages shown above were inserted by the producers, after the fact, with perfect knowledge of each player's cards. In the heat of battle, we don't have perfect knowledge of anything except our own cards. And the way we typically get around this is by assigning our opponents not a specific hand, but a range or distribution of potential hands.

When confronted with a situation like this, the typical poker calculator curls up into the fetal position and begs for mercy. We want a poker calculator capable of handling these sorts of calculations—multiway ranged equity calculations—without skipping a beat. For example, let's say there are nine players, two of whom have known hands, two of whom have hand ranges, and five of whom have random hands...
Normally we'd have to break open a copy of Andrew Prock's excellent PokerStove in order to perform this sort of analysis.

The purpose of today's post is to explain how to perform these calculations in a couple lines of code, with a view towards incorporating robust ranged equity calculation into our pet poker software projects: poker bots, real-time strategy assists, PokerStove clones, etc. We talked about ranged equity calculation briefly in The Great Poker Hand Evaluator Roundup and again in How I Built a Working Online Poker Bot, Part 8. Today's discussion will pick up where those posts left off.
This article is rather long-winded, so here's an overview of what we'll be covering:
Fair warning! If you're a grizzled veteran of poker-related code, you probably won't learn much by reading this. Save yourself! If you're a non-programmer, this material will probably be excruciatingly boring. Save yourself! If, on the other hand, you've got the poker/programming bug, if you've struggled to write robust equity calculation code before, or if you plan on one day writing such code, well, this article may come in handy.
Who knows. Anything's possible.
There are (at least) four ways to calculate equity in the game of poker. Whatever the game and whatever the specific scenario:
These methods are all subtly related to one another. Exhaustive enumeration is really a case of applied combinatorics. Lookup tables are a way of pre-computing equities and storing them in a file so we don't have to recalculate them. Monte Carlo is a statistical method which allows us to approximate the value we would've gotten had we taken the time to exhaustive enumerate every possible outcome. And so forth.
The point I want to make is that a poker equity calculator is a hand evaluator sitting inside a loop.

Now, the "loop" in question might be a series of nested loops. It might be a recursive loop. But every calculator will impose a circular, repetitive motion across the following actions:
So no matter how convoluted the code or how advanced the algorithm, you'll generally be able to pick out the above stages. Let's take a look at some representative code.

We have a basic loop, set to run (in this case) a certain number of trials. For each trial, we'll generate a) any missing player cards and b) any missing board cards. Once we've done that, we'll pass those into the hand evaluator, which will compute the winner and tally the results.
Now, when I say a hand evaluator, I mean a component whose only job is to take the cards for a specific trial and determine the winner. Sometimes the term is used loosely, but for me it has a precise meaning. In The Great Poker Hand Evaluator Roundup, we discussed a dozen or so different evaluators. In particular:
We'll discuss how to use each of these evaluators to perform true multiway equity calculation. In this installment, we'll focus on the Pokersource evaluator. If you're not familiar with this evaluator, you might want to read A Pokersource Poker-Eval Primer before continuing.
Hand distributions and ranges are so important to poker strategy, a sort of mini-language has sprung up to describe them. This language is still evolving, but it started as a way of describing hands while stripping out unnecessary suit information. Poker players will be familiar with the following descriptions of agnostic hands.
| Hand | Number of Combinations | Meaning |
| AJs | 4 | Any Ace with a Jack of the same suit. |
| 77 | 6 | Any pair of Sevens. |
| T9o | 12 | Any Ten and Nine of different suits. |
| 54 | 16 | Any Five and Four, suited or unsuited. |
It wasn't long before players started adding a few symbols to make these notations more expressive:
| Hand | Number of Combinations | Meaning |
| AJs+ | 12 | Any Ace with a (Jack through King) of the same suit. |
| 77+ | 48 | Any pair greater than or equal to Sevens. |
| T9o-65o | 12 | Any unsuited connector between 65o and T9o. |
| 54 | 16 | Any Five and Four, suited or unsuited. |
And of course, these notations can be glommed together with the "comma operator":
| Hand | Number of Combinations | Meaning |
| QQ+,AQs+,AK | 38 | Any pair of Queen or better, any AQs, and any AK whether suited or not. |
| AhKh,7h7d | 2 | Ace-King of Hearts or a pair of red Sevens. |
Needless to say, if we're building an evaluator that can work with hand distributions, it should be able to understand the notation used to describe them. In particular, when we say "I believe my opponent has a range of 99+,AJs+", it should understand that what we're really saying is I believe my opponent has one of 48 specific hands.

Of course, if you happen to be holding the Ace of Spades, then some of those possibilities are now blocked for your opponent, and we'll need to take this into account when performing any equity calculations:

But regardless of what distribution we assign an opponent, or how many of the specific hands contained in that distribution are available, we can always, always, always represent an opponent's distribution as a simple collection of specific hands. Even if we know the opponent's specific cards, he still has a distribution...of one hand.
In fact, the core abstraction used in our evaluator is exactly that: a class representing a single player's distribution of possible hands:
This is the acid test of a true isometric calculator. Isometric (we could also use the word congruent) calculators treat everything as a distribution. The isometric calculator could care less whether a player has:
This normalizes the underlying logic, allowing us to disregard arbitrary differences between specific hands, hand ranges, and random hands. They're all the same. And they're all treated the same.
Monte Carlo simulation and Exhaustive Enumeration are the two horns of the poker equity calculation beast.

On the one hand, we have the exhaustive enumeration approach, which consists of generating each and every possible outcome. No matter if you have 22 players with random and ranged hands before the flop, exhaustive enumeration will generate every possible combination of cards for each player along with every possible combination of board cards, tally them all, and yield the precise theoretical equity for the situation with zero error.
On the other hand, we have the Monte Carlo method, darling of physicists and statisticians, which consists of generating random inputs (cards, in our case) across many trials, thereby converging a result which closely approximates the theoretical "correct" result. Monte Carlo simulation produces results which have a small margin of error, although in practice this error is low enough that we can effectively ignore it.
Now: in a perfect world, we'd always use exhaustive enumeration. Given infinite computing power, we'd analyze every possible outcome in a nanosecond and be done with it. But in the real world, exhaustive enumeration can be prohibitively expensive. The outcomes start to explode as you add more and more choices to a given scenario:
| Scenario | Street | Number of Outcomes |
| AhAd vs. KcKs | Turn | 44 |
| QsJc vs. Ad2c | Flop | 990 |
| 44 vs. Ts7c | Flop | 2,970 |
| AKs vs. TT | Flop | 23,760 |
| AKs vs. TT vs. J9o | Flop | 260,064 |
| 3c2s vs. 5d4c | Preflop | 1,712,304 |
| AA vs. KK | Preflop | 61,642,944 |
| AA vs. KK vs. QQ | Preflop | 296,082,864 |
| AA vs. KK vs. QQ vs. JJ | Preflop | 1,407,466,368 |
| AA vs. XX | Preflop | 12,585,434,400 |
You're already looking at on the order of 12 billion outcomes just to exhaustively enumerate an agnostic pair of Aces versus a random hand before the flop. And we'll frequently be calculating situations involving 4 or 5 players (if not more), each of whom has a distribution of N possible hands, times the 5 board cards, and so forth.
Now here's the key point: even though it would take us (say) 12 billion evaluations to exhaustively enumerate the AA-vs.-random preflop scenario, we can Monte Carlo the same scenario and get some very precise results in a fraction of that time. A million-trial Monte Carlo simulation will produce equities that are precise down to fractions of a percent; in fact, we can typically get that type of precision with far fewer than a million trials (possibly as few as 10,000 or 100,000).
This leads us to a few rules of thumb:
PokerStove actually lets the user choose how to perform the analysis:

And sure enough, in the source code accompanying this article, you'll find a couple telltale methods:
The decision as to when to use Monte Carlo vs. Exhaustive Enumeration really boils down to you and the purpose of your tool. If you need to compute equities involving many players with fat distributions in fractions of a second, you'll gravitate towards Monte Carlo. If on the other hand you have a lot of processing time or if you're not dealing with ranged/random hands so much, exhaustive enumeration might be the order of the day. In general, you'll find that there exists a Monte Carlo threshhold which is ideal for your application. When the number of potential outcomes exceeds this threshhold, you'll Monte Carlo; when the number of outcomes falls short, you'll exhaustively enumerate.
But the calculator itself should support both.
The terms equity and win percentage are often used interchangeably, in casual conversation, but these are actually two different things. As Andrew Prock explains it:
[Equity] is not the chance that a hand will win the pot. Rather it is the fraction of the pot that a hand will win on average over many repeated trials, including split pots. The equity for a hand is calculated by dividing the number of "pots" that the hand won by the number outcomes considered. Because two players can split a pot, a player can win fractional pots. Thus, it is possible for a hand to have non-zero equity despite the fact that it cannot win.
The metaphor I like to use is that of a pizza.

In a single battle of poker, there's exactly 1.0 unit of "winningness" to go around. One pizza. The player who wins the hand gets the pizza, and everybody else goes hungry. But if two or more players tie for the win, well, they each get an equal share of the pizza. If exactly two players tie, they each get half of the pizza: 0.5 units of winningness each. If three players tie, they each get a third (0.333) of the pizza. And so forth.
In general, when N players tie in a particular game of poker, they're each awarded a fractional win equal to 1 / N.
This is not just some number we use by way of explanation. This fraction of the pizza, be it 1.0 or 0.5 or 0.333 or 0.25, is the actual amount you'll add to each player's "win tally" in the poker calculator implementation, after you determine the winner(s) of each specific trial:
That code is a little messy (see my code disclaimer, below), but it gets the point across. Equity is similar to win percentage except it normalizes the value of ties. This is hugely important in a game like Hold'em or Omaha, where ties are so frequent.
One of the benefits of treating each player's hand as a distribution containing one or more hands is that it gives us a precise count of each player's possible holdings and allows us to express each player's hand as a number between 0 and N. For example, in a given three-player matchup we might find that:
So we can exhaustively enumerate all possible combinations of player holdings using a typical nested loop structure.
The problem is that the number of loops has to be hard-coded per the number of players. If we had seven players, we'd need seven loops. That's a little messy, it violates DRY, and we'd prefer a normalized solution that will handle any arbitrary N number of players. In order to do that, we'll take our nested-loop structure and invert it, creating a recursive function with a depth equal to the number of players in the hand.
The above code omits some important details—such as how to handle dead cards and collisions between player distributions—but the general idea, and you'll see this in the full source code accompyaning this article, is that we can exhaustively enumerate any arbitrary situation involving N players with arbitrary distributions along with all possible board combinations using a single recursive function.
So now that we know our core abstraction will be the hand distribution, and now that we're agreed on the language we use to describe hand distributions, let's talk a little bit about how to generate them programatically. In other words, how do we go from this...
22+,A2s+,ATo+,KT+,QT+,JT+,65s+
...to this?

In general, to parse a given textual hand distribution, we'll follow these steps:
For example, to boil a given agnostic pair (such as 77) down into its six unique combinations, we might hack out this straightforward solution:
If the agnostic pair includes an incrementor, as in "77+", we can add a third loop to increment the rank:
And if the agnostic pair specifies a range with a ceiling, as in "JJ-88", we'll just change the condition on the rank loop:
Do the above loop structures look familiar? They should, if you're one of the masochistic few who actually read Exhaustively Enumerating Combinations and Permutations in Code. Converting a textual hand range notation into a concrete distribution is just a special case of combination counting. The above method isn't the most elegant, but it is straightforward.
When Monte Carlo is used to randomly select a single hand from each opponent's distribution, the possibility of collisions can arise. That is, a situation can occur in which every hand in a player's distribution is prevented or blocked by the cards chosen for other opponents during a specific trial. Consider the following four-way matchup:
Now, what happens if we (randomly) select the [AhKh] for player 1, the [Ad7c] for player 2, and the [AsAc] for player 3?
Answer: player 4's distribution is now completely blocked. Every hand in his distribution requires an Ace, but the four Aces have already been dealt out. This won't happen very often, but it can and will happen. And when it happens, the trial is invalid and should be thrown out. Furthermore, it doesn't take a complete blockage to introduce bias into the results. Even partial collision can bias the results. The reason is simple: the first player to be "dealt" cards always has his entire distribution to choose from; but many of the hands in the last player's distribution will no longer be available.
It's unfair.
So in order to reduce the likelihood of this happening, we change the player pecking order between trials. That is, instead of choosing Player 1's hand followed by Player 2's hand followed by Player 3's, each and every trial, we want to alter the order in which we choose cards for opponents across many trials. Instead of starting with Player 1 every time, we want to start with Player 1 on one trial, Player 2 on the next trial, Player 3 on the trial after that, and so forth.
By choosing the "starting player" in this round-robin fashion, we amortize potential collisions across all players, reducing the likelihood of a) bogus trials that we have to discard and b) bias due to partial collision. And in order to do this cleanly, we'll use a circular linked list to address these players, and increment our "head" with each new trial.

I hope it's becoming clear that when I said in A Circular Dilemma Concluded:
The circle is the fundamental geometry of poker.
This wasn't some theoretical pie-in-the-sky notion! Of course, you don't have to use a circularly-linked list, but it makes the code cleaner.
Today's installment includes source code for a full-fledged isometric calculator capable of computing equity for any Texas Hold'em scenario, including weird scenarios such as pocket Aces versus twenty-two random hands before the flop. Using the evaluator is simple:
Just put in your opponent hands/ranges separated by | and go. That version of the function will switch between Monte Carlo and Exhaustive Enumeration based on the MC threshhold. In addition, there are a couple overloads which you can use to force Monte Carlo or Exhaustive Enumeration:
This evaluator is implemented without optimizations of any kind in order to make the code as transparent as possible.
Despite the lack of optimization, this evaluator is fast enough for typical use, including real-time poker botting in a multi-table scenario.
Download the XPokerEquity source code (751K)
The XPokerEquity evaluator solution includes a simple test project (console app) which will run various matchups and test the returned equities against PokerStove results:

When it comes to testing your poker calculator, there are three key sanity checks you'll want to employ, especially if you're using the evaluator for something important (a commercial product, a real-money poker bot, etc.):
In practice you'll find that isometric evaluators tend to be either "right" or "wrong". That's not to say they aren't susceptible to obscure bugs, but generally speaking, if an isometric evaluator calculates any multiway matchup correctly, it'll calculate them all correctly. That's not a substitute for robust testing, but it's another benefit of the isometric approach to equity calculation.
I apologize for the length of this post (well, not really) but I wanted to do a (fairly) comprehensive overview of the subject rather than just throwing a brick of source code at you. Needless to say, there are better and more clever ways of doing pretty much everything we've discussed here today.
Anytime you flirt with the boundary between computer science and hard math (or software development and computer science) things start to get a little crazy. Maybe you can use N-ary decomposition across a diagnate infinity of infinities of choice with matrix-based combinations to derive the asymptotic convergence curve and thereby somehow back yourself into a massively parallel exploration of the poker game tree, and you know what? That's fascinating. It really is. But for now let's just deal out a bunch of hands and tally the results. It's easy and it works.
And for those of you who've been wondering what happened to the poker botting series?...stay tuned. Because once you've built your isometric equity calculator, your poker bot can start to do all sorts of nifty things in real time:
So I hope you'll stay with me as we watch our formerly naive poker bots start to grow some teeth. Until then, may the equities always be in your favor.
94 comment(s)
Awesome! I've only skimmed this so far. Will DL the code and give it a twirl later today.
I have been futzing around with code like this for literally about a year. Ended up using Keith Rule, which is decent. But I wanted it in C++...
Edward G. on Monday, April 20, 2009Sweet Jesus. Downloaded. Tested. Love the simplicity of the HoldemCalculator::Calculate method. Have been looking for something like this for a looooong time. Just let me pass in a string damnit!!
That said, I wish you'd included a LUT in the implementation. At least for heads-up PF matchups. Then again, with the code here, I can build my own. But that's work.
Kenny on Monday, April 20, 2009thats it. i said it last year. you teach a poker bot how to perform these kinds of calculations and you blow the lid right off this game. you and your stupid poker botting BS, encouraging people to do something you know damn well not 1 in 1000 would've done without you holding their hand like some demented asshole.
"poker bots growing teeth..."
you better hope i never catch you at the tables.
Anonymous and pissed on Monday, April 20, 2009@anonymous and pissed: He's just leveling the playing field here. More and more people use this kinda crap. And every single thinking human being can find half of this crap all over the internet anyway. He's just condensing it. And I love it.
I think you should be hating less and start working on your poker game. Probably it sucks. And that's the reason you're so pissed. Ass-wipe.
Anonymous and loving it... on Monday, April 20, 2009James please ignore this dork and keep 'em coming!
-Ed
Ed K. on Monday, April 20, 2009Shortcuts like the "88+" system are good at first, but I feel like it is worth it from the start to recognize that in a real poker "88+" situation, it is significantly ignorant to treat the distribution as having an equal chance for aces or eights, as well as no chance for sevens. Great work and keep it coming, but I feel like there has to be a relatively simple fix to allow for each hand to have a different likelihood of being played by a certain player instead of assigning him only a few hands and treating them as equally likely.
Mac on Monday, April 20, 2009@Anonymous and pissed:
any computer science major can figure this stuff out in ~2 days' research, depending on what their skill level is; he's just presenting it in a coherent fashion.
I suggest you read about Security by Obscurity.
@codingthewheel:
do you introduce minor fairness issues by maintaining the order of the players between hands? Wouldn't it be better to shuffle the list of players rather than rotate it when generating their hands in the MC simulation?
Bill Mill (not at all anonymous) on Monday, April 20, 2009@anonymouse Some people like playing, but many computer scientists (or simply geeks) prefer to build programs able to play in a smart way, rather than playing themselves. For me, playing (almost any card game) is plain boring, but designing algorithms is so fascinating! There is nothing wrong with that, because we are not all playing with bots on websites where bot are disallowed. A few years ago, when IRC poker was still popular there was even poker room for bots only!
Laurent on Monday, April 20, 2009The hand evaluation stuff was interesting enough. However, I didn't find word one about "How To Speak To a Girl". Disappointing.
Rob Fagen on Monday, April 20, 2009As usual, it seems this guy is copying what is already available in OpenHoldem and has been for a while. OH has had MonteCarlo iterators based on Poker-Eval for years. Has had ICM calculators for only slightly shorter.
I guess if you are looking for a complete pokerbot before the article series are complete, you know where to go...
Anonymous on Monday, April 20, 2009awesome article
Anonymous on Monday, April 20, 2009James could probably give out the source code for a mostly-built poker bot, and most readers of this series wouldn't be able to do anything worthwhile with it. He's only covered (fairly lightly at that) 15% of the topics needed to produce a bot that makes money. AI alone is probably 50%. Then there's the meta-implementation meta-details, like setting up bank accounts, getting money out in a non-conspicuous way, table selection, etc. If someone were to hand you the blueprints for a stealth bomber, would you be able to build it? And even if you could build it, would you then be able to fly it? As a matter of fact, if there were a sudden influx of people using bots, most people who actually make money off of online poker (be it playing themselves or operating a successful bot) would likely see a spike in profits.
Marc on Monday, April 20, 2009@anonymous and pissed: Instead of getting angry, how about using the info yourself and work on improving your own game? I have been a professional programmer for a decade and playing around with code calculators of various types the entire time. I may or may not ever actually build a working bot (likely not, it's a HUGE time investment), however just by studying in-depth the concepts presented here, both my online and live games have improved immensely. Online, I can now spot a winholdem bot in about 5 seconds flat, slightly longer for a few other varieties. I'm sure there are many, many, many programs out there that I can't spot yet, but I've started working on ways to try. (Anyone working on datamining algorithms for Pokertracker or Holdem Manager? ;-) )
Point is, information itself is neither good nor evil. It's just information. And knowledge is power, in whichever way you choose to use it.
The concepts I've learned about odds, hand ranges, and equity estimation have turned me from a break-even into a winning player across the board, both online and live play. I read about programming because it's fascinating. I play poker because it's fun. I learn everything I can about things that interest me because if I don't ... then, well there's no point to life, then is there?
Anonymous on Monday, April 20, 2009Where can I find the pizza in the picture?
D on Tuesday, April 21, 2009In the poker AI I made for my senior project, I represented the hands for each opponent as a (52*51) length array containing a double that initially started as 1, representing the weighted chance of that happened. Then as cards were dealt, set them to 0. As player actions occurred, the weights would be updated. For instance, if the player raised twice pre-flop, then there was a lookup table that had high chances for AA/AKs/AK/KK etc, and low chances for 72 etc, that would then be multiplied in. In the end, it would multiply the EV for each hand and the estimated probability of that hand and get a weighted EV for each of betting/folding/checking and play based on that. It was designed for heads-up play and extremely rudimentary, but it was fairly good (It regularly beat me, even though I knew how it worked).
Another thing is you can exploit symmetry to speed up the calculations. There are a lot of cases when you can get the EV for two or three hands that the opponent might have by doing only one calculation. For instance, if you are doing AhKh vs XX, then the EV against all of 9sTs, 9dTd, and 9cTc are the same, so you could calculate it for only one and multiply it by 3. Doing this you can turn the 12 billion into less.
Also, there is another option for evaluating hands that doesn't follow your model of Generate -> Evaluate -> Tally, and more accurately describes how a human would evaluate a hand, in that given N hands, find the set of cards that would improve any of the hands that aren't the highest. In turn, deal each of those sets of cards to the table. Evaluate these partial hands, then recursively repeat. Using some combinatronics, make the return of the function equal to the weighted sum of those cards being dealt over the chance that the card would be dealt. I haven't actually implemented this, and it seems really hard to get right, for little gains when you could be simulating, but it is definitely another way to do it.
Kevin H on Tuesday, April 21, 2009Pokerstove can easily do three-way range vs range vs range calculation without monte carlo so it's possible!
Thomas on Tuesday, April 21, 2009@Laurent... what sites do not disallow pokerbots and are still reputable (so you can be sure you get your money, rakeback or maybe even increase in status, like on pokerstars). Is "absolute poker" such a site? And their related network of poker sites.
Nick on Tuesday, April 21, 2009to the poster that claims this functionality is present in Open Holdem. The answer is yes and no. OpenHoldem does have weighted prwin, and enhanced prwin. Enhanced prwin is better than the example listed here in the fact that you can add or remove hands from a players lists based on handrank1326. ie I can remove the ace of hearts from a player specified hand list, instead of just specifying JTs+ or 88+. But I have to admit, I like the pokerstove-like functionality here.
Also, the OpenHoldem prw1326 is a pure Monte-Carlo simulator, not exhaustion enumeration which is faster. So, the coding the wheel is better in that regaurd, but Monte Carlo is accurate to the second demical place over 10,000 iterations. Having both will be nice, Thank you Mr. Devlin I am enjoying your series. And for anyone that is interested join us at http://botclub.ning.com for AI financial prediction.
gman on Wednesday, April 22, 2009would be interesting to combine something like the OH scaper to this code so that it auto scrapes the screen and can access something like PT database to give you an idea of where your hand stands vs your opponents range.
would be interesting to have playing yourself or a bot playing.
Anonymous on Wednesday, April 22, 2009You are crazy man. I really wish I knew what exactly were talking about, but I don't feel like devoting a year of my life to learn coding.
Players Only Rakeback on Thursday, April 23, 2009function WhenToTalkToGirl(t_time Time) { return (inf/0) }
function HowToTalkToGirl(long procastination) { return HowToTalkToGirl(procastination++) }
Orwellophile on Thursday, April 23, 2009DO NOT RUN ORWELLOPHILE'S CODE FOR SPEAKING TO A GIRL!!
Boom. Stack overflow on line 5.
JeremyX on Saturday, April 25, 2009Hi James,
I would really appreciate it if you made an odds calculator availiable for purchase (or even better, open source :D). My scripting just isn't good enough yet to follow this blog post.
Would be great to hear back from you! Nick
Poker Forum on Sunday, April 26, 2009@James, He did make the calculator available under open source, and there is two links to download it. It's very nice too, I've imported it into a DLL that can communicate with Perl, very nice and makes development a lot faster.
gman on Tuesday, April 28, 2009@Mac... Weighted ranges are a great idea. Something like a degree of truth value for each hand, or for multiple ranges,
i.e {AA-QQ, AKs} 1.0, {JJ, AKo, AQs} : .8, ... junk: .01; etc.
Has anyone implemented something like that publicly?
LetsFocus on Tuesday, April 28, 2009@Jeremy - stack overflow? pfff. dude is trying to end the universe in line 2! >:O
@James - Awesome series man. I won't be writing a poker-bot, but I WILL be rewriting my old Absolute Poker Helper app. no screen scraping or OCR this time. lol ;)
Keep 'em coming - I love this series! :D
aw on Wednesday, April 29, 2009@ew - it happens, and I now know why bots love to fold ace high flushes...
function calcBreakEvenBet($pwin, $pot, $ev = 1.00) { return (float)($pwin * $pot) / ($ev - $pwin); }
Bot with Ace high flush: "The most I can bet is $0.00? Holy crap Batman, I'd better fold this ace high flush on the river!"
World might as well have imploded.
@kevin - the hole card estimation is naïve bayesian, and has potential... during the evaluation process it's possible to generate a list of "winning-ish" hole cards... and in an ABC game, your opponents hole cards will be the intersection between these values and their betting.
Orwellophile on Thursday, April 30, 2009James,
I think there is a bug in AgnosticHand.cpp, namely in AgnosticHand::IsInclusive. For a hand like "T9-87", the function will always return false. Shouldn't
[quote] return !IsPair(handText) && ((textlen == 2) || (textlen == 3 && handText[2] == '+')); [/quote]
be expanded to cover ranges? (it does get messy with all the different possibilities) Also, as Bill Mill pointed out above, isn't there still a small bias by rotating the order in which you assign hands to players with ranges? Wouldn't shuffling the order of players be unbiased?
Thanks, Marc.
Marc on Friday, May 01, 2009With regard to the naive bayesian hand estimation, I threw together a PHP version of the 2+2 evaluation engine, and wrote a few quick classes in order to ask it the question:
[b]What hole cards would beat me?[/b]
The results were ... encouraging.... here's a typical random board:
Board [b]9c 5d Th Ks 3h[/b]
Pair
22 23 25 29 2K 2T 34 36 37 38 3A 3J
3Q 44 45 49 4K 4T 56 57 58 5A 5J 5Q
66 69 6K 6T 77 79 7K 7T 88 89 8K 8T
9A 9J 9Q AA JJ JK KA QK QQ TA TJ TQ
Two Pair 35 39 3K 3T 59 5K 5T 9K 9T TK
Three of a Kind 33 55 99 KK TT
Straight JQ
So basically, you're good to go... unless you think that the guy in late position who raised the flop might possibly have a 99, KK, TT, or QJs ..... and what are the chances of that right? :-p
The way I see it, if someone bets into you, they have either one of the hands on that list, or they have a bluff. Using an adaptable evaluator like James has presented in this article, coupled with with a list of EV+ starting hands for each position, some PT3 magic, and a bit of special naive bayesian betting sauce ... and magic should happen.
Email me at your favourite place (no, not empornium) if you would like a copy of the PHP that drives it. Yes, HR[] lookup is in PHP. No it's not in memory.
Orwellophile on Sunday, May 03, 2009I found the work awesome, just my poor programming skills prevent me from doing anything useful as i wasn't able to import the DLL into a C# project.
I tried whatever is possible with p/invoke but without success. Can you please help me providing a DLL wrapper or whatever is possible to use it in a VStudio project?
Thanks A LOT
Alex
Alex_none on Sunday, May 17, 2009Great post. Lot of content of course, but I love your choice of graphics.
Born4Holdem on Tuesday, June 09, 2009Hi guys!
"Testing preflop equities against the various preflop lookup tables that are available."
I'm currently searching for 2 and 3 player preflop lookup tables. Any idea where I can find some?
blak
Anonymous on Thursday, June 11, 2009Thanks for making this very useful code available. Is there any possibility that the Visual Studio project can be converted to a fileformat that can be opened with the Visual C++ 2005 Express Edition? Both the Express edition and the platform SDK is available for download from Microsoft, so the code examples can then be used by anyone, even people without a commercial licence of Visual Studio.
Anonymous on Thursday, June 11, 2009Oh ... 2008 has come out. ups
Anonymous on Friday, June 12, 2009Please help. Am I the only one having this issue ?
When using [code] HoldemCalculator calc; calc.Calculate(hd, bd, "", 0, result); [/code]
With u full board (Holdem), that is 5 cards, the result is... unexpected. [code] hd=[AcAs|KsKc] bd=[Ad9s3s4c7h] result[0]=-1.#IND00 result[1]=-1.#IND00 [/code] Here, you can see what this command : printf("result[%d]=%f\n", i, result[i]); ... produces.
? Help pleaz. If board is not on the river (preflop, flop and turn), it's ok. That works fine. I get equity numbers.
Grognon on Sunday, June 14, 2009Sorry, it seems like my BBCode did not work.
Grognon on Sunday, June 14, 2009Seems I found a bug in XPokerEquity Monte Carlo. PokerStove tells AA has 48.21% vs 4 opps with JJ+. HoldemCalculator().CalculateMC("AA|JJ+|JJ+|JJ+|JJ+", "", "", 500000 * 4, results) told that AA has 41.32% vs JJ+ (the more opponents the more the deviation). I tried to increase the number of iterations but it didn't help.
I modified HoldemHandDistribution::Choose method near the place where 10 attempts are made to pick random hand without collission. I suspect there was an error there. We should perform only a single attempt. Though I can't explain why. I tried to change that line to "for (int attempt = 0; attempt < 1; attempt++)" and CalculateMC returned 48.20%
zecode on Friday, June 19, 2009It's a damn shame that you didn't bother to separate the Windows specific stuff out so that OSX/Linux people can also enjoy your work. Your example is a "console app" and should be able to be built w/ g++ on Unix in a more straight forward manner.
Now I'm sitting here removing things that shouldn't be there in the first place :(
Anonymous on Thursday, July 09, 2009[i]>It's a damn shame that you didn't bother to separate the Windows specific stuff out so that OSX/Linux people can also enjoy your work. Your example is a "console app" and should be able to be built w/ g++ on Unix in a more straight forward manner.[/i]
[i]>With u full board (Holdem), that is 5 cards, the result is... unexpected.[/i]
[i]>Seems I found a bug in XPokerEquity Monte Carlo.[/i]
Thanks guys for noticing those value-added features. Will post the updated version shortly. Keep in mind this is quick and dirty code, when the repository is set up we'll look at some production stuff.
James Devlin on Friday, July 10, 2009Lol
Alan Canes on Saturday, July 11, 2009Kudos! Damn good articles. I'd be very interested in learning how to optimize it, e.g. what kinds of isomorphisms exist apart from suit equivalence isomorphisms, any worthwhile checks to detect them, any worthwhile cheap checks for pruning, and (drum roll...) how to implement the GameShrink algorithm to detect any remaining isomorphisms. Also, I'm not sure what the best way is to store the probabilities for which player(s) win/tie in the case of a split pot or multiple split pots (this data would be necessary for GameShrink to work properly, as far as I understand).
Quatari on Sunday, July 12, 2009Thank you in advance!
Could someone help with the VB6 for Poker.Equity.dll
Thank you very much....
RMB on Monday, July 27, 2009somewhere in the header "holdemcalculator.h" this comment is post:
// Write code similar to the following... // // double results[10]; // HoldemEquityCalculator calc; // calc.Calculate("AhKh|Td9s|QQ+,AQs+,AQo+|JJ-88|XxXx|XxXx|XxXx", "Ks7d4d", "", 100000, results); // // Use the | symbol to separate players. Use the comman (,) to separate parts of a single player's // range.
"HoldemEquityCalculator calc;" needs to be: "HoldemCalculator calc;"
I almost committed suicide not finding this error, but that's mainly because I'm a newbie at C++. I hope this post will save some lives. Nevertheless thanks for the calculator!
kasparov on Wednesday, August 05, 2009I've been trying to alter the iterator to make it more easy compatible with my bot (and to avoid strings & chars in cpp, which I guess, you can all understand), but I'm finding it all very confusing and I believe I'm altering a lot more than allowed. Anyway my opponent model is of this format: int Opponentmodel[52][52][2][10][2];// //Opponentmodel[card1][card2][on/off][player][playing/notplaying] int boardcards[5][2];// boardcards[x][0] == cardx //rank board_cards[x][1] == cardx suit
transforming this into a string and then into the struct used for the iteration gives me a lot of trouble, so I was hoping someone could help me out altering the converters for my model?
please reply trough this post,
Regards,
Kasparov
kasparov on Saturday, August 15, 2009Equity calculation when using 5 cards on board returns -1s.
But if last of 5 card is distribution, it's ok.
BOARD: 2h7s9h4hTh - bug BOARD: 2h7s9h4hT - ok BOARD: 2h7s9h4hXx - ok
Anon on Friday, September 04, 2009update: Bug is only in exhaustive mode
Anon on Saturday, September 05, 2009Could someone tell me how to get this code working in VC++ 2008 I have opened the Project, but what now. How can I make my own console testfunction, compile and then uses it? I would just like something like the test Poker.Equity.Test.
Thanks in advance
dk on Tuesday, September 08, 2009I was actually working on a web based fully enumerated multiway hand range evaluator back when you wrote this entry. I didn't read this entry till a couple weeks ago. When I realized that I couldn't realistically enumerate everything on a server, I put the project on hold and eventually just made a limited 2/3 player version.
After reading this entry, I decided to go back and add Monte Carlo simulation for a full 9 player hand range evaluator. It works pretty well on my web server.
So now I have 4 cases: 1) Where I can fully enumerate and have no board/discard cards.
(Can reuse more enumerations. I have some cool hand type compression code.) 2) Where I can fully enumerate and have some board/discard cards. 3) Where I need to use Monte Carlo but can still precompute unique hand combinations. 4) Where I need to use Monte Carlo and can't precompute unique hand combinations.
Thanks for giving me the green light to finish this.
Greg on Friday, September 25, 2009Oh, I forgot the fastest case: 5) If just 2 players and no board/dead cards, just sum up some pre-enumerated hands.
Greg on Friday, September 25, 2009@Greg why not use case 5 for 3 players (one with a known hand)?
use a 169 hand format with two tables, the first showing equity for each scenario and the second showing the number of possible occurances of each scenario.
This way you can do an exhaustive 3-way preflop equity calculation with only 28561 iterations.
I pity your CPU making these tables though.
Paul on Thursday, October 01, 2009sorry a maximum of 28561 iterations
Paul on Thursday, October 01, 2009ask bir hayal izle
ask bir hayal izle on Sunday, October 04, 2009If anyone is interested in doing multi-way analysis using Keith Rule's Evaluator I posted a method that calculates the trial results for a full table of players. It is written in IronPython, but should be pretty simple to convert to C# or VB.NET. I haven't tackled the pocket card selection algorithm yet, but this should be a good start for anyone that need more than just the heads up analysis that is built into the library.
Excellent article by the way... Keep up the great work!
Greg Bray on Monday, November 02, 2009Can I use 64s+ to represent 1 gappers -> 64s, 75s, 86s, 97s, T8s, J9s, QTs, KJs, AQs
Dude on Thursday, November 05, 2009Also, how would I represent say, any TWO cards 7 or higher? (T7, 97, A8, K7, etc)
Dude on Thursday, November 05, 2009I use Exhaustive Enumeration mode to calc, but it's very slow. Why PokerStove can so fast?
Defei Zhu on Tuesday, January 19, 2010Thank you so much James for distributing this code. I have greatly enjoyed working with it on my first HE simulation project. It is very easy to use and quite intuitive and reasonable fast. But after running some lengthy sims, my computer has run out of memory (4Gb)! I have found the memory leak! In HoldemCalculator::CreateHandDistributions(const char* hands) you assign a pointer pCur to a "new" memory location, but never delete it. You can quickly remove this memory leak by adding a function to delete all the elements of m_dists[].
declare the new function in HoldemCalculator.h under public: void deletemdists();
in HoldemCalculator.cpp: void HoldemCalculator::deletemdists() { for (int hand = 0; hand < mdists.size(); hand++) { delete mdists[hand]; } }
And then in your main code, whenever you call calc.MCcalculate or calc.EEcalculate, just call calc.deletemdists() afterwords to free up the assigned memory location.
Now the program runs at a steady 980K and can run days on end! Thanks again for the great code and article and I hope this memory leak catch helps someone else out!
Drew on Friday, January 29, 2010I've found that hands notation differs from PokerStove.
XPokerEquity KJs+ means KJs,AQs PokerStove KJs+ means KJs,KQs
Am I right? Is it bug or feature? Anyway this can lead to unexpected findings when comparing PokerStove with XPokerEquity results.
snow_max on Tuesday, February 09, 2010Nevertheless how to use library Poker.Equity.dll? To include in the project on C# not possible. I at all do not know ?++.
Michael
Anonymous on Thursday, March 04, 2010Hello james, i have been trying to read all your posts last two weeks and finally.....i mean finally understood some stuff to say and code you put!!! Im really thankful to you...you are a very smart and funny person. I was wondering why u didnt update this amazing blog..please...please update it!!!
On other hand...i have a question about your equitycalculator. Why do you think that the already built equitytest.exe run faster than the one I build with the same files you uploaded? I mean...if i run the .exe it runs smooth...but if I rebuild the .exe on my visual studio enviroment...it runs a lot slower....
How can it be possible??? It is a really importat thing to me because I want to do some coding on your source...and when the time to building come..its gonna be a slow program.
Thank you in advance! and again..update you blog. You are a genius man...or at least a very crazy man!!!
Alberto on Saturday, March 06, 2010[i]>I use Exhaustive Enumeration mode to calc, but it's very slow. Why PokerStove can so fast?[/i]
PokerStove is heavily optimized. The source code in this example is a naive approach.
[i]>I've found that hands notation differs from PokerStove.[/i]
Yep. Hand range notation hasn't quite standardized yet, though a little calculator like this should probably follow PokerStove's example. Interestingly though, people have vastly different ideas about what a given hand range signifier actually signifies. :) There was a 2p2 thread on this a while back...
[i]>I have found the memory leak! In HoldemCalculator...[/i]
Awesome! I have had zero time to look at this since I posted it. Thanks to all who contributed code or suggestions, I will bundle these updates and update the source.
[i]>Why do you think that the already built equitytest.exe run faster than the one I build with the same files you uploaded?[/i]
Are you building in Release mode? (rather than Debug?)
James Devlin on Saturday, March 06, 2010Does anyone have the declare statement for VB6? Also I have a working VB model for the 2+2 calc to post if anyone is interested.
thanks
RMB on Sunday, March 21, 2010@Drew
I'm also using this in a small project I'm working on. Thanks so much for posting the memory leak you found. I'll definitely use it (although I couldn't confirm the bug or the fix so far).
James, excellent work. When can we expect an improved version of this to be posted? I'm really looking forward to see it.
Anonymous on Sunday, March 28, 2010Does anyone have a good solution to enter in any hand with a specific card? For example, opponent shows me that he has the 5 of clubs, how do I evaluate my hand verses all hands that contain the 5 of clubs?
@Anonymous The memory leak only posed a problem when I was running the program for 3+ hours. Also, my solution to it is basic and could probably be implemented in a better way (I haven't used C++ in 7 years, but this was a good refresher). When you run the program, open the task manager and track the memory usage of the program. It should be pretty constant, if it is at all going up then the memory leak is still present. I really would not worry about it unless you are running the program for many hours or have a low memory computer. Goodluck with your project!
Thanks again James for the code.... it has been quite profitable :)
Drew on Sunday, April 04, 2010This has to be a bug. If anybody could please help me figure out whats going on here, it would be greatly appreciated.
Player 1: 72.34% [AA] Player 2: 27.66% [KK+]
Ran 1000000 trials via Monte Carlo.
Player 1: 77.38% [AA] Player 2: 22.62% [KK+]
Ran 71916768 trials via exhaustive enumeration.
ClockTime: 48.867000
All tests concluded with 2 errors.
Anonymous on Wednesday, April 21, 2010Hi Anonymous, not that my code isn't as buggy or buggier than the next guy's, but I think those are the correct percentages. (Verified against PokerStove, anyway.) You're running AA agnostic vs. KK+ agnostic. In other words, you're running
vs.
The KK+ gets some additional equity because he will sometime have AA as well. If you intended to do a standard AA vs KK matchup, remove the + from the KK. Not sure if that's the problem you're seeing, but that little "+" can be easy to miss.
James Devlin on Wednesday, April 21, 2010Thanks for the quick reply.
I am indeed looking at AA|KK+ and not AA|KK. I understand that KK+ gets addition equity since AA is also in range. But here is the problem.
1) The results differ from pokerstove. The exhaustive calculation is 100% accurate. However, the monte-carlo calculation differs from pokerstove by 5% with 1,000,000 itterations.
PokerStove Monte-Carlo
Text results appended to pokerstove.txt
11,168,949 games 6.633 secs 1,683,845 games/sec
Board: Dead:
Hand 0: 77.398% 70.38% 07.03% 7860319 785360.50 { AA } Hand 1: 22.602% 15.57% 07.03% 1739431 785374.50 { KK+ }
PokerStove Exhaustive Enumeration
Text results appended to pokerstove.txt
71,916,768 games 0.041 secs 1,754,067,512 games/sec
Board: Dead:
Hand 0: 77.382% 70.35% 07.03% 50594604 5056266.00 { AA } Hand 1: 22.618% 15.59% 07.03% 11209632 5056266.00 { KK+ }
2) As monte-carlo #iterations -> infinity these equities should obviously be identical. We have a 5% discrepancy after 1,000,000 iterations.
~~~~~~~~~~~~~~~~~~~~~~ The KK+ range is receiving more win% equity than it should. I looked at the hand selection algorithm with the circular linked list implementation but could not see anything blatantly incorrect (ie. if AA was selected more often often than KK which would naturally improve equity). It also seemed like the selected cards were appropriately added to the deadcards mask.
So basically, I'm lost.
Anonymous on Wednesday, April 21, 2010Ah, I see what you're saying. I missed the differences in your first set of results.
I'm looking into this. Quite a few improvements and several bug fixes have been suggested in the comments and over email, time I incorporated those and got this code somewhat production-ready, even though this was never intended to be a production evaluator/calculator. Look for a Google code drop soon (I'll post about it as well.)
In the meantime, the Keith Rule evaluator is a great choice, and it's been tested/used and is fairly mature. I'd still recommend that, as opposed to this, for production work. Just make sure to grab the latest version.
James Devlin on Thursday, April 22, 2010Thanks a lot for the advice on the Keith Rule evaluator. I'll be checking it out asap.
The reason i'm being quite anal about this is because I think it's hard enough to properly identifying opponents' hand ranges. Coupled with discrepancies / incorrect equity calculations and EV miscalculations are amplified.
Anonymous on Thursday, April 22, 2010For real-time 3-way+ pre-flop equity calculations, I'm forced to use a Monte-Carlo computation because EE takes too long (especially if multiple EE calculations are done to compute a final decision).
The only way to use EE effectively would be to create an equity lookup table for O(1) retrieval. However, creating the lookup table for all combinations of 3-way pre-flop hands would take months to build and would be around 8 gb. So that really isn't an option either.
Keep in mind, I'm only looking for pre-flop equities (3-way).
Keith Rule's evaluator, from what I have seen so far, only performs exhaustively enumerated calculations, and does not have a native monte-carlo evaluator.
Is there a production monte-carlo evaluator with source available?
WindForce on Thursday, April 22, 2010AA vs KK+ bug is posed by hand selection algo.
When evaluation runs, it cycles player, which first receives holecards. So for 2 players we have two different situations
1)first dealt player is "AA player". He gets his AA and "KK+ player" chooses exactly from 7 possible combinations for him - one AA and 6 KK. So you can see that he receives AA only one time out of 7
2)first dealt player is "KK player". Now he can choose from 12 possible combos - 6 AA and 6 KK. So you will not be surprised that he will get AA 50% of time.
You can comment out first player cycling in code:
//pFirstToDraw = pDist->Next();
Than you will get exact result by MC as calculated by EE if set first player as AA:
performMatchup("AA|KK+", "", NULL, numberOfTrials, true, expected);
and 10% different result if set first player as KK+.
performMatchup("KK+|AA", "", NULL, numberOfTrials, true, expected);
and you get 5% difference with player cycling, which is obviously now why.
Though I don't know how that can be fixed in arbitrary way in code.
Regards.
Alex on Wednesday, May 19, 2010I love these articles. Great work.
I think the method for handling collisions is not right. Even with the round-robin rotation.
Let's say player 1 can have hands A and B, and player 2 can have hands C, D, and E. Then there are six possibilities: AC, AD, AE, BC, BD, BE
Now let's say hands B and C are mutually impossible and hands B and D are also mutually impossible. The results should be AC, AD, AE, BE, each with 25% likelihood
If you choose player 1 first and then player 2 from the remaining possible choices, you get A (1/2 of the time) with C, D, E equally likely so AC, AD, and AE each at 1/6 B (1/2 of the time) with E, so BE at 1/2
Then player 2 followed by player 1 you get C (1/3) with A, so AC at 1/3 D (1/3) with A, so AD at 1/3 E (1/3) with A or B, so AE and BE each at 1/6
So the total likelihood is AC: (1/6+1/3)/2 = 1/4 AD: (1/6+1/3)/2 = 1/4 AE: (1/6+1/6)/2 = 1/6 BE: (1/2+1/6)/2 = 1/3
The round robin does help, but it is still uneven due to partial collisions.
Instead of picking from the available cards, you could pick from the entire hand distribution and in case of a collision, discard the entire sample and start over from the first player. You should get accurate results then, and you wouldn't need round robin starting points either. You would discard more samples due to collision, but I'm not sure there's a way around it.
If the hole card combinations are few enough to make frequent collisions a problem, you could enumerate all the hole card combinations, select one from the list at random, and then play out a random board.
Jamie on Tuesday, June 29, 2010This seems interesting. logo design
Summer on Wednesday, June 30, 2010When I try to evaluate on the river (say KsKd|XxXx, with a board of AsTs9s3d4c), Xpoker equity returns "nan" as a result... has this bug been fixed yet, or does XPE not work on the river at all?
Thanks!
pandemik on Saturday, July 10, 2010Thank you for share with us,I like Wholesale Chanel.especially Chanel Bracelet,Guess Men's Watches,Longines Watches,D&G ladies watches,Breitling,Cheap Chanel handbags,Chanel handbags for cheap,it is good. MBT shoes,MBT Men's Shoes,Five fingers,it is good.
cheap chanel on Monday, July 12, 2010Life will change what you are but not who you are;
Blu-ray Ripper on Tuesday, July 20, 2010Marry a person who likes talking; because when you get old, you’ll find that chatting to be a great advantage
blu-ray ripper on Tuesday, July 20, 2010nice article. keep post like this...
Fendi replica watches on Tuesday, July 20, 2010PerformingGraham for sale that will create a one-wayswiss watches backlink to your website whichMaurice Lacroix watches is a good point to have. It is Patek Philippe watchesa time-consuming Tag Heuer for saleprocess even though it produces good outcomes U-boat for saleand works. You can also swiss watchespost comments on blogs alongMaurice Lacroix watches together with your link, but make sureGraham watches these blogs are do-follow, which dolce & gabbana handbagsindicates the link that youreplica coach handbags simply post will probably be replica handbagscounted by the search engines jimmy choo replicaas a backlink.There are many thingsversace replica handbags that contribute to online businessjuicy couture replica failure, and the lack of good action thomas wyldeis surely one of the deadliest business-killersdolce gabbana handbags on the net. Take action like by no means chloe handbags replicaprior to, and don’t get struck by analysis paralysisburberry replica. Your achievement lies in your rapid actionchanel replica and how well you apply numerous strategies.
replica watches on Saturday, July 24, 2010nike air jordan 2010 nike air jordan 5 nike air jordan 3 nike air jordan 11 cheap nike air jordan 2 nike air jordan 1 nike air jordan shoes discount nike air jordan shoes nike air jordan 6 wholesale nike air jordan 1 discount nike air jordan 6 nike air jordan 7 nike air jordan 8 top quality nike air jordan shoes 23 nike air jordan 21 nike air jordan 22 nike air jordan 6 rings cheap nike air jordan 22 nike air lebron james shoes nike air lebron james shoes nike air jordan 2010 nike air joredan lebron james nike air jordan 2009 discount nike air jordan 2009 nike lebron james wholesale nike air jordan 2010 cheap nike air jordan 2009 discount nike air jordan 19 cheap nike air jordan 3 discount nike air jordan 18 brand nike air jordan 12 wholesale nike air jordan 2 nike air jordan 13 nike air jordan 14 nike air jordan 6 rings discount jordan shoes7 discount jordan shoes1 jordan shoes2010 jordan shoes 6 rings cheap jordan shoes2 discountjordan shoes3 discount jordan shoes4 jordan shoes uk23 jordan shoes classic bw22 cheap jordan shoes 21 ltd discount jordan shoes20 discountjordan shoes19 jordan shoes 18 uk nike air jordan shoes 17 cheap nike air jordan shoes 16 discount air jordan shoes 15 discount air jordan shoes 14 nike air jordan shoes 3 uk nike air jordan shoes 13 cheap nike air jordan shoes 11 discount air jordan shoes 6 discount jordan shoes 10 nike air jordan shoes 8 nike air jordan shoes 7 cheap louis vuitton bags cheap kobe bryant shoes cheap lebron james shoes .
cheapjordan on Saturday, July 24, 2010I will keep visiting this blog very often. Blu ray ripper /
ipad converter on Sunday, July 25, 2010The variety links of london items bearing depends on the occasion. You are plain, but you are elegant. links of London sweetie braceletIf presence a groove, especially nightfall outfit, you are allowed to be very gentle in truth. What you should do is to links of london charms choose some delicate sweetie bracelets with your subtle sensation of fashion on Christmas Day, Easter, Halloween and Valentines Day. Discovering links of London friendship bracelet on the net is an excellent choice for your needs and can also assure you may benefit from the best insurance coverage at the best price tag. The links of London braceletis one kind of those brands that basically level the start a time honored design and style and design untreated. links of london necklace and links of london earringswill be the consultant of level and higher personal taste; so many people contain the hopes for donning links of London sweetie bracelets. Nevertheless, in the large price, so most of us cannot pay the big money. links of London friendship bracelets charm bracelets links of london sale charm bracelet silver friendship bracelets links of london charm bracelet
links of london on Monday, July 26, 2010ed hardy, cheap ed hardy, ed hardy clothing, ed hardy outlet, ed hardy jeans, ed hardy bags, ed hardy swimwear, ed hardy shirts, ed hardy tee, ed hardy caps, ed hardy purse, ed hardy board shorts, ed hardy shoes, ed hardy for men, ed hardy for women, ed hardy jeans for women.
cheap ed hardy on Tuesday, July 27, 2010ed hardy, cheap ed hardy, ed hardy clothing, ed hardy outlet, ed hardy jeans, ed hardy bags, ed hardy swimwear, ed hardy shirts, ed hardy tee, ed hardy caps, ed hardy purse, ed hardy board shorts, ed hardy shoes, ed hardy for men, ed hardy for women, ed hardy jeans for women.
cheap ed hardy on Tuesday, July 27, 2010It is your best choice which can help you perfectly resolve those problems without limitation.
5.11 tactical series on Wednesday, July 28, 2010It is your best choice which can help you perfectly resolve those problems without limitation.
military supply on Wednesday, July 28, 2010Wholesale NFL Jerseys
Cheap NFL Jerseys
NFL Jerseys
NFL Football Jerseys
Women NFL Jerseys
Kid NFL Jerseys
Super Bowl Jerseys
Super Bowl NFL Jerseys
Throwback Jerseys
Throwback NFL Jerseys
Cheap Throwback Jerseys
Wholesale Throwback Jerseys
Cheap Super Bowl Jerseys
Wholesale Super Bowl Jerseys
youth nfl jerseys wholesale
youth nfl jerseys cheap
nfl youth jerseys
Baltimore Ravens Jerseys
Chicago Bears Jerseys
Cincinnati Bengals Jerseys
Denver Broncos Jerseys
Dallas Cowboys Jerseys
Green Bay Packers Jerseys
Indianapolis Colts Jerseys
Minnesota Vikings Jerseys
New England Patriots Jerseys
New Orleans Saints Jerseys
New York Jets Jerseys
Arizona Cardinals Jerseys
Buffalo Bills Jerseys
Atlanta Falcons Jerseys
Carolina Panthers Jerseys
Cleveland Browns Jerseys
Houston Texans Jerseys
Detroit Lions Jerseys
Jacksonville Jaguars Jerseys
Kansas City Chiefs Jerseys
Miami Dolphins Jerseys
New York Giants Jerseys
Philadelphia Eagles Jerseys
San Francisco 49ers Jerseys
Oakland Raiders Jerseys
Seattle Seahawks Jerseys
Pittsburgh Steelers Jerseys
St Louis Rams Jerseys
San Diego Chargers Jerseys
Tampa Bay Buccaneers Jerseys
Tennessee Titans Jerseys
Washington Redskins Jerseys
Ray Lewis Jerseys
Ed Reed Jerseys
Joe Flacco Jerseys
Terrell Suggs Jerseys
Dick Butkus Jerseys
Greg Olsen Jerseys
Matt Forte Jerseys
Devin Hester Jerseys
Walter Payton Jerseys
Brian Urlacher Jerseys
Lance Briggs Jerseys
Jay Cutler Jerseys
Carson Palmer Jerseys
Rey Maualuga Jerseys
Chad Johnson Jerseys
Demarcus Ware Jerseys
Jason Witten Jerseys
Terrell Owens Jerseys
Felix Jones Jerseys
Marion Barber Navy Jerseys
Marion Barber Jerseys
Emmitt Smith Jerseys
Miles Austin Jerseys
Roger Staubach Jerseys
Troy Aikman Jerseys
Tony Romo Jerseys
Eddie Royal Jerseys
Brandon Marshall Jerseys
Aaron Rodgers Jerseys
A.J. Hawk Jerseys
Donald Driver Jerseys
Greg Jennings Jerseys
Peyton Manning Jerseys
Dallas Clark Jerseys
Robert Mathis Jerseys
Marvin Harrison Jerseys
Drew Brees Jerseys
Marques Colston Jerseys
Pierre Thomas Jerseys
Reggie Bush Jerseys
Jeremy Shockey Jerseys
Tarvaris Jackson Jerseys
Adrian Peterson Jerseys
Jared Allen Jerseys
Mark Sanchez Jerseys
Thomas Jones Jerseys
Leon Washington Jerseys
Brett Favre Jerseys
buynflshop on Thursday, July 29, 2010Thank you for sharing with us,i like it very much and i will always give attention. Welcome to say something about my recent shopping experience: guess men's watches Guess watches is about sexy, adventurous, trendsetting apparel and accessories; all-American looks, with a uniquely European attention to detail. People, who know fashion, know Guess.
guess men's watches on Friday, July 30, 2010Thank you for sharing.I like 铁观音
tea on Friday, July 30, 2010essay essay writing essay writing service essay writing service uk
jane on Friday, July 30, 2010Pool Temperature Madera Jobs Madera Pest Control Madera Dentist Merced Dentist Visalia Dentist Modesto Dentist Fresno Limousine Fresno Granite briefcases leather leather briefcases prospect solution | prospect solutions | prospectsolution | prospectsolutions | prospectsolution.com prospect solution | prospect solutions | prospectsolution | prospectsolutions | prospectsolution.com prospect solution | prospect solutions | prospectsolution | prospectsolutions | prospectsolution.com
carmi on Friday, July 30, 20102010 chanel handbags hot sale on buybury.com, you can discover all kinds of fashion chanel handbags in free shipping worldwide, and buybury.com provide chanel bags are all 70% discount, that attracted numerous chanel funs, and you can place an order for cheap chanel handbags will have the same discount. If you are looking for chanel handbags now, do not hesitate, chanel hobos on our site is really noble but cheaper. All chanel bags really are wonderful.
chanel handbags on Friday, July 30, 2010Replica miu miu handbags are not just beautiful and elegant, but it is also at excellent quality and similar design as the real. You will like it once you see it. Now attention please, at our shop, we are holding a promotion. You can buy replica miu miu bags of high quality with the lowest price. Meanwhile, miu miu handbags buying from here you can enjoy free and fast delivery shipping. Welcome to our shop!
miu miu bags on Friday, July 30, 2010Want to get Ed hardy at home? No hesitation, get them at with big discount. We are promise you that all the ed hardy clothing are good in qualities. Meanwhile, buying ed hardy clothing online, that’s never a bad idea. By the way, whenever and wherever you need us, we will be there for you. Ed Hardy T-Shirts are waiting for you now, welcome you!
ed hardy on Friday, July 30, 2010