识别直线' (来自扑克)使用Python

时间:2016-01-08 19:41:33

标签: python

我正在编写一个Python功能,可以识别出直接的'来自扑克。我的代码可以正常工作并且会识别出直线,但只能给出直线上的数字,而不是套装。此外,其余的代码是用卡的特定格式编写的,即python字典格式,因此我需要此功能也以这种格式返回卡。

到目前为止我的代码:

cards_numbers=[11, 5, 6, 4, 2, 4, 3]
cards_dct={'11D': (11, 'D'), '5S': (5, 'S'), '6S': (6, 'S'), '4D': (4, 'D'), '2H': (2, 'H'), '4C': (4, 'C'), '3D': (3, 'D')}

def is_straight():
    straight=False
    numbers=set(numbers)
    print numbers
    sorted_numbers=sorted(numbers)
    for i in range(len(sorted_numbers)):
        if sorted_numbers[i]-sorted_numbers[i-1]==1 and sorted_numbers[i-1]-sorted_numbers[i-2]==1 and sorted_numbers[i-2]-sorted_numbers[i-3]==1 and sorted_numbers[i-3]-sorted_numbers[i-4]==1:
            straight=True                
            highest_in_straight=sorted_numbers[i]
    straight_numbers=range(highest_in_straight-4,highest_in_straight+1)
    print straight_numbers 
    print self.cards_dct
    for i in cards_dct.keys():
        for j in numbers:
            pattern=re.compile(str(j)+'[DSHC]')
            print re.findall(pattern,i)

上面的代码将识别出一个直接的,但我很难从字典中找回数字和套装。所以我的问题是,我怎样才能让我的代码返回一个字典,只包含直字内的元素(不包括重复的4')?

desired_outout={'5S': (5, 'S'), '6S': (6, 'S'), '2H': (2, 'H'), '4C': (4, 'C'), '3D': (3, 'D')}

3 个答案:

答案 0 :(得分:4)

不要使用字典来表示手牌,使用列表列表或词典列表,例如

cards = [{rank: 5, suit: 'S'}, {rank: 11, suit: 'D'}, ...]

然后,您的is_straight函数可以使用此功能,方法是根据rank元素对其进行排序,然后测试是否sorted_numbers[i].rank == sorted_numbers[i-1].rank + 1等。当它检测到有直线时,可以只使用sorted_cards中的卡片。

答案 1 :(得分:4)

与大多数用作编程任务的扑克(或二十一点)游戏的例子一样,真正的解决方案是修复您的数据结构。事实证明,试图处理卡而不为其创建对象真的很难。您可以使用元组进行管理,但如果您这样做,则使用Enums进行排名和套装通常很有用。让我们走那条路(只是因为Enums比班级更有趣!)

看起来你正在使用Python2,这是一种耻辱。我 强烈 建议您升级到Python3,但如果由于某种原因不能,那么您应该从命令行安装enum34

$ pip install enum34

enum34是Py3.4的enum模块向Python2的后端。然后你可以这样做:

import collections
from enum import IntEnum

Suits = IntEnum("Suits", "spades hearts clubs diamonds")
Ranks = IntEnum("Ranks", "ace two three four five six seven eight nine ten jack queen king")

Card = collections.namedtuple("Card", "rank suit")

然后您的卡初始化变为:

# 2 of spades, 5 of clubs, King of hearts
cardsinfo = [(2, "spades"), (5, "clubs"), (13, "hearts")]
hand = [Card(Ranks(r), Suits[s]) for r,s in cardsinfo]

你的直接检测如下:

def is_straight(hand):
    hand.sort(key=operator.attrgetter("rank"))
    start = hand[0].rank
    straight = [Card(r, None) for r in range(start, start+6)]
    return all(got.rank == want.rank for got,want in zip(hand, straight))

这种方法的好处在于它可以很容易地用于进行多次检查

def is_flush(hand):
    the_suit = hand[0].suit
    return all(c.suit == the_suit for c in hand)

def is_straightflush(hand):
    return is_straight(hand) and is_flush(hand)

def is_royalflush(hand):
    s = hand[0].suit
    royal = [Card(Ranks.ace, s)] + [Card(Ranks(r), s) for r in range(10, 14)]
    return royal == sorted(hand, key=operator.attrgetter("rank"))

def is_pair(hand):
    ranks = collections.Counter(map(operator.attrgetter("rank"), hand))
    return ranks.most_common(1)[1] == 2

def is_three_of_kind(hand):
    ranks = collections.Counter(map(operator.attrgetter("rank"), hand))
    return ranks.most_common(1)[1] == 3

def is_four_of_kind(hand):
    ranks = collections.Counter(map(operator.attrgetter("rank"), hand))
    return ranks.most_common(1)[1] == 4

def is_two_pair(hand):
    ranks = collections.Counter(map(operator.attrgetter("rank"), hand))
    pairs = ranks.most_common(2)
    return pairs[0][1] == 2 and pairs[1][1] == 2

def is_full_house(hand):
    ranks = collections.Counter(map(operator.attrgetter("rank"), hand))
    triplet, pair = ranks.most_common(2)
    return triplet[1] == 3 and pair[1] == 2

答案 2 :(得分:3)

和Barmar一样,我建议使用一个词典列表代表你的手。

hand = [{'rank':10, 'suit':'Spade'}, {'rank':11, 'suit':'Heart'}, ...]

然后你可以通过创建一组排名(这将消除重复)来检查是否有直线。如果最大等级和最小等级加1之间的差异等于集合的大小而且集合是手的大小,则你有一个笔直。它缩减为pigeonhole principle

在Python中实现它非常简单。

在这里验证它是否正常工作:

>>> hand = [{'rank':10, 'suit':'Spade'}, {'rank':11, 'suit':'Heart'}, {'rank':9, 'suit':'Spade'}, {'rank':12, 'suit':'Spade'}, {'rank':8, 'suit':'Spade'}]
>>> rank_set = { card['rank'] for card in hand }
>>> rank_set
set([8, 9, 10, 11, 12])
>>> is_straight = (max(rank_set) - min(rank_set) + 1) == len(hand) and len(rank_set) == len(hand)
>>> is_straight
True

现在检查它是否是直的:

>>> hand = [{'rank':10, 'suit':'Spade'}, {'rank':11, 'suit':'Heart'}, {'rank':9, 'suit':'Spade'}, {'rank':12, 'suit':'Spade'}, {'rank':7, 'suit':'Spade'}]
>>> rank_set = { card['rank'] for card in hand }
>>> is_straight = (max(rank_set) - min(rank_set) + 1) == len(hand) and len(rank_set) == len(hand)
>>> is_straight
False

现在让它成为一个功能:

def is_a_straight(hand):
    rank_set = { card['rank'] for card in hand }
    rank_range = max(rank_set) - min(rank_set) + 1
    return rank_range == len(hand) and len(rank_set) == len(hand)