Esempio n. 1
0
            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);
            }
Esempio n. 2
0
        public override void ParseLine(string line)
        {
            // Call base class method FIRST
            base.ParseLine(line);

            // Declare match variable that will hold the results
            Match matchResult;

            /* Check game phase changes */
            bool gamePhaseChanged = ParseForGamePhaseChanges(line);
            if (gamePhaseChanged) return;

            /* An all-in doesn't exclude a raise or a call, so it's not part of the if-elseif block
             * Ex. Player: raises and is all-in is both an all-in and a raise */
            if (LineMatchesRegex(line, pokerClient.GetRegex("hand_history_detect_all_in_push"), out matchResult))
            {
                String playerName = matchResult.Groups["playerName"].Value;

                // Make sure that the game phase is a valid one (being all-in because the blinds force us to is not really a push)
                if (currentGamePhase == HoldemGamePhase.Preflop || currentGamePhase == HoldemGamePhase.Flop ||
                    currentGamePhase == HoldemGamePhase.Turn || currentGamePhase == HoldemGamePhase.River)
                OnPlayerPushedAllIn(playerName, currentGamePhase);
            }

            /* Compare line to extract game id or table id */
            if (LineMatchesRegex(line, pokerClient.GetRegex("hand_history_game_id_token"), out matchResult))
            {
                currentGameId = matchResult.Groups["gameId"].Value;
            }

            if (LineMatchesRegex(line, pokerClient.GetRegex("hand_history_table_token"), out matchResult))
            {
                currentTableId = matchResult.Groups["tableId"].Value;
                String maxSeatingCapacity = matchResult.Groups["tableSeatingCapacity"].Value;

                Trace.WriteLine("Table: " + currentTableId);
                Trace.WriteLine("Max seating capacity: " + maxSeatingCapacity);

                // Note: often currentGameId will be null because we don't have that information
                OnNewTableHasBeenCreated(currentGameId, currentTableId);

                // Abemus max seating capacity?
                if (maxSeatingCapacity != String.Empty)
                {
                    OnFoundTableMaxSeatingCapacity(Int32.Parse(maxSeatingCapacity));
                }
                else
                {
                    // We didn't find the exact seating capacity

                    // If we have a more specific regex, we'll wait until we get the line containing the maximum number of seats
                    // Otherwise, we need to infer
                    if (!pokerClient.HasRegex("hand_history_max_seating_capacity"))
                    {
                        int inferredMaxCapacity = pokerClient.InferMaxSeatingCapacity(line, handhistoryFilename);
                        Trace.WriteLine("Inferred max seating capacity: " + inferredMaxCapacity);
                        OnFoundTableMaxSeatingCapacity(inferredMaxCapacity);
                    }
                    else
                    {
                        Trace.WriteLine("Seating capacity not found, but we will find it later with a specialized regex");
                    }
                }
            }

            /* Detect the exact max seating capacity */
            if (pokerClient.HasRegex("hand_history_max_seating_capacity") && (LineMatchesRegex(line, pokerClient.GetRegex("hand_history_max_seating_capacity"), out matchResult)))
            {
                String maxSeatingCapacity = matchResult.Groups["tableSeatingCapacity"].Value;

                Trace.Assert(maxSeatingCapacity != String.Empty, "Table max seating capacity regex found, but empty result.");
                Trace.WriteLine("Found certain max seating capacity from regex: " + maxSeatingCapacity);

                OnFoundTableMaxSeatingCapacity(Int32.Parse(maxSeatingCapacity));
            }

            /* Detect the exact blind amounts */
            if (pokerClient.HasRegex("hand_history_blind_amounts") && (LineMatchesRegex(line, pokerClient.GetRegex("hand_history_blind_amounts"), out matchResult)))
            {
                float bigBlindAmount = float.Parse(matchResult.Groups["bigBlindAmount"].Value);
                float smallBlindAmount = float.Parse(matchResult.Groups["smallBlindAmount"].Value);

                Trace.WriteLine(String.Format("Found certain blind amounts: ({0}/{1})", smallBlindAmount, bigBlindAmount));

                OnFoundBigBlindAmount(bigBlindAmount);
                OnFoundSmallBlindAmount(smallBlindAmount);

                InfereBlindsFromButton(lastButtonSeatNumber);
            }

            /* Detect raises, calls, folds, bets */
            if (LineMatchesRegex(line, pokerClient.GetRegex("hand_history_detect_player_call"), out matchResult))
            {
                Trace.Assert(currentGamePhase != HoldemGamePhase.Showdown && currentGamePhase != HoldemGamePhase.Summary, "We detected a call during an impossible game phase");

                String playerName = matchResult.Groups["playerName"].Value;
                float amount = float.Parse(matchResult.Groups["amount"].Value);
                OnPlayerCalled(playerName, amount, currentGamePhase);
            }
            else if (LineMatchesRegex(line, pokerClient.GetRegex("hand_history_detect_player_bet"), out matchResult))
            {
                Trace.Assert(currentGamePhase != HoldemGamePhase.Showdown && currentGamePhase != HoldemGamePhase.Summary, "We detected a bet during an impossible game phase");

                String playerName = matchResult.Groups["playerName"].Value;
                float amount = float.Parse(matchResult.Groups["amount"].Value);
                OnPlayerBet(playerName, amount, currentGamePhase);
            }
            else if (LineMatchesRegex(line, pokerClient.GetRegex("hand_history_detect_player_fold"), out matchResult))
            {
                Trace.Assert(currentGamePhase != HoldemGamePhase.Showdown && currentGamePhase != HoldemGamePhase.Summary, "We detected a fold during an impossible game phase");

                String playerName = matchResult.Groups["playerName"].Value;

                Trace.WriteLine(playerName + " folds");
                OnPlayerFolded(playerName, currentGamePhase);
            }
            else if (LineMatchesRegex(line, pokerClient.GetRegex("hand_history_detect_player_check"), out matchResult))
            {
                Trace.Assert(currentGamePhase != HoldemGamePhase.Showdown && currentGamePhase != HoldemGamePhase.Summary, "We detected a check during an impossible game phase");

                String playerName = matchResult.Groups["playerName"].Value;
                OnPlayerChecked(playerName, currentGamePhase);
            }

            else if (LineMatchesRegex(line, pokerClient.GetRegex("hand_history_detect_player_raise"), out matchResult))
            {
                Trace.Assert(currentGamePhase != HoldemGamePhase.Showdown && currentGamePhase != HoldemGamePhase.Summary, "We detected a raise during an impossible game phase");

                String playerName = matchResult.Groups["playerName"].Value;
                float raiseAmount = float.Parse(matchResult.Groups["raiseAmount"].Value);

                Trace.WriteLine(playerName + " raises " + raiseAmount);

                OnPlayerRaised(playerName, raiseAmount, currentGamePhase);
            }

            /* Search for table seating patterns */
            else if (LineMatchesRegex(line, pokerClient.GetRegex("hand_history_detect_player_in_game"), out matchResult))
            {
                // Retrieve player name
                String playerName = matchResult.Groups["playerName"].Value;
                int seatNumber = Int32.Parse(matchResult.Groups["seatNumber"].Value);

                // Some poker clients rewrite the list of players at the summary, but we don't need this extra information
                if (currentGamePhase != HoldemGamePhase.Summary)
                {
                    // Raise event
                    OnPlayerIsSeated(playerName, seatNumber);

                    // Save
                    playerSeats.Add(seatNumber, playerName);
                }
            }

            /* Search for a winner */
            else if (LineMatchesRegex(line, pokerClient.GetRegex("hand_history_detect_hand_winner"), out matchResult))
            {
                // Retrieve player name
                String playerName = matchResult.Groups["playerName"].Value;

                // Raise event
                OnFoundWinner(playerName);
            }

            /* Search for mucked hands */
            else if (LineMatchesRegex(line, pokerClient.GetRegex("hand_history_detect_mucked_hand"), out matchResult))
            {
                // Somebody had to show... keep track of this
                PlayerHasShowedThisRound = true;

                // Retrieve player name and hand
                String playerName = matchResult.Groups["playerName"].Value;
                String cardsText = matchResult.Groups["cards"].Value;

                List<Card> cards = GenerateCardsFromText(cardsText);

                // Sometimes a regex will return only one card (when a player decides to show only one card)
                if (cards.Count == 2){
                    Hand hand = new HoldemHand(cards[0], cards[1]);

                    OnPlayerMuckHandAvailable(playerName, hand);
                }
            }

            /* Search for final board */
            else if (pokerClient.HasRegex("hand_history_detect_final_board") && (LineMatchesRegex(line, pokerClient.GetRegex("hand_history_detect_final_board"), out matchResult)))
            {
                // Retrieve cards
                String cardsText = matchResult.Groups["cards"].Value;
                List<Card> cards = GenerateCardsFromText(cardsText);

                HandleFinalBoard(cards);
            }

            /* Detect small/big blind */
            else if (pokerClient.HasRegex("hand_history_detect_small_blind") && (LineMatchesRegex(line, pokerClient.GetRegex("hand_history_detect_small_blind"), out matchResult)))
            {
                String playerName = matchResult.Groups["playerName"].Value;
                float amount = float.Parse(matchResult.Groups["smallBlindAmount"].Value);
                OnFoundSmallBlind(playerName);
                OnFoundSmallBlindAmount(amount);
            }
            else if (pokerClient.HasRegex("hand_history_detect_big_blind") && (LineMatchesRegex(line, pokerClient.GetRegex("hand_history_detect_big_blind"), out matchResult)))
            {
                String playerName = matchResult.Groups["playerName"].Value;
                float amount = float.Parse(matchResult.Groups["bigBlindAmount"].Value);
                OnFoundBigBlind(playerName);
                OnFoundBigBlindAmount(amount);
            }

            /* Find the button */
            if (LineMatchesRegex(line, pokerClient.GetRegex("hand_history_detect_button"), out matchResult))
            {
                Trace.Assert(matchResult.Groups["seatNumber"].Success || matchResult.Groups["playerName"].Success, "Detect button line matched, but no seatNumber or playerName set");
                int seatNumber = -1;

                if (matchResult.Groups["seatNumber"].Success)
                {
                    seatNumber = Int32.Parse(matchResult.Groups["seatNumber"].Value);
                }
                else if (matchResult.Groups["playerName"].Success)
                {
                    String playerName = matchResult.Groups["playerName"].Value;
                    foreach (int seat in playerSeats.Keys)
                    {
                        if ((String)playerSeats[seat] == playerName)
                        {
                            seatNumber = seat;
                            break;
                        }
                    }
                    Trace.Assert(seatNumber != -1, "Button's player name found, but he's not in our players list");
                }

                OnFoundButton(seatNumber);
                lastButtonSeatNumber = seatNumber; // Save
            }
        }
