我正在编写一个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')}
答案 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)