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 multiple AI agents against each other in batch mode very quickly, and play multiple AI agents vs. multiple humans (probably via a Silverlight client). I'd like to keep efficiency high but maintain 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:
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With