2013-05-01

General

A DSL for Poker – On Achieving Your Dreams

Six years ago, I saw some source code that has stayed with me ever since. It was a piece of Erlang code that described the game of Texas Hold’em poker. What struck me was the beautiful simplicity in that it described exactly the rules of poker and nothing else. This was very different from the legacy poker system I wrestled with at the time. I decided then and there to set a goal to create “a card rules engine”. I even added this goal to a website which kept sending me emails nagging about this goal.

I tried some different things over the years, first I toyed with the idea of describing card games as a state machine. I even implemented the basics of Texas Hold’em in UniMod. That quickly got very messy, mostly because of all the special cases but also because it’s actually quite hard to reuse a sub state machine from the outer state machine.

I also considered modelling poker as rules with a rules engine (Drools to be specific). It seems to make sense, poker is a set of rules and a rules engine takes a set of rules and a set of facts and applies these rules. However, these rules engines are meant for “business” rules, meaning they will help you apply the right insurance premium or offer the correct rebate on your order. Having a system where “any” matching rule will fire does not make for very predictable gameplay. In other words, it’s just a bad match.

For a while it seemed like my dream to create “a card rules engine” would remain just that (it was also a case of the goal not being SMART, but I digress). During the last year and a bit, I have found myself writing poker code from scratch again, this time working on Cubeia’s social poker network. As always, there were deadlines and requirements, so I could not sit around and polish on this ivory tower dream of mine. I did however apply a lot of the good design principles I had picked up over the years, mostly from my man crush Miško Hevery.

The key principles in this case were “design for testability” (with the help of TDD) and “composition over inheritance“. And so one evening it hit me that going from where I was to a DSL for poker would not even be a lot of work. So I sat down and spent just over one day before my new and shiny DSL for poker saw the light. Here’s what the definition of Texas Hold’em looks like with this DSL:

[code lang=”java”]
public static GameType createTexasHoldem() {
return new PokerGameBuilder().withRounds(
blinds(),
dealFaceDownCards(2),
bettingRound(PRE_FLOP, fromBigBlind()),
dealCommunityCards(3),
bettingRound(FLOP),
dealCommunityCards(1),
bettingRound(TURN),
dealCommunityCards(1),
bettingRound(RIVER)).build();
}
[/code]

and here’s what Omaha would look like:

[code lang=”java”]
public static GameType createOmaha() {
return new PokerGameBuilder().withRounds(
blinds(),
dealFaceDownCards(4),
bettingRound(PRE_FLOP, fromBigBlind()),
dealCommunityCards(3),
bettingRound(FLOP),
dealCommunityCards(1),
bettingRound(TURN),
dealCommunityCards(1),
bettingRound(RIVER)).
withHandEvaluator(new OmahaHandEvaluator()).build();
}
[/code]

You get the idea (the entire code is available from Cubeia’s open source poker repo on BitBucket). Having now achieved this goal of mine I felt very proud and slightly embarrassed that it took me so long to get there.

My takeaway from this and the message I want impress on you is to never give up on your goal and most of all to not get stuck searching for the “one grand unified model” as I did which easily gets you stuck in “analysis paralysis“, but rather break the problem down into pieces and apply adequate design principles to each part.

I hope this gets you motivated to achieve your goal!

Viktor Nordling