Example #1
0
 def rankHand(cls, hand):
     """Rank a hold'em hand (pair or high card)."""
     if hand[0].rank == hand[1].rank:
         return PokerRank.pair(hand[0].rank, kickers=None)
     if hand[0].rank > hand[1].rank:
         return PokerRank.highCard(hand[0].rank, hand[1:])
     else:
         return PokerRank.highCard(hand[1].rank, hand[:1])
Example #2
0
    def _rankFiveCardHand(cls, cards):
	"""Get rank of five cards. This method is more efficient than
	_getRankSixPlusCards()."""
	cards.sort(reverse=True)
	isFlush = cards.sameSuit()
	straightRank = cls._isStraight(cards)
	# Do we have a straight flush?
	if (straightRank and isFlush):
	    return PokerRank.straightFlush(straightRank)
	# Check for four of a kind
	if (cards[0].rank == cards[1].rank == cards[2].rank == cards[3].rank):
	    return PokerRank.quads(cards[0].rank, cards[4:])
	if (cards[1].rank == cards[2].rank == cards[3].rank == cards[4].rank):
	    return PokerRank.quads(cards[1].rank, cards[0:1])
	# Check for full house
	#   -First two and last two cards must match each other
	#   -Then middle card either matches first two cards
	#    or last two cards
	if ((cards[0].rank == cards[1].rank) and
	    (cards[3].rank == cards[4].rank)):
	    if (cards[2].rank == cards[0].rank):
		# XXXYY
		return PokerRank.fullHouse(cards[0].rank, cards[3].rank)
	    elif (cards[2].rank == cards[3].rank):
		# XXYYY
		return PokerRank.fullHouse(cards[2].rank, cards[0].rank)
	# Check for flush, which we've already done
	if isFlush:
	    return PokerRank.flush(cards[0].rank, cards[1:])
	# Check for Straight, which we've already done
	if straightRank:
	    return PokerRank.straight(straightRank)
	# Check for trips
	if ((cards[0].rank == cards[1].rank == cards[2].rank) or
	    (cards[1].rank == cards[2].rank == cards[3].rank) or
	    (cards[2].rank == cards[3].rank == cards[4].rank)):
	    # cards[2] will always be one of the trips
	    primaryRank = cards[2].rank
	    cards.removeRank(primaryRank)
	    return PokerRank.trips(primaryRank, cards)
	# Check for two pair	    
	# At this point we know we don't have trips, so can optimize some
	if (cards[0].rank == cards[1].rank):
	    if (cards[2].rank == cards[3].rank):
		return PokerRank.twoPair(cards[0].rank, cards[2].rank, cards[4:])
	    if (cards[3].rank == cards[4].rank):
		return PokerRank.twoPair(cards[0].rank, cards[3].rank, cards[2:3])
	elif ((cards[1].rank == cards[2].rank) and
	      (cards[3].rank == cards[4].rank)):
	    return PokerRank.twoPair(cards[1].rank, cards[3].rank, cards[0:1])
	# Check for a pair
	# At this point we know we don't have two pair or trips
	foundPair = False
	for index in range(4):
	    if cards[index].rank == cards[index+1].rank:
		foundPair = True
		break
	if foundPair:
	    pairRank = cards[index].rank
	    del cards[index:index+2]
	    return PokerRank.pair(pairRank, cards)
	# Just a high card
	return PokerRank.highCard(cards[0].rank, cards[1:])
