private bool IsOpenEndedStraightDraw(CardList cardList) { if (cardList.Count < 4) return false; // Except if the ace is the last card, because there's no cards higher than the ace if (cardList.AreConsecutive(true, false, 4)){ // (list is sorted from lowest to highest) cardList.Sort(SortUsing.AceHigh); // Special case if (cardList[cardList.Count - 1].Face == CardFace.Ace && cardList[cardList.Count - 2].Face == CardFace.King && cardList[cardList.Count - 3].Face == CardFace.Queen && cardList[cardList.Count - 4].Face == CardFace.Jack) return false; else return true; } // Except if the ace is not the first card, there's no cards lower than the ace if (cardList.AreConsecutive(false, false, 4)) { cardList.Sort(SortUsing.AceLow); // Special case if (cardList[0].Face == CardFace.Ace && cardList[1].Face == CardFace.Two && cardList[2].Face == CardFace.Three && cardList[3].Face == CardFace.Four) return false; else return true; } return false; }
private PairType GetPairType(CardList communityCards, Card matching, Card firstCard, Card secondCard) { communityCards.Sort(SortUsing.AceHigh); // Pocket pair if (firstCard.Face == secondCard.Face) { if (firstCard.GetFaceValue() >= communityCards.Last.GetFaceValue()) return PairType.Top; else if (firstCard.GetFaceValue() <= communityCards[0].GetFaceValue()) return PairType.Bottom; else return PairType.Middle; } else { // Matched the board if (matching.Face == communityCards.Last.Face) return PairType.Top; else if (matching.Face == communityCards[0].Face) return PairType.Bottom; else return PairType.Middle; } }
private bool IsInsideStraightDraw(CardList cardList, bool countAceAsHigh) { if (cardList.Count < 4) return false; cardList.Sort(countAceAsHigh); // Case 1 and 2 are special cases // Case 1: first card is an ace and we are not counting ace as low, followed by 2, 3, 4 if (!countAceAsHigh && cardList[0].Face == CardFace.Ace && cardList[1].Face == CardFace.Two && cardList[2].Face == CardFace.Three && cardList[3].Face == CardFace.Four) return true; // Case 2: first card is a J and we are counting ace as high, followed by Q, K, A if (countAceAsHigh && cardList[0].Face == CardFace.Jack && cardList[1].Face == CardFace.Queen && cardList[2].Face == CardFace.King && cardList[3].Face == CardFace.Ace) return true; // Case 2: 1 card, missing, 3 straight for (int i = 0; i < (cardList.Count - 3); i++) { int faceValue = cardList[i].GetFaceValue(countAceAsHigh); if (cardList[i + 1].GetFaceValue(countAceAsHigh) == faceValue + 2 && cardList[i + 2].GetFaceValue(countAceAsHigh) == faceValue + 3 && cardList[i + 3].GetFaceValue(countAceAsHigh) == faceValue + 4) { return true; } } // Case 3: 2 straight, missing, 2 straight for (int i = 1; i < (cardList.Count - 2); i++) { int faceValue = cardList[i].GetFaceValue(countAceAsHigh); if (cardList[i - 1].GetFaceValue(countAceAsHigh) == faceValue - 1 && cardList[i + 1].GetFaceValue(countAceAsHigh) == faceValue + 2 && cardList[i + 2].GetFaceValue(countAceAsHigh) == faceValue + 3) { return true; } } // Case 4: 3 straight, missing, 1 card for (int i = 2; i < (cardList.Count - 1); i++) { int faceValue = cardList[i].GetFaceValue(countAceAsHigh); if (cardList[i - 2].GetFaceValue(countAceAsHigh) == faceValue - 2 && cardList[i - 1].GetFaceValue(countAceAsHigh) == faceValue - 1 && cardList[i + 1].GetFaceValue(countAceAsHigh) == faceValue + 2) { return true; } } return false; }
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); }