使用 Python 识别顺子、同花和其他类别(来自扑克)

2023-12-01

我是 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. 排序时,顶牌与底牌之差等于牌总数减一(例如 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
    )

您还必须考虑低 A 和高 A。例如,您可以通过执行两次类似的检查来做到这一点,一次使用正常的卡牌等级,一次通过执行类似“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
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用 Python 识别顺子、同花和其他类别(来自扑克) 的相关文章

  • 使用 Pytest 捕获 SystemExit 消息

    我正在使用 pytest 编写测试 我遇到了一些函数抛出异常的情况SystemExit如果输入错误 终端上会显示一些错误消息 我想为以下情况编写测试SystemExit抛出并验证输出错误消息中是否有特定字符串 这是代码 def test v
  • 如何在 PyQt5 GUI 中快速绘制 matplotlib 实时绘图

    几年前 我已经尝试过嵌入现场matplotlib中的情节PyQt5图形用户界面 实时绘图显示从传感器捕获的实时数据流 某些过程 我已经成功了 您可以在此处阅读相关帖子 您自己的 GUI 中的 Matplotlib 动画 https stac
  • Python 3 基于列名相似度的匹配值

    我有以下形式的数据框 Year 1 Grade Year 2 Grade Year 3 Grade Year 4 Grade Year 1 Students Year 2 Students Year 3 Students Year 4 St
  • 当键未知时访问字典值的简洁方法

    我有一堆大字典 其键是文本字符串 每个键值对都具有相同的格式 我经常最终需要打印出其中一个值来验证结构 which键 值对无关紧要 使用以下内容 my dict list my dict keys ARBITRARY INDEX 我觉得必须
  • 如何对请求使用线程? [复制]

    这个问题在这里已经有答案了 您好 我正在使用请求模块 我想提高速度 因为我有很多网址 所以我想我可以使用线程来获得更好的速度 这是我的代码 import requests urls http www google com http www
  • 如何才能完全替代 3.10 中已弃用的 distutils?

    根据PEP 632 https www python org dev peps pep 0632 distutils将被正式标记为已弃用 并在 Python 3 12 中将其删除 我的产品很快就会支持 Python 3 10 我不想忍受弃用
  • PermissionError: [WinError 5] 访问被拒绝

    每次我尝试使用删除文件os remove 在 Python 3 5 1 中 我收到此消息PermissionError WinError 5 Access is denied 这是简单的代码 def clean thrash path di
  • Python 3.x 中的绘图

    在Python 2 6中 我使用matplotlib制作了一些简单的图表 但是 它与 Python 3 1 不兼容 有哪些替代模块可以完成相同的事情而不非常复杂 您说您想创建一些简单的图表 但没有真正说明您想要多简单或哪种类型的图表 只要它
  • 内置 Exception 类需要什么参数?

    作为我的后续上一个问题 https stackoverflow com questions 55210410 creating exceptions that are co operative 我试图创建不违反 LSP 的协作用户定义异常
  • 从 nowgoal 获取表值出现索引错误

    我对刮擦很陌生 我收到的链接来自nowgoal http www nowgoal3 com 下面是我如何开始导航到上面的页面 我不希望获得所有比赛的链接 但我会有一个输入文本文件 它是附在这里 https drive google com
  • 无需安装即可获取给定源目录的 python3 包元数据

    我正在尝试获取一些包元数据 名称 版本 并给出源目录的路径 而不安装所述包 这些工作 使用setup py如果您位于根目录中 gt python3 setup py name my package name gt python3 setup
  • 让 django 不插入某些字段

    我有一个针对 postgresql 数据库表的 Django 模型 我希望 Django 在对象创建期间不要插入 field 3 作为 DB 应该填写的时间戳字段 class AbcModel model id models AutoFie
  • python编写的类爬虫抛出属性错误

    用 python 编写一些代码后 我陷入了深深的麻烦 我是按照 Python 中的 OOP 设计编写代码的新手 我在代码中使用的 xpath 是完美的 当通过 page crawler 类的实例运行 info grabber 类中的 pas
  • 将整数列表划分为总和相等的 K 个子列表

    类似的问题还有1 https stackoverflow com questions 27322804 partition of a set into k disjoint subsets with equal sum and 2 http
  • 当存在多个条件时替换 numpy 数组中的元素

    这个问题与以下帖子相关 如果满足条件则替换 Numpy 元素 https stackoverflow com questions 19766757 replacing numpy elements if condition is met 假
  • 在 matplotlib 中使用轴绘制带有子点的图形时出现错误

    我尝试使用下面的代码绘制子图 但是我得到了 AttributeError numpy ndarray object has no attribute boxplot 但改变plt subplots 1 2 它正在用indexerror绘制箱
  • Sublime Text 3 内部图像查看器

    是否可以为 Sublime Text 3 创建一个内部图像查看器插件 我注意到在他们的论坛中 人们提到 ST2 不可能 因为 API 不允许访问 UI 和小部件 但只是想知道 ST3 是否仍然如此 Sublime Text 3 现在有内置的
  • 动态组装 Python 模块,动态导入

    我正在努力让自己熟悉importlib钩子 我想实现直接导入用其他语言编写的非Python文件并维护源映射的能力 因此提高SyntaxError带有行号的 s 仍然会给出有意义的堆栈跟踪 我加载外部文件的方法是组装 Pythonic 源代码
  • 如何将 xlsx 读取为 pandas 数据框,并将公式作为字符串

    我有一个包含一些计算列的 Excel 文件 例如 我在 a 列中有一些数据 而 b 列是使用 a 列中的值计算的 我需要将新数据附加到 a 列并计算 b 列并保存文件 import pandas as pd df pd DataFrame
  • 从谷歌云存储桶加载数据

    这是一个从谷歌云存储桶加载数据的函数 action dataset folder path action data set zip path actions zip url http console cloud google com sto

随机推荐