Example #3
0
    def _rankSixOrSevenCardHand(cls, cards):
        """Given a set of 6 or 7 cards, return a PokerRank for its best hand.

        Will work for 5 cards, but is less efficient than _rankFiveCardHand()."""
        if len(cards) > 7:
            raise ValueError("Hand has too many cards (%d > 7)" % len(cards))
        if len(cards) < 5:
            raise ValueError("Hand has too few cards (%d < 5)" % len(cards))

        # Array of bitfields of cards by suit
        suitedBitFields = cls._handToSuitedBitFields(cards)
        
        # Check for straight-flush
        highRank = None
        for suit in Suit.suits:
            rank = cls._hasStraight(suitedBitFields[suit])
            if rank and ((highRank is None) or (rank > highRank)):
                highRank = rank
        if highRank is not None:
            return PokerRank.straightFlush(highRank)

        # Get bitfields representing singletons, pairs, trips and quads
        (singletonsBitField,
         pairsBitField,
         tripsBitField,
         quadsBitField) = cls._suitedBitFieldsToRankedBitFields(suitedBitFields)

        # Single bitfield with all four suits merged for kickers and straights
        bitfield = (suitedBitFields[Suit.CLUBS] |
                    suitedBitFields[Suit.DIAMONDS] |
                    suitedBitFields[Suit.HEARTS] |
                    suitedBitFields[Suit.SPADES])

        # Check for quads
        if quadsBitField.setCount() > 0:
            rank = quadsBitField.highestSet()
            # Highest remaining card is our kicker
            kickerRank = bitfield.filterBits(rank).highestSet()
            return PokerRank.quads(rank, [kickerRank])
            
        # Check for full house
        if ((tripsBitField > 0) & (pairsBitField > 0)):
            return PokerRank.fullHouse(tripsBitField.highestSet(),
                                       pairsBitField.highestSet())

        # Check for flush
        flushBitField = None
        for suit in Suit.suits:
            if suitedBitFields[suit].setCount() >= 5:
                if ((flushBitField is None) or
                    (suitedBitFields[suit] > flushBitField)):
                    flushBitField = suitedBitFields[suit]
        if flushBitField:
            rank = flushBitField.highestSet()
            kickers = flushBitField.filterBits(rank).highestNSet(4)
            return PokerRank.flush(rank, kickers)

        # Check for straight
        # We don't care about suit anymore so can just operate on bitfield
        rank = cls._hasStraight(bitfield)
        if rank:
            return PokerRank.straight(rank)

        # Check for trips
        if (tripsBitField > 0):
            rank = tripsBitField.highestSet()
            kickers = bitfield.filterBits(rank).highestNSet(2)
            kickers = bitfield.highestNSet(2)
            return PokerRank.trips(rank, kickers)

        # Check for two pair
        if (pairsBitField.setCount() > 1):
            ranks = pairsBitField.highestNSet(2)
            kickers = bitfield.filterBits(ranks[0], ranks[1])
            kicker = kickers.highestSet()
            return PokerRank.twoPair(ranks[0], ranks[1], [kicker])

        # Check for pair
        if (pairsBitField > 0):
            rank = pairsBitField.highestSet()
            kickers = bitfield.filterBits(rank).highestNSet(3)
            return PokerRank.pair(rank, kickers)

        # High card
        highCard = bitfield.highestSet()
        kickers = bitfield.filterBits(highCard).highestNSet(4)
        return PokerRank.highCard(highCard, kickers)
Example #4
0
    def _rankHand(cls, hand):
        """Given a Hand, return its PokerRank for its best low hand.

        Limited to Hands of 5-7 cards."""
        if len(hand) > 7:
            raise ValueError("Hand has too many cards (%d > 7)" % len(hand))
        if len(hand) < 5:
            raise ValueError("Hand has too few cards (%d < 5)" % len(hand))
        rankCounts = hand.countRanks()
        # Count ranks which we have at least one of
        atLeastOne = filter(lambda rank: rankCounts[rank] > 0, Rank.rankRange)
        # If we don't have at least two different ranks, we have five-of-a-kind
        if len(atLeastOne) < 2:
            raise PokerInternalException("Apparently have five of a kind with hand %s" % hand)
        if len(atLeastOne) >= 5:
            # We can make a hand without a pair
            return PokerRank.highCard(atLeastOne[4], atLeastOne[0:4])

        # We didn't find 5 unpaired cards, figure out where we stand
        atLeastTwo = filter(lambda rank: rankCounts[rank] > 1, Rank.rankRange)
        if len(atLeastTwo) == 0:
            raise PokerInternalException("Invalid state (no pair) with hand %s" % hand)
        if len(atLeastOne) == 4:
            # We will have one pair which will be lowest rank remaining
            pairRank = atLeastTwo[0]
            # Remove pair to obtain kickers
            atLeastOne.remove(pairRank)
            return PokerRank.pair(pairRank, atLeastOne)
        elif (len(atLeastOne) == 3) & (len(atLeastTwo) >= 2):
            # We have two pair
            pairRank1 = atLeastTwo[0]
            pairRank2 = atLeastTwo[1]
            # Remove pairs to obtain kicker
            atLeastOne.remove(pairRank1)
            atLeastOne.remove(pairRank2)
            return PokerRank.twoPair(pairRank1, pairRank2, atLeastOne)

        # If we reach this point, we have at least trips.
        atLeastThree = filter(lambda rank: rankCounts[rank] > 2, Rank.rankRange)
        if len(atLeastThree) == 0:
            raise PokerInternalException("Invalid state (no trips) with hand %s" % hand)
        if len(atLeastOne) == 3:
            tripsRank = atLeastThree[0]
            # Remove trips to obtain kickers
            atLeastOne.remove(tripsRank)
            return PokerRank.trips(tripsRank, atLeastOne)

        # If we reach this point, we have a full house or quads
        if len(atLeastOne) != 2:
            raise PokerInternalException("Invalid state (less than two ranks) with hand %s" % hand)
        if len(atLeastTwo) > 1:
            # Remove trips from pairs to find full house fillers
            tripsRank = atLeastThree[0]
            atLeastTwo.remove(tripsRank)
            return PokerRank.fullHouse(tripsRank, atLeastTwo[0])

        # If we reach this point, we have quads
        atLeastFour = filter(lambda rank: rankCounts[rank] > 3, Rank.rankRange)
        if len(atLeastFour) == 0:
            raise PokerInternalException("Invalid state (no quads) with hand %s" % hand)
        quadsRank = atLeastFour[0]
        # Remove quads to obtain kicker
        atLeastOne.remove(quadsRank)
        return PokerRank.quads(quadsRank, atLeastOne)