【问题标题】:Efficient Algorithms Ordering "5 Out of 7" Card Poker (non-straight / non-flush) Hands | Divide & Conquer [closed]排序“5 出 7”牌扑克(非顺子/非同花)手牌的高效算法 |分而治之[关闭]
【发布时间】:2019-02-06 17:39:30
【问题描述】:

考虑长度为 7 的排序列表,其中每个条目 x 是一个数字 2

在线扑克网站会对高性能算法感兴趣,这些算法会在这种情况下获得 5 张最好的牌。

用 Python 编写不导入模块的程序是对此类算法进行原型设计的好方法。

“怪物大小”的在线扑克网站很可能不需要我们的任何帮助,但看到专为速度设计的算法会很有趣。在问题中

7 Card Poker Hand Evaluator

从 2010 年开始对此进行了检查,但许多链接已损坏。很高兴知道当今使用的最快的已知算法的状态。

问题:下面讨论的算法是否已知?是否已确定某些算法在性能方面表现出色?

我的工作

我注意到长度为 7 的列表有一个中点,并且算法可以包含“组合对称”和结构。我们在下面的代码中实现了这个逻辑。可以想象一个用汇编程序编写的闪电般的快速程序,它可以计算出GOTO 数字偏移量。

注意:我还有一个一次性排序例程,它采用任意 7 张牌来确定是顺子还是同花。但有人建议我让我的问题更加集中,所以这里不讨论。

Python 程序:

hand=[2,2,7,7,8,11,12]
hand=[2,3,4,7,7,7,11]


start_spot = 3
end_spot = 3

if hand[3] == hand[4]:
    if hand[4] == hand[5]:
        if hand[5] == hand[6]:
            end_spot = 6
        else:
            end_spot = 5
    else:
        end_spot = 4

if hand[3] == hand[2]:
    if hand[2] == hand[1]:
        if hand[1] == hand[0]:
            start_spot = 0
        else:
            start_spot = 1
    else:
        start_spot = 2

if end_spot - start_spot == 3:
    if end_spot == 6:
        Kick = hand[start_spot-1]
    else:
        Kick = hand[6]
    best5 = [Kick,hand[start_spot],hand[start_spot+1],hand[start_spot+2],hand[start_spot+3]]
    print(hand, best5, 'four of a kind')
    raise SystemExit
else:
    pass


def multCount(c1,c2,c3):
    pc = 0
    if c1 == c2: pc = pc + 1
    if c2 == c3: pc = pc + 10
    return pc

pc_r = multCount(hand[4],hand[5],hand[6])
pc_l = multCount(hand[2],hand[1],hand[0])

