/* Certain statistics are round specific (for example a person can only limp once per round) * This function should get called at the beginning of a new round */ public override void PrepareStatisticsForNewRound() { base.PrepareStatisticsForNewRound(); IsBigBlind = false; IsSmallBlind = false; IsButton = false; limps.AllowIncrement(); limpsDetails.AllowIncrement(); voluntaryPutMoneyPreflop.AllowIncrement(); raises.AllowIncrement(); raisesRatings.AllowIncrement(); bets.AllowIncrement(); betsRatings.AllowIncrement(); cbets.AllowIncrement(); stealRaises.AllowIncrement(); foldsToAStealRaise.AllowIncrement(); callsToAStealRaise.AllowIncrement(); raisesToAStealRaise.AllowIncrement(); folds.AllowIncrement(); calls.AllowIncrement(); callsRatings.AllowIncrement(); checkRaises.AllowIncrement(); checksRaisesRatings.AllowIncrement(); checkFolds.AllowIncrement(); checkCalls.AllowIncrement(); checksCallsRatings.AllowIncrement(); checks.AllowIncrement(); checksRatings.AllowIncrement(); sawStreet.AllowIncrement(); wentToShowdown.AllowIncrement(); wonAtShowdown.AllowIncrement(); pushedAllIn.AllowIncrement(); totalAllIns.AllowIncrement(); draws.AllowIncrement(); foldsBlindToAPreflopRaise.AllowIncrement(); callsBlindToAPreflopRaise.AllowIncrement(); raisesBlindToAPreflopRaise.AllowIncrement(); lastFinalBoard = null; }
/* The final board became available */ public void BoardAvailable(HoldemBoard board) { lastFinalBoard = board; }
/* This method takes care of generating a board (if requirements are met) and raising * an event when proper */ private void HandleFinalBoard(List<Card> cards) { // We check whether this board is a final board by checking how many cards we've detected // We're not interested into boards with less than 5 cards if (cards.Count == 5) { Board board = new HoldemBoard(cards[0], cards[1], cards[2], cards[3], cards[4]); OnFinalBoardAvailable(board); } else { Trace.WriteLine("Board detected, but only " + cards.Count + " cards in there. Skipping..."); } }
public ClassificationPostflop(HoldemHand hand, HoldemGamePhase phase, HoldemBoard board) { CardList communityCards = board.GetBoardAt(phase); // Default this.hand = HandType.Unknown; this.kicker = KickerType.Unknown; this.pair = PairType.Irrelevant; this.draw = DrawType.Irrelevant; this.straightDraw = StraightDrawType.None; Trace.Assert(communityCards.Count > 0, "Cannot classificate an empty list of community cards."); // Create a new list including the board cards and the cards from the hand CardList cards = new CardList(communityCards.Count + 2); foreach (Card c in communityCards) cards.AddCard(c); cards.AddCard(hand.GetFirstCard()); cards.AddCard(hand.GetSecondCard()); // --- Royal flush if (IsRoyalFlush(cards)) { this.hand = HandType.RoyalFlush; this.kicker = KickerType.Irrelevant; return; } // -- Four of a kind if (cards.HaveIdenticalFaces(4)) { this.hand = HandType.FourOfAKind; this.kicker = KickerType.Irrelevant; return; } // -- Full House // If we have three of a kind and two pair at the same time, we have a full house bool isThreeOfAKind = cards.HaveIdenticalFaces(3); bool isTwoPair = IsTwoPair(cards); if (isThreeOfAKind && isTwoPair) { this.hand = HandType.FullHouse; this.kicker = KickerType.Irrelevant; return; } // -- Flush for (int i = 0; i < cards.Count; i++) { int numCardsSameSuit = 0; for (int j = i + 1; j < cards.Count; j++) { if (cards[i].Suit == cards[j].Suit) { numCardsSameSuit++; } } if (numCardsSameSuit >= 4) { this.hand = HandType.Flush; this.kicker = KickerType.Irrelevant; return; } } // -- Straight if (IsStraight(cards)) { this.hand = HandType.Straight; this.kicker = KickerType.Irrelevant; return; } // Calculate draws (if we got until here, there might be some) // Also, no draws are possible at the river if (phase == HoldemGamePhase.River) { draw = DrawType.None; straightDraw = StraightDrawType.None; } else { draw = GetDrawType(cards); if (IsInsideStraightDraw(cards)) { straightDraw = StraightDrawType.InsideStraightDraw; } if (IsOpenEndedStraightDraw(cards)) { straightDraw = StraightDrawType.OpenEndedStraightDraw; } } // -- Trips if (isThreeOfAKind) { this.hand = HandType.ThreeOfAKind; this.kicker = KickerType.Irrelevant; return; } // -- Two pair if (isTwoPair) { this.hand = HandType.TwoPair; this.kicker = KickerType.Irrelevant; return; } // -- Pair Card matching; if (cards.HaveIdenticalFaces(2, out matching)) { // Sort list by face value (ace high first) cards.Sort(SortUsing.AceHigh); // Find kicker (check from end of the list where face values are higher) Card kicker = cards[0]; for (int i = cards.Count - 1; i >= 0; i--) { if (cards[i].Face != matching.Face) { kicker = cards[i]; break; } } this.hand = HandType.Pair; this.kicker = GetKickerTypeFromCard(kicker); this.pair = GetPairType(communityCards, matching, hand.GetFirstCard(), hand.GetSecondCard()); return; } // -- High card cards.Sort(SortUsing.AceHigh); Card highCard = cards.Last; this.hand = HandType.HighCard; this.kicker = GetKickerTypeFromCard(highCard); }
public HoldemHand.Classification GetHandClassification(HoldemGamePhase phase, HoldemBoard board) { HoldemHand.Classification classification = GetClassification(phase, board); Trace.WriteLine(String.Format("Rating hand [{0}] for {1} on board [{2}]: {3}", base.ToString(), phase.ToString(), board.ToString(), classification.ToString())); return classification; }
/* Calculates the type of the hand given a board * during a game phase */ public HoldemHand.Classification GetClassification(HoldemGamePhase phase, HoldemBoard board) { if (phase == HoldemGamePhase.Preflop) { return new ClassificationPreflop(this); } else { return new ClassificationPostflop(this, phase, board); } }
public List<Statistic> Calculate(HoldemHand hand, HoldemBoard board) { List<Statistic> result = new List<Statistic>(); // What game phase are we in (returns empty list if the board is invalid) HoldemGamePhase phase = HoldemGamePhase.Flop; if (board.Count == 3) phase = HoldemGamePhase.Flop; else if (board.Count == 4) phase = HoldemGamePhase.Turn; else if (board.Count == 5) phase = HoldemGamePhase.River; else { Trace.WriteLine("We were asked to calculate the odds for " + hand.ToString() + " and " + board.ToString() + " but the board seems to be invalid. Returning empty."); return result; } HoldemHand.ClassificationPostflop classification = (HoldemHand.ClassificationPostflop)hand.GetClassification(phase, board); HoldemHand.ClassificationPostflop.HandType handType = classification.GetHand(); HoldemHand.ClassificationPostflop.DrawType drawType = classification.GetDraw(); HoldemHand.ClassificationPostflop.StraightDrawType straightDrawType = classification.GetStraightDraw(); result.Add(new Statistic(new StatisticsDescriptiveData("Your hand", classification.GetHandDescription()))); if (phase == HoldemGamePhase.Flop || phase == HoldemGamePhase.Turn) { result.Add(new Statistic(new StatisticsDescriptiveData("Draws", classification.GetDrawsDescription()))); if (handType == HoldemHand.ClassificationPostflop.HandType.HighCard) { // Hold high card, hope to make a pair result.Add(CreateOutsStatistic("Improve to a pair", 6, phase)); } else if (handType == HoldemHand.ClassificationPostflop.HandType.Pair) { // Hold a pair, hope to make three of a kind result.Add(CreateOutsStatistic("Improve to three of a kind", 2, phase)); } else if (handType == HoldemHand.ClassificationPostflop.HandType.TwoPair) { // Hold two pair, hope to make a full house result.Add(CreateOutsStatistic("Improve to a full house", 4, phase)); } if (drawType == HoldemHand.ClassificationPostflop.DrawType.Flush) { result.Add(CreateOutsStatistic("Improve to a flush", 9, phase)); } else if (drawType == HoldemHand.ClassificationPostflop.DrawType.Straight) { if (straightDrawType == HoldemHand.ClassificationPostflop.StraightDrawType.OpenEndedStraightDraw) { result.Add(CreateOutsStatistic("Improve to a straight", 8, phase)); } else if (straightDrawType == HoldemHand.ClassificationPostflop.StraightDrawType.InsideStraightDraw) { result.Add(CreateOutsStatistic("Improve to a straight", 4, phase)); } else { Trace.WriteLine("Warning! Straight draw detected when calculating odds but none of the cases was matched?"); } } else if (drawType == HoldemHand.ClassificationPostflop.DrawType.FlushAndStraight) { // Open ended straight flush draw if (straightDrawType == HoldemHand.ClassificationPostflop.StraightDrawType.OpenEndedStraightDraw) { // 9 outs for the flush + 6 outs (2 outs for the straight draw are the suit we need to make the flush) result.Add(CreateOutsStatistic("Improve to a flush or straight", 15, phase)); } else if (straightDrawType == HoldemHand.ClassificationPostflop.StraightDrawType.InsideStraightDraw) { // inside straight flushd draw, 9 outs + 3 (1 out is the suit we need) result.Add(CreateOutsStatistic("Improve to a flush or straight", 12, phase)); } else { Trace.WriteLine("Warning! Flush and straight draw detected when calculating odds but none of the cases was matched?"); } } } return result; }