PokerEngine is a deterministic poker rules engine written in C#.
- No-Limit Texas Hold'em
- Manual and automatic dealing
- Blinds, antes, straddles, and extra blinds
- Betting validation
- All-ins and side pots
- Uncalled bet returns
- Multiple boards and runouts
- Hand evaluation
- Event-based hand history
- Real-hand replay tests
The project is under active development. The public API may change before version 1.0.0.
Planned support:
- Pot-Limit Omaha
- Fixed-Limit games
- NuGet distribution
- .NET 10 SDK
dotnet restore
dotnet build
dotnet testIn manual mode, the caller posts blinds and deals cards.
using PokerEngine.Enums;
using PokerEngine.Games;
using PokerEngine.States;
IPokerGame game = new NoLimitTexasHoldem(
automation: Automation.None,
smallBlind: 100,
bigBlind: 200);
IPokerState state = game.CreateState();
state.Initialize([10_000, 10_000, 10_000]);
state.PlayerPost(0, PostType.SmallBlind, 100);
state.PlayerPost(1, PostType.BigBlind, 200);
state.Start();
state.DealHole(0, ["As", "Ad"]);
state.DealHole(1, ["Kh", "Qh"]);
state.DealHole(2, ["7c", "7s"]);
// Preflop
state.PlayerAction(2, ActionType.RaiseTo, 600);
state.PlayerAction(0, ActionType.Call);
state.PlayerAction(1, ActionType.Call);
// Flop
state.DealBoard(0, ["2c", "7d", "Jh"]);
state.PlayerAction(0, ActionType.Check);
state.PlayerAction(1, ActionType.Check);
state.PlayerAction(2, ActionType.Check);
// Turn
state.DealBoard(0, ["Qs"]);
state.PlayerAction(0, ActionType.Check);
state.PlayerAction(1, ActionType.Check);
state.PlayerAction(2, ActionType.Check);
// River
state.DealBoard(0, ["9c"]);
state.PlayerAction(0, ActionType.Check);
state.PlayerAction(1, ActionType.Check);
state.PlayerAction(2, ActionType.Check);
//History
Console.WriteLine("*** HISTORY ***");
foreach (var e in state.Events)
{
Console.WriteLine($"{e}");
}In automatic mode, the engine posts blinds, shuffles the deck, and deals cards.
Player decisions are still passed through PlayerAction.
using PokerEngine.Enums;
using PokerEngine.Games;
using PokerEngine.States;
IPokerGame game = new NoLimitTexasHoldem(
automation: Automation.All,
smallBlind: 100,
bigBlind: 200);
IPokerState state = game.CreateState();
state.Initialize([10_000, 10_000, 10_000]);
state.Start();
// Preflop
state.PlayerAction(2, ActionType.RaiseTo, 600);
state.PlayerAction(0, ActionType.Call);
state.PlayerAction(1, ActionType.Call);
// Flop
state.PlayerAction(0, ActionType.Check);
state.PlayerAction(1, ActionType.Check);
state.PlayerAction(2, ActionType.Check);
// Turn
state.PlayerAction(0, ActionType.Check);
state.PlayerAction(1, ActionType.Check);
state.PlayerAction(2, ActionType.Check);
// River
state.PlayerAction(0, ActionType.Check);
state.PlayerAction(1, ActionType.Check);
state.PlayerAction(2, ActionType.Check);
//History
Console.WriteLine("*** HISTORY ***");
foreach (var e in state.Events)
{
Console.WriteLine($"{e}");
}All state changes and hand results are stored in state.Events.
foreach (PokerHandEvent handEvent in state.Events)
{
Console.WriteLine(handEvent);
}For example, pot winners can be read from PotAwardedEvent:
foreach (PotAwardedEvent award in state.Events
.OfType<PotAwardedEvent>())
{
Console.WriteLine(
$"Seat {award.SeatId} won {award.Amount} chips.");
}A completed hand emits EndHandEvent.
Cards use two-character notation:
As = ace of spades
Kd = king of diamonds
Th = ten of hearts
2c = two of clubs
PokerEngine includes a Texas Hold'em hand evaluator that selects the strongest five-card combination from the player's hole cards and the board.
using PokerEngine.Evaluation;
IHandEvaluator evaluator = new TexasHoldemEvaluator();
HandRank result = evaluator.Evaluate(
holeCards: ["As", "Ks"],
boardCards: ["Qs", "Js", "Ts", "2d", "3c"]);
Console.WriteLine(result.Category);
Console.WriteLine(result.Strength);
Console.WriteLine(string.Join(", ", result.Cards));This project is licensed under the MIT License.