if start_spot == 3 and end_spot == 3:
    if   pc_l ==  0 and pc_r == 0:        
        best5 = [hand[2],hand[3],hand[4],hand[5],hand[6]]
        print(hand, best5, 'no pair')
        raise SystemExit
    elif pc_l ==  0 and pc_r == 1:   
        best5 = [hand[2],hand[3],hand[6],hand[4],hand[5]]
        print(hand, best5, 'one pair')
        raise SystemExit
    elif pc_l ==  0 and pc_r == 10:       
        best5 = [hand[2],hand[3],hand[4],hand[5],hand[6]]
        print(hand, best5, 'one pair')
        raise SystemExit
    elif pc_l ==  0 and pc_r == 11:       
        best5 = [hand[2],hand[3],hand[4],hand[5],hand[6]]
        print(hand, best5, 'trips')
        raise SystemExit

    elif pc_l == 1  and pc_r == 0:        
        best5 = [hand[4],hand[5],hand[6],hand[1],hand[2]]
        print(hand, best5, 'one pair')
        raise SystemExit
    elif pc_l == 1  and pc_r == 1:       
        best5 = [hand[6],hand[1],hand[2],hand[4],hand[5]]
        print(hand, best5, 'two pair')
        raise SystemExit
    elif pc_l == 1  and pc_r == 10:       
        best5 = [hand[4],hand[1],hand[2],hand[5],hand[6]]
        print(hand, best5, 'two pair')
        raise SystemExit
    elif pc_l == 1  and pc_r == 11:       
        best5 = [hand[1],hand[2],hand[4],hand[5],hand[6]]
        print(hand, best5, 'full house')
        raise SystemExit

    elif pc_l == 10 and pc_r == 0:        
        best5 = [hand[4],hand[5],hand[6],hand[0],hand[1]]
        print(hand, best5, 'one pair')
        raise SystemExit
    elif pc_l == 10 and pc_r == 1:       
        best5 = [hand[6],hand[0],hand[1],hand[4],hand[5]]
        print(hand, best5, 'two pair')
        raise SystemExit
    elif pc_l == 10 and pc_r == 10:       
        best5 = [hand[4],hand[0],hand[1],hand[5],hand[6]]
        print(hand, best5, 'two pair')
        raise SystemExit
    elif pc_l == 10 and pc_r == 11:       
        best5 = [hand[0],hand[1],hand[4],hand[5],hand[6]]
        print(hand, best5, 'full house')
        raise SystemExit

    elif pc_l == 11 and pc_r == 0:        
        best5 = [hand[5],hand[6],hand[0],hand[1],hand[2]]
        print(hand, best5, 'trips')
        raise SystemExit
    elif pc_l == 11 and pc_r == 1:       
        best5 = [hand[4],hand[5],hand[0],hand[1],hand[2]]
        print(hand, best5, 'full house')
        raise SystemExit
    elif pc_l == 11 and pc_r == 10:       
        best5 = [hand[5],hand[6],hand[0],hand[1],hand[2]]
        print(hand, best5, 'full house')
        raise SystemExit
    elif pc_l == 11 and pc_r == 11:       
        best5 = [hand[1],hand[2],hand[4],hand[5],hand[6]]
        print(hand, best5, 'full house')
        raise SystemExit

    else:
        pass



if start_spot == 3 and end_spot == 4:
    if   pc_l ==  0 and pc_r == 0:        
        best5 = [hand[2],hand[5],hand[6],hand[3],hand[4]]
        print(hand, best5, 'one pair')
        raise SystemExit
    elif pc_l ==  0 and pc_r == 1:
        print("ERROR 1")
        pass # can't happen
        raise SystemExit    
    elif pc_l ==  0 and pc_r == 10:       
        best5 = [hand[2],hand[3],hand[4],hand[5],hand[6]]
        print(hand, best5, 'two pair')
        raise SystemExit
    elif pc_l ==  0 and pc_r == 11:       
        print("ERROR 2")
        pass # can't happen
        raise SystemExit

    elif pc_l == 1  and pc_r == 0:        
        best5 = [hand[6],hand[1],hand[2],hand[3],hand[4]]
        print(hand, best5, 'two pair')
        raise SystemExit
    elif pc_l == 1  and pc_r == 1:       
        print("ERROR 3")
        pass # can't happen
        raise SystemExit    
    elif pc_l == 1  and pc_r == 10:       
        best5 = [hand[2],hand[3],hand[4],hand[5],hand[6]]
        print(hand, best5, 'two pair')
        raise SystemExit
    elif pc_l == 1  and pc_r == 11:       
        print("ERROR 4")
        pass # can't happen
        raise SystemExit

    elif pc_l == 10 and pc_r == 0:        
        best5 = [hand[6],hand[0],hand[1],hand[3],hand[4]]
        print(hand, best5, 'two pair')
        raise SystemExit
    elif pc_l == 10 and pc_r == 1:       
        print("ERROR 5")
        pass # can't happen
        raise SystemExit
    elif pc_l == 10 and pc_r == 10:       
        best5 = [hand[4],hand[0],hand[1],hand[5],hand[6]]
        print(hand, best5, 'two pair')
        raise SystemExit
    elif pc_l == 10 and pc_r == 11:       
        print("ERROR 6")
        pass # can't happen
        raise SystemExit

    elif pc_l == 11 and pc_r == 0:        
        best5 = [hand[3],hand[4],hand[0],hand[1],hand[2]]
        print(hand, best5, 'full house')
        raise SystemExit
    elif pc_l == 11 and pc_r == 1:       
        print("ERROR 7")
        pass # can't happen
        raise SystemExit
    elif pc_l == 11 and pc_r == 10:       
        best5 = [hand[5],hand[6],hand[0],hand[1],hand[2]]
        print(hand, best5, 'full house')
        raise SystemExit
    elif pc_l == 11 and pc_r == 11:       
        print("ERROR 8")
        pass # can't happen
        raise SystemExit

    else:
        pass


