views:

235

answers:

2

I'm writing a poker framework in C# and I don't like the design I currently have. My goal is to have a game engine that can play a multiple AI against each other in batch mode very quickly, play multiple AI vs. multiple humans (probably via a Silverlight client). I'd like to keep efficiency high but maintain game support flexibility-- e.g., it should be able to play games like Limit Hold'em, No-Limit Hold'em, Limit 7-card Stud, etc.

My current design is rather clunky and inflexible:

  • HandHistory: Contains all the information about the current hand (players in, bets made, etc.)
  • IPlayer: Every player defines a GetAction(HandHistory history) method.
  • GameEngine: Defines a Play(HandInfo info) method that returns a HandHistory object.
  • PotManager: Manages the pot and determines how much each player has to call and how much they can win (e.g., if they have unequal stacks).
  • BetManager: Manages the bets and determines when a betting round is finished.

The HandInfo class contains all the information about how to setup the hand. The Play method then looks something like this:

HandHistory Play(HandInfo info)
{
    PotManager pots = new PotManager(info);
    BetManager bets = new BetManager(info);
    HandHistory history = CreateHistory(info);

    bets.CollectBlinds();
    if(!bets.GameOver)
    {
        DealHoleCards();
        if(bets.PlayersThatCanStillBet > 1)
            bets.CollectBets();
        if(!bets.GameOver)
        {
            DealFlop();
            ... and on and on
        }
    }

    return history;
}

The problems arise because there are so many little things to consider like collecting the blinds, etc. The Pot and Bet manager classes become a nightmare and are invariably riddled with bugs. Also, my engine design only supports one game type (Hold'em) as opposed to others.

My main ranking is first for efficiency, as the engine is used primarily as an AI simulator over billions of hands. However, I'd like to think there is a more elegant way that this could be done.

A: 

I really liked the interface IOpponent that was written by John Gietzen for the Battleship AI tourney. I would take a look at his framework for some inspiration.

http://stackoverflow.com/questions/1631414/what-is-the-best-battleship-ai

Oh and I recently saw this: http://visualstudiogallery.msdn.microsoft.com/en-us/ba4638ad-a2d2-49e5-ae46-94e0f747cae0?SRC=VSIDE

itchi
+2  A: 

My first thought is, code for readability and lack of redundancy first, and optimize for performance (which I assume is what you mean by efficiency) last. It is usually hard to foresee where the performance bottle necks will be, and a slightly slower app is better than a buggy or unmaintainable system. It's easy to use a product like dotTrace when you're ready to optimize, if you find it isn't fast enough.

Regarding your desire to add functionality, I recommend becoming better at refactoring. That's one of the core priciples of TDD: write the least amount of code to complete a piece of functionality, then refactor out any code smells. And by using TDD, you can make sure that when you implement, say, Stud, your Hold'em still works.

A good place to start with your refactoring, since it sounds like you are already running into maintainability issues, is to try to ensure each class has a single responsibility (the first of the SOLID priciples). Your example method has many responsibilities: betting, dealing, game history, etc.

Lachlan
In addition to @Lachlan's post above I would suggest optimizing for lack of redundancy.
Lawrence Johnston