/// <summary> /// <para>This method calculates chances of our hand to win and based on the results returns values, which to be used for decisionmaking</para> /// <para>Used methods to calculate chances:</para> /// <para>-> for pre-flop: uses the gap parameter and checkes wether we have High Card or a Pair</para> /// <para>-> for all other rounds: uses MonteCarlo algorythm on 250 game trials, which is with diff: (3 to 2.5)</para> /// </summary> /// <param name="ourCards"><c>string</c> that contains our cards <example>example: "2h 3h"</example></param> /// <param name="communityCards"><c>string</c> that contains the community cards <example>example: "Jh Qh 2d"</example></param> /// <param name="currentRound"><c>GameRoundType</c> is enum that informs us in which round are we currently playing <example>example: GameRoundType.PreFlop</example></param> /// <param name="gapBetweenOurCards"><c>int</c> that informs us what is the gap between the cards in our hand /// <example>example: If we have Jack and 8 -> gap = 2, /// If we have King and 6 -> gap = 6</example></param> /// <returns><c>Turn</c> object that holds the chance values for Fold, Call, Raise and AllIn</returns> /// <seealso cref="http://www.codeproject.com/Articles/19092/More-Texas-Holdem-Analysis-in-C-Part-2"/> public Turn DecideChanceForAction(string ourCards, string communityCards, GameRoundType currentRound, int gapBetweenOurCards) { var output = new Turn(); var ourHand = new Hand(ourCards, communityCards); int chance = 0; switch (currentRound) { case GameRoundType.PreFlop: if (gapBetweenOurCards >= 4) { this.Call++; this.Fold++; } else if (gapBetweenOurCards >= 2) { this.Raise++; this.Call++; } else { this.AllIn++; this.Raise++; } var handTypeValue = ourHand.HandTypeValue; switch (handTypeValue) { case Hand.HandTypes.HighCard: this.Raise++; this.Call++; break; case Hand.HandTypes.Pair: this.AllIn++; this.Raise++; this.Call++; break; default: this.Raise++; this.Call++; this.Fold++; break; } break; case GameRoundType.Flop: chance = MonteCarloAnalysis.WinOddsMonteCarlo(ourCards, communityCards); if (chance > 16 && chance <= 34) { this.Call++; this.Fold++; } else if (chance > 34 && chance <= 40) { this.Raise++; this.Call++; } else if (chance > 40 && chance <= 51) { this.AllIn++; this.Raise++; this.Call++; } else if (chance > 51) { this.AllIn++; this.Raise++; } else { this.Fold++; } break; case GameRoundType.Turn: chance = MonteCarloAnalysis.WinOddsMonteCarlo(ourCards, communityCards); if (chance > 18 && chance <= 34) { this.Call++; this.Fold++; } else if (chance > 34 && chance <= 41) { this.Raise++; this.Call++; } else if (chance > 41 && chance <= 55) { this.AllIn++; this.Raise++; this.Call++; } else if (chance > 55) { this.AllIn++; this.Raise++; } else { this.Fold++; } break; case GameRoundType.River: chance = MonteCarloAnalysis.WinOddsMonteCarlo(ourCards, communityCards); if (chance > 20 && chance <= 36) { this.Call++; this.Fold++; } else if (chance > 36 && chance <= 45) { this.Raise++; this.Call++; } else if (chance > 45 && chance <= 62) { this.AllIn++; this.Raise++; this.Call++; } else if (chance > 62) { this.AllIn++; this.Raise++; } else { this.Fold++; } break; } return(output); }
public override PlayerAction GetTurn(GetTurnContext context) { #region PreFlopLogic if (context.RoundType == GameRoundType.PreFlop) { //checks if we have the button if (context.MyMoneyInTheRound == context.SmallBlind) { hasTheButton = true; } //checks if 3bettedPot; If the pot is big it is! if (context.CurrentPot > (context.SmallBlind * 4)) { is3bettedPot = true; } var playHand = HandStrengthValuation.PreFlop(this.FirstCard, this.SecondCard, hasTheButton); //http://www.holdemresources.net/h/poker-theory/hune/usage.html #region mFactor< 20 if (mFactor < 20) { double nashEquillibriumRatio = 0; if (hasTheButton) { nashEquillibriumRatio = HandStrengthValuation.GetPusherBlindsCount(this.FirstCard, this.SecondCard); } else { nashEquillibriumRatio = HandStrengthValuation.GetCallerBlindsCount(this.FirstCard, this.SecondCard); } //find if we have less money then the effective stack size bool push = context.MoneyLeft <= (nashEquillibriumRatio * (context.SmallBlind * 2)); if (push) { return(PlayerAction.Raise(context.CurrentMaxBet)); } else { if (context.CanCheck) { return(PlayerAction.CheckOrCall()); } else { return(PlayerAction.Fold()); } } } #endregion #region UnplayableHands if (playHand == CardValuationType.Unplayable) { if (context.CanCheck) { return(PlayerAction.CheckOrCall()); } else { return(PlayerAction.Fold()); } } #endregion // raises risky hands only if in position and if it is not a 3betted Pot if (playHand == CardValuationType.Risky && context.MyMoneyInTheRound == context.SmallBlind) { // var smallBlindsTimes = RandomProvider.Next(1, 8); return(PlayerAction.Raise(context.SmallBlind * 6)); } // folds if not in position else if (playHand == CardValuationType.Risky && !hasTheButton) { if (context.CanCheck) { return(PlayerAction.CheckOrCall()); } else { return(PlayerAction.Fold()); } } // if recommended and not in 3bettedPot and a big M RAISES if (playHand == CardValuationType.Recommended) { if (is3bettedPot && mFactor > 100) { return(PlayerAction.CheckOrCall()); } if (is3bettedPot && mFactor > 200) { return(PlayerAction.Fold()); } // var smallBlindsTimes = RandomProvider.Next(6, 10); return(PlayerAction.Raise(context.SmallBlind * 6)); } //needs refactoring if (playHand == CardValuationType.Premium || playHand == CardValuationType.TopPremium) { if (playHand == CardValuationType.TopPremium) { hasTopPremium = true; return(PlayerAction.Raise(context.SmallBlind * 10)); } if (playHand == CardValuationType.Premium) { return(PlayerAction.Raise(context.SmallBlind * 10)); } } // not sure if this doesn't brake everything if (context.CanCheck) { return(PlayerAction.CheckOrCall()); } // not sure if this doesn't brake everything else { return(PlayerAction.Fold()); } } #endregion #region Post-FlopLogic double currentPotRaise = context.CurrentPot * 0.55; int currentPotRaiseInt = (int)currentPotRaise; List <Card> allCards = new List <Card>(this.CommunityCards); allCards.Add(this.FirstCard); allCards.Add(this.SecondCard); HandRankType type = HandEvaluator.GetBestHand(allCards).RankType; var playerFirstHand = ParseHandToString.GenerateStringFromCard(this.FirstCard); var playerSecondHand = ParseHandToString.GenerateStringFromCard(this.SecondCard); string playerHand = playerFirstHand + " " + playerSecondHand; string openCards = string.Empty; foreach (var item in this.CommunityCards) { openCards += ParseHandToString.GenerateStringFromCard(item) + " "; } var chance = MonteCarloAnalysis.CalculateWinChance(playerHand, openCards.Trim()); int Check = 15; int Raise = 60; int AllIn = 85; if (context.MoneyToCall <= (context.SmallBlind * 2)) { return(PlayerAction.CheckOrCall()); } if (chance < Check) { return(PlayerAction.Fold()); } if (chance < Raise) { return(PlayerAction.CheckOrCall()); } else if (chance < AllIn) { if ((int)type >= (int)HandRankType.Pair) { return(PlayerAction.Raise(currentPotRaiseInt)); } else { return(PlayerAction.Raise(context.SmallBlind * 4)); } } else { return(PlayerAction.Raise(context.CurrentMaxBet)); } }