if start_spot == 2 and end_spot == 3:
    if   pc_l ==  0 and pc_r == 0:        
        best5 = [hand[4],hand[5],hand[6],hand[2],hand[3]]
        print(hand, best5, 'one pair')
        raise SystemExit
    elif pc_l ==  0 and pc_r == 1:
        best5 = [hand[6],hand[2],hand[3],hand[4],hand[5]]
        print(hand, best5, 'two pair')
        raise SystemExit
    elif pc_l ==  0 and pc_r == 10:       
        best5 = [hand[4],hand[2],hand[3],hand[5],hand[6]]
        print(hand, best5, 'two pair')
        raise SystemExit
    elif pc_l ==  0 and pc_r == 11:       
        print("ERROR 9")
        pass # can't happen
        raise SystemExit

    elif pc_l == 1  and pc_r == 0:        
        print("ERROR 10")
        pass # can't happen
        raise SystemExit
    elif pc_l == 1  and pc_r == 1:       
        print("ERROR 11")
        pass # can't happen
        raise SystemExit    
    elif pc_l == 1  and pc_r == 10:       
        print("ERROR 12")
        pass # can't happen
        raise SystemExit
    elif pc_l == 1  and pc_r == 11:       
        print("ERROR 13")
        pass # can't happen
        raise SystemExit

    elif pc_l == 10 and pc_r == 0:        
        best5 = [hand[6],hand[0],hand[1],hand[2],hand[3]]
        print(hand, best5, 'two pair')
        raise SystemExit
    elif pc_l == 10 and pc_r == 1:       
        best5 = [hand[6],hand[2],hand[3],hand[4],hand[5]]
        print(hand, best5, 'two pair')
        raise SystemExit
    elif pc_l == 10 and pc_r == 10:       
        best5 = [hand[4],hand[2],hand[3],hand[5],hand[6]]
        print(hand, best5, 'two pair')
        raise SystemExit
    elif pc_l == 10 and pc_r == 11:       
        print("ERROR 14")
        pass # can't happen
        raise SystemExit

    elif pc_l == 11 and pc_r == 0:        
        print("ERROR 15")
        pass # can't happen
        raise SystemExit
    elif pc_l == 11 and pc_r == 1:       
        print("ERROR 16")
        pass # can't happen
        raise SystemExit
    elif pc_l == 11 and pc_r == 10:       
        print("ERROR 17")
        pass # can't happen
        raise SystemExit
    elif pc_l == 11 and pc_r == 11:       
        print("ERROR 18")
        pass # can't happen
        raise SystemExit

    else:
        pass


