使用Python识别直线,同花顺和其他类别(来自Poker)

时间:2019-07-03 16:24:24

标签: python-3.x

我是python的新手,可以从书籍,论坛和开发人员那里学习。最近,我尝试在扑克程序中实现各种手排名类别。目的是计算概率,看看它是否与理论扑克手概率相符?

Source: https://en.wikipedia.org/wiki/Poker_probability?oldformat=true

请在下面找到我到目前为止用来构建它的代码和逻辑。该代码包含Card和Deck类,它们共同实现了所使用的一系列标准扑克牌,以及一个示例PyTest测试函数test_xxx()。

到目前为止,我已经编写了hasOnePair,hasTwoPairs,hasThreeOfAKind,hasFullHouse和hasFourOfaKind()函数,并且运行良好,但是我在Straight,flush,StraightFlush方面苦苦挣扎。

有人可以提出建议或给出有关如何处理平直,同花,皇家同花顺,同花顺案例的指南吗?此外,任何更新此代码的建议都将是很好的。


import random

SUITS = ["Clubs", "Diamonds", "Hearts", "Spades"]
RANKS = ["", "Ace", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight", "Nine", "Ten", "Jack", "Queen", "King"]

# here's two Python classes whose objects represent playing cards and decks thereof

class Card():
    """
    Represents a single playing card,
        whose rank internally is int _rank: 1..13 => "Ace".."King"
        and whose suit internally is int _suit 0..3 => "Clubs".."Spades"
    """

    def __init__(self, rank=1, suit=3): # this is the constructor!
        '''
        Initialize card with given int suit and int rank
        :param rank:
        :param suit:
        :return:
        '''
        self._rank = rank
        self._suit = suit

    def __str__(self): # this is the "stringifier"
        """
        Return the string name of this card:
        "Ace of Spades": translates int fields to strings
        :return:
        """

        # "Ace of Spades" is string for self._rank==1, self._suit==3

        toreturn = RANKS[self._rank] + " of " + SUITS[self._suit]

        return toreturn


class Deck():
    """
    Represents a deck of 52 standard playing cards,
        as a list of Card refs
    """

    def __init__(self): # constructor
        """
        Initialize deck: field _cards is list containing
            52 Card refs, initially
        :return: nothing
        """

        self._cards = []
        for rank in range(1, 14):
            for suit in range(4):
                c = Card(rank, suit) # create next Card with given value
                self._cards.append(c) # add it to this Deck

    def __str__(self):
        """
        "Stringified" deck: string of Card named,
        with \n for easier reading
        :return:
        """
        toreturn = ''

        # for index in range(len(self._cards)):
        #     self._cards[index]

        for c in self._cards:
            temp = str(c)  # temp is the stringified card
            toreturn = toreturn + temp + "\n"  # note \n at end

        return toreturn

    def shuffle(self):
        random.shuffle(self._cards)  # note random function to do this

    def dealCard(self):
        toreturn = self._cards.pop(0)  # get and remove top card from deck
        return toreturn

def buildDict(hand):
    dict = {}

    for card in hand:
        dict[card._rank] = dict.get(card._rank, 0) + 1


    return dict


def hasOnePair(dict):

    twocount = 0
    threecount = 0

    for v in dict.values():
        if v == 2:
            twocount += 1
        elif v == 3:
            threecount += 1

    if twocount==1 and threecount != 1:
        return True
    else:
        return False



def hasTwoPairs(dict):

    twocount1 = 0
    threecount1 = 0

    for v in dict.values():
        if v ==2:
            twocount1 += 1
        elif v == 3:
            threecount1 +=1

    if twocount1 == 2 and threecount1 != 1:
        return True
    else:
        return False



def hasThreeOfAKind(dict):


    twocount = 0
    threecount = 0

    for v in dict.values():
        if v == 2:
            twocount += 1
        elif v == 3:
            threecount += 1

    if twocount != 1 and threecount == 1:
        return True
    else:
        return False



def hasFullHouse(dict):

    twocount = 0
    threecount = 0

    for v in dict.values():
        if v == 2:
            twocount += 1
        elif v == 3:
            threecount += 1

    if twocount == 1 and threecount == 1:
        return True
    else:
        return False





def hasFourOfAKind(dict):

    fourcount = 0
    onecount = 0

    for v in dict.values():
        if v ==4:
            fourcount += 1
        elif v == 1:
            onecount +=1

    if fourcount == 1 and onecount == 1:
        return True
    else:
        return False


def hasStraight(hand):


    return False

def hasFlush(dict):


    return False

def hasStraightFlush(dict):

    return False

def hasRoyalFlush(dict):

    return False

def main():


    TRIALS = 1000  # int(input ("Input number of hands to test: "))

    hand = []  # list of Card in hand

    # accumulators for different counts

    onepairCount = 0
    twopairCount = 0
    threeCount = 0
    fourCount = 0
    fullHouseCount = 0
    StraightCount = 0



    for num in range(TRIALS):

        # create new Deck and shuffle
        d = Deck()
        d.shuffle()

        # initialize hand as empty list
        hand = []

        # deal top 5 cards of deck, adding to hand

        for count in range(5):
            hand.append(d.dealCard())


        # build the dictionary of card ranks in hand

        dict = buildDict(hand)



        # use dictionary to make hand checking easier

        if hasOnePair(dict):
            onepairCount += 1
        elif hasTwoPairs(dict):
            twopairCount += 1
        elif hasThreeOfAKind(dict):
            threeCount += 1
        elif hasFourOfAKind(dict):
            fourCount += 1
        elif hasFullHouse(dict):
            fullHouseCount += 1
        elif hasStraight(dict):
            StraightCount +=1

    # add more if needed...

    # print out results...

    print("Number of one pair hands is: ", onepairCount)
    print("% of hands: ", 100.0 * onepairCount / TRIALS)

    print("Number of two pair hands is: ", twopairCount)
    print("% of hands: ", 100.0 * twopairCount / TRIALS)


    print("Number of trips hand is: ", threeCount)
    print("% of hands: ", 100.0 * threeCount / TRIALS)

    print("Number of quads hand is: ", fourCount)
    print("% of hands: ", 100.0 * fourCount / TRIALS)

    print("Number of trips hand is: ", fullHouseCount)
    print("% of hands: ", 100.0 * fullHouseCount / TRIALS)

    print("Number of trips hand is: ", StraightCount)
    print("% of hands: ", 100.0 * StraightCount / TRIALS)



def card_example():

    card1 = Card()  # Card(1,3) => Ace of Clubs
    card2 = Card(12, 2) # Card (12,2) => Queen of Hearts

    card1._newfield = 47 # we can add new fields to any Python object!

    # three ways of printing a Card
    #

    print(card1.__str__())  # calling the methods against card
    print(str(card2)) # type-casting
    print(card2) # short-cut: passing obj ref to print does str() automagically

    print(card1._newfield) # see the new field value?

    print(card1._rank) # see the rank (1..13)
    print(card1._suit) # see the suit (0..3)

def deck_example():
    """
    Test Deck: create, print then shuffle, print again
    Then deal first two cards and print, along with bottom card
    """

    deck = Deck()
    print(str(deck)) # see entire deck before shuffling

    print("Now we shuffle:\n")

    deck.shuffle()
    print(str(deck)) # see entire deck after shuffling

    card1 = deck.dealCard()
    card2 = deck.dealCard()

    print("The first card dealt is", str(card1), "and the second is", str(card2))
    print("Bottom of deck is", deck._cards[-1])  # can't hide the implementation!

if __name__ == "__main__": # only run this if this .py is NOT imported
    # pass

    # card_example() # uncomment to test creating & calling Card methods

    # deck_example()  # uncomment to test Deck: create, print, shuffle, print

    main()  # uncomment to run general poker odds calculations

#
# -------------------------------------------------------------------------
#

#pytest follows...

def test_one_pair():
    testhand = [Card(2, 3), Card(1, 2),
                Card(3, 1), Card(13, 2),
                Card(2, 0)]

    dict = buildDict(testhand)

    assert hasOnePair(dict)  #hasTwoPairs

def test_two_pair():
    testhand = [Card(2, 3), Card(1, 2),
                Card(3, 1), Card(3, 2),
                Card(2, 0)]

    dict = buildDict(testhand)

    assert hasTwoPairs(dict)

def test_three_pair():
    testhand = [Card(1, 3), Card(1, 2),
                Card(1, 1), Card(13, 2),
                Card(2, 0)]

    dict = buildDict(testhand)

    assert hasThreeOfAKind(dict)

def has_Four_Of_A_Kind():
    testhand = [Card(1, 3), Card(1, 2),
                Card(1, 1), Card(1, 0),
                Card(2, 0)]

    dict = buildDict(testhand)

    assert hasFourOfAKind(dict)

def test_full_house():
    testhand = [Card(1, 3), Card(1, 2),
                Card(1, 1), Card(13, 2),
                Card(13, 2)]

    dict = buildDict(testhand)

    assert hasFullHouse(dict)

def test_Straight():
    testhand = [Card(11, 1), Card(10, 3),
                Card(9, 2), Card(8, 1),
                Card(7, 3)]

    dict = buildDict(testhand)

    assert hasStraight(dict)


1 个答案:

答案 0 :(得分:1)

顺子的条件是您的五张牌具有相邻的等级,这样就不会有两张牌具有相同的等级。您可以使用两种不同的检查来确认这一点:

  1. 排序后,顶卡和底卡之间的差等于总牌数减去一(例如,一个4-8的顺子的差为4)
  2. 顺子中没有两张牌具有相同的等级(因此,根据信鸽原则,必须存在最小与最大之间的所有等级

以下是该示例的实现:

def hasStraight(hand):
    # account for both low-ace and high-ace
    ranks_low = sorted([card._rank for card in hand])
    ranks_high = sorted([(14 if card._rank == 1 else card._rank) for card in hand])

    return (
        (
            ranks_low[-1] - (len(hand) - 1) == ranks_low[0]
            or ranks_high[-1] - (len(hand) - 1) == ranks_high[0]
        )                                                        # condition 1
        and len(set(hand)) == len(hand)                          # condition 2
    )

您还必须考虑低位和高位。例如,您可以通过两次类似的检查来完成此操作,一次检查正常的卡片等级,一次执行类似“ if card._rank == 1:card._rank == 14


同花顺的条件是,所有牌都是相同的花色。这很容易验证,只需简单地手工制作所有set中所有独特的花色,然后返回true(如果该花色只有一个元素(因此所有花色必须相同)):

def hasFlush(hand):
    suits_set = set(*[card._suit for card in hand])
    return len(suits_set) == 1

一旦有了这些,同花顺和皇家同花顺就很容易了:

def hasStraightFlush(hand):
    return hasStraight(hand) and hasFlush(hand)

def hasRoyalFlush(hand):
    ranks = sorted([14 if card._rank == 1 else card._rank for card in hand])
    return (
        hasStraightFlush(hand)
        and ranks[0] == 10 and ranks[-1] == 14
    ) # royal flush starts at 10, ends at high-ace