Esempio n. 3
0
 /* Returns true if the hand is a gapped connector and is within the range of hands (inclusive)
  * specified, ex. between 54 and JT (only the upper cards are checked) */
 public bool IsGappedConnectorsInRange(int gap, HoldemHand lower, HoldemHand upper)
 {
     if (this.GetHigher().GetFaceValue() >= lower.GetHigher().GetFaceValue() &&
         this.GetHigher().GetFaceValue() <= upper.GetHigher().GetFaceValue())
     {
         return IsGappedConnectors(gap);
     }
     else return false;
 }
Esempio n. 4
0
 public bool IsConnectorsInRange(HoldemHand lower, HoldemHand upper)
 {
     return IsGappedConnectorsInRange(0, lower, upper);
 }
Esempio n. 5
0
        /* Checks that every possible hand is covered in the table */
        public static void TestPercentiles()
        {
            for (CardFace face1 = CardFace.Ace; face1 <= CardFace.King; face1++)
            {
                for (CardSuit suit1 = CardSuit.Clubs; suit1 <= CardSuit.Spades; suit1++)
                {
                    Card c1 = new Card(face1, suit1);

                    for (CardFace face2 = CardFace.Ace; face2 <= CardFace.King; face2++)
                    {
                        for (CardSuit suit2 = CardSuit.Clubs; suit2 <= CardSuit.Spades; suit2++)
                        {
                            Card c2 = new Card(face2, suit2);

                            HoldemHand hand = new HoldemHand(c1, c2);
                            Trace.Assert(HoldemHand.preflopPercentiles.ContainsKey(hand.ToString()), "Percentile not found for: " + hand.ToString());
                        }
                    }
                }
            }
        }
Esempio n. 6
0
 public ClassificationPreflop(HoldemHand hand)
 {
     this.percentile = (float)HoldemHand.preflopPercentiles[hand.ToString()];
 }
        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;
        }