if start_spot == 2 and end_spot == 4:
    if   pc_l ==  0 and pc_r == 0:        
        best5 = [hand[5],hand[6],hand[2],hand[3],hand[4]]
        print(hand, best5, 'trips')
        raise SystemExit
    elif pc_l ==  0 and pc_r == 1:
        print("ERROR 19")
        pass # can't happen
        raise SystemExit    
    elif pc_l ==  0 and pc_r == 10:       
        best5 = [hand[5],hand[6],hand[2],hand[3],hand[4]]
        print(hand, best5, 'full house')
        raise SystemExit
    elif pc_l ==  0 and pc_r == 11:       
        print("ERROR 20")
        pass # can't happen
        raise SystemExit

    elif pc_l == 1  and pc_r == 0:        
        print("ERROR 21")
        pass # can't happen
        raise SystemExit
    elif pc_l == 1  and pc_r == 1:       
        print("ERROR 22")
        pass # can't happen
        raise SystemExit    
    elif pc_l == 1  and pc_r == 10:       
        print("ERROR 23")
        pass # can't happen
        raise SystemExit
    elif pc_l == 1  and pc_r == 11:       
        print("ERROR 24")
        pass # can't happen
        raise SystemExit

    elif pc_l == 10 and pc_r == 0:        
        best5 = [hand[0],hand[1],hand[2],hand[3],hand[4]]
        print(hand, best5, 'full house')
        raise SystemExit
    elif pc_l == 10 and pc_r == 1:       
        print("ERROR 25")
        pass # can't happen
        raise SystemExit
    elif pc_l == 10 and pc_r == 10:       
        best5 = [hand[5],hand[6],hand[2],hand[3],hand[4]]
        print(hand, best5, 'full house')
        raise SystemExit
    elif pc_l == 10 and pc_r == 11:       
        print("ERROR 26")
        pass # can't happen
        raise SystemExit

    elif pc_l == 11 and pc_r == 0:        
        print("ERROR 27")
        pass # can't happen
        raise SystemExit
    elif pc_l == 11 and pc_r == 1:       
        print("ERROR 28")
        pass # can't happen
        raise SystemExit
    elif pc_l == 11 and pc_r == 10:       
        print("ERROR 29")
        pass # can't happen
        raise SystemExit
    elif pc_l == 11 and pc_r == 11:       
        print("ERROR 30")
        pass # can't happen
        raise SystemExit

    else:
        pass


if start_spot == 1 and end_spot == 3:
    if   pc_r ==  0:
        best5 = [hand[5],hand[6],hand[1],hand[2],hand[3]]
        print(hand, best5, 'trips')
        raise SystemExit
    elif pc_r ==  1:
        best5 = [hand[4],hand[5],hand[1],hand[2],hand[3]]
        print(hand, best5, 'full house')
        raise SystemExit
    elif pc_r ==  10:   
        best5 = [hand[5],hand[6],hand[1],hand[2],hand[3]]
        print(hand, best5, 'full house')
        raise SystemExit
    elif pc_r ==  11:
        best5 = [hand[2],hand[3],hand[4],hand[5],hand[6]]
        print(hand, best5, 'full house')
        raise SystemExit

    else:
        pass


if start_spot == 3 and end_spot == 5:
    if   pc_l ==  0:
        best5 = [hand[2],hand[6],hand[3],hand[4],hand[5]]
        print(hand, best5, 'trips')
        raise SystemExit
    elif pc_l ==  1:
        best5 = [hand[1],hand[2],hand[3],hand[4],hand[5]]
        print(hand, best5, 'full house')
        raise SystemExit
    elif pc_l ==  10:   
        best5 = [hand[0],hand[1],hand[3],hand[4],hand[5]]
        print(hand, best5, 'full house')
        raise SystemExit
    elif pc_l ==  11:
        best5 = [hand[1],hand[2],hand[4],hand[5],hand[6]]
        print(hand, best5, 'full house')
        raise SystemExit

    else:
        pass


print("ERROR 99")
pass # can't happen
raise SystemExit

【问题讨论】:

  • 我建议对顺子、满屋子、三连子等进行一系列单独的过牌,然后看看哪一个会产生最好的结果。在按价值对卡片进行排序和/或按花色分组之后,这些检查中的大多数应该是相当简单的。
  • @tobias_k 如果您了解扑克,这当然会有所帮助,这样您就可以减少决策树。
  • 请按照您创建此帐户时的建议阅读并遵循帮助文档中的发布指南。 On topichow to ask... the perfect question 在此处申请。 StackOverflow 不是设计、编码、研究或教程资源。但是,如果您遵循您在网上找到的任何资源,进行诚实的编码尝试并遇到问题,那么您将有一个很好的示例可以发布。
  • 问题的问题是:虽然这个问题确实有点有趣,但你的努力似乎非常有限,而且问题也很广泛,需要实现例如以上所有这些检查。此外,如果这确实意味着某种代码高尔夫挑战,那么这些实际上并不是这里的主题。
  • 我认为它不值得投反对票,但问题确实很广泛。你想让我为你写整个程序吗?该算法似乎您有一个想法,只是给了我们相当随意的部分?这就像你试图写一个家庭作业问题来张贴在这里。

标签: python algorithm performance poker


【解决方案1】:

我相信我已经实现了您指定的算法,但是很容易出错,所以如果有任何问题,请告诉我。我几乎只做四项核心评估

  • 是直道吗?
  • 是同花顺吗?
  • 它包含多少个 k 对?
  • 最大的 k 对的大小是多少?

根据这些,我确定了 5 张牌的特定组合可以在一系列 if 语句中形成的最佳手牌,并相应地对牌进行排序。然后,我从一组 7 张牌中创建所有 5 张牌组合的列表,使用此逻辑确定最大/最佳手牌(我重新排列分数和手牌顺序以完成此操作),然后返回该手牌。

from collections import Counter
from itertools import combinations

def num_of_kind(cards):
    return Counter(c[0] for c in cards)

def count_pairs(cards):
    return sum(i > 1 for i in num_of_kind(cards).values())

def largest_pair(cards):
    return max(num_of_kind(cards).values())

def is_straight(cards):
    values = [c[0] for c in cards]
    index = "A23456789TJQKA"["K" in values:].index
    indices = sorted(index(v) for v in values)
    return all(x == y for x, y in enumerate(indices, indices[0]))

def is_flush(cards):
    suit_pop = Counter(c[1] for c in cards)
    return any(s > 4 for s in suit_pop.values())

def straight_sort(cards):
    values = [c[0] for c in cards]
    index = "A23456789TJQKA"["K" in values:].index
    return sorted(cards, key=lambda x:index(x[0]), reverse=True)

def flush_sort(cards):
    suit_pop = Counter(c[1] for c in cards)
    return sorted(cards, key=lambda x: suit_pop[x[1]], reverse=True)

def pair_sort(cards):
    num = num_of_kind(cards)
    return sorted(cards, key=lambda x: num[x[0]], reverse=True)

def card_vals(cards):
    return [c[0] for c in cards]

def score_hand(cards):
    pairs = count_pairs(cards)
    largest = largest_pair(cards)
    straight = is_straight(cards)
    flush = is_flush(cards)

    cards = straight_sort(cards)
    hand_score = 0
    if flush and straight:
        hand_score, cards = 8, flush_sort(cards)
    elif largest == 4:
        hand_score, cards = 7, pair_sort(cards)
    elif pairs == 2 and largest == 3:
        hand_score, cards = 6, pair_sort(cards)
    elif flush:
        hand_score, cards = 5, flush_sort(cards)
    elif straight:
        hand_score = 4
    elif largest == 3:
        hand_score, cards = 3, pair_sort(cards)
    else:
        hand_score, cards = pairs, pair_sort(cards)
    return hand_score, card_vals(cards), cards

def best_hand(cards):
    cards = max(list(combinations(cards, 5)), key=score_hand)
    score, _, hand = score_hand(cards)
    return hand[::-1], score

def main():
    hand = ['2c','Ah','3d', '5s','4h','5d', '3h']
    print(*best_hand(hand))

if __name__ == "__main__":
    main()

我可能会让你厌烦每种方法的细节,但我觉得这一切都是不言自明的。唯一棘手的地方是is_straight(),这只是确定卡片值是否可以按顺序排序的一些索引技巧。

【讨论】:

  • 我的问题被标记为“太宽泛”,但您很快就想出了一个不仅“足够”(而且简短)而且正是我想要的答案。我很遗憾现在不能奖励你 - 如果你知道该联系谁,我当然愿意给你 50 分。
  • 代码确实需要一些工作。使用hand=['2h','9h','3h','5s','4h','5h','3c'],语句print(hand, *best_hand(hand)) 输出['2h', '9h', '3h', '5s', '4h', '5h', '3c'] ['5s', '3h', '4h', '5h', '9h'] 5。但再次感谢您的努力!
  • @CopyPasteIt 我认为这只是对“自然排序”含义的误解,因为我认为这手牌应该是同花,尤其是那些牌,我已经将其更正为首先按最重要的卡片排序。我还发现了一个小错误,套件会导致算法在非常特定的情况下选择手牌的次优变体。
  • 另外,如果你决定奖励赏金,你总是可以根据别人问题的随机答案奖励赏金(你不必是提问者)——PCCG 交易所会这样做经常参加比赛。否则,我理解;毕竟你没有选择关闭问题。
  • 当 HC 分类器相等时,通过从最后(最高)开始(最低)读取,自然排序可以轻松计算出两只手中哪只手更好。所以['Ac', 'Th', 'Tc', 'Ks', 'Kc'] < ['Qc', 'Jd', 'Js', 'Ks', 'Kc'],因为Tc < Js
【解决方案2】:

在设计寻找最佳手牌的算法时,您可以考虑以下几点:

  • 所有比较都涉及比较卡值(数字)和/或花色。因此,您可能需要考虑制作一张卡号列表和一张卡套列表。或者看看itertools 模块的技巧。
  • 同花和同花是花色唯一重要的牌。否则,您只会查看卡号。
  • 同花顺和同花顺是唯一需要查找 5 个连续数字的牌。请记住,这可能包括 A 和面牌。此外,如果 A 包括在内,则它必须在开头或结尾(例如,“Q K A 2 3”不算作顺子)。您可能还想查看模块 more_itertools.consecutive_groups
  • 其他牌(一对、两对、三对、全葫芦、四对)都是基于相同数字出现的频率。如果某个值出现 4 次,则无需检查此列表中的其他手牌。如果一个出现了 3 次,那么检查你是否可以做一个完整的房子,否则它是一个三。您可以像这样从最高手到最低手继续查看此列表,当您找到匹配时停止。
  • 您甚至可以考虑创建一个名为Card 的类,并将您的卡片作为“卡片”类型的对象输入。然后你可以在类中有函数来返回卡片的花色或数值。

【讨论】:

  • 不需要花哨。使用字符串作为卡片。将其按卡值放入字典并进行测试,这对于 4 种、满屋、2 对、三条和一对非常有用。以另一种方式将其放入字典中非常适合同花顺。排序和扫描非常适合寻找顺子,无论是从最初的 7 中还是从同花中。如果没有更好的类型匹配,只需排序并取出最上面的卡片。
  • 永远不要使用字符串来表示卡片。弦乐是给人类的。计算机使用数字:它们可以有效地存储、轻松比较、组合等。这是新手程序员常见的痛苦,导致我们称之为“字符串类型”编程(“强类型”的双关语)。使用数字将使您的程序更小、更简单、更可靠,并且速度提高 100 倍。只需将字符串用于 I/O。
  • 为什么你们两个评论我的回复,而不是发表你自己的回复?
  • @LeeDanielCrocker 对于高性能代码,当然。在 I/O 期间用数字替换短字符串会导致代码速度提高 1-2 个数量级。但是我发现用字符串编写和调试一个简单的工作程序会更快。并且在脚本语言中,没有显着的性能差异。
  • @BillM。对我来说,这是因为我不想为那些似乎不想付出自己努力的人写一个完整的代码答案。所以我把实用的技巧给了那些这样做的人。另一个人出于自己的原因回复我,并在他的个人资料中链接了与此相关的高性能代码。
猜你喜欢
  • 2017-07-11
  • 1970-01-01
  • 1970-01-01
  • 2016-02-24
  • 1970-01-01
  • 1970-01-01
  • 2010-11-19
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多