穆罕默德·S·安瓦尔 (Mohammad S. Anwar) 每周都会发出“每周挑战”,让我们所有人都有机会为每周两次的任务提出解决方案。我的解决方案首先用Python编写,然后转换为Perl。这对我们所有人来说都是练习编码的好方法。
挑战,我的解决方案
给你一个整数数组,@ints。
编写一个脚本来查找最左边的中间索引(MI),即所有可能索引中最小的一个。
中间索引是一个索引,其中 ints[0] ints[1] … ints[MI-1] == ints[MI 1] ints[MI 2] … ints[ints.length-1].
这相对简单。我将位置从 0 循环到比输入长度小 1。在每个位置我都会查看是否满足条件。
def middle_index(ints: list) -> int: for i in range(len(ints)): if sum(ints[:i]) == sum(ints[i + 1:]): # It is, so return this position return i return -1
$ ./ch-1.py 2 3 -1 8 4 3 $ ./ch-1.py 1 -1 4 2 $ ./ch-1.py 2 5 -1
一手抽牌扑克由 5 张牌组成,从 52 张牌中抽取:没有小丑,没有百搭牌。 A 的排名可以高也可以低。
编写一个脚本来确定以下三件事:
系好安全带,因为这将是一篇很长的文章。这也是很长一段时间以来第一次任务不需要任何输入。在我完成的挑战中,最后一个是#177。
为了回答第一个问题,可以发的牌有 311,875,200 种可能的排列(52 × 51 × 50 × 49 × 48)。然而,卡片的顺序并不重要。对于任意五张抽牌,它们可以以 120 种方式排列(5 × 4 × 3 × 2 × 1)。因此共有 2,598,960 种独特的组合。
我首先创建一副纸牌。为此,我的等级(牌号)为 1 到 13。1 是 A,2 到 10 是数字,11 是 Jack,12 是 Queen,K 是 13。我还有一套花色 s、c、d和 h(分别为备用、梅花、菱形和红心)。使用双 for 循环,我生成所有 52 张牌(等级和花色的元组)并将其存储在名为牌组的列表中。
然后,我循环遍历牌组中每个独特的五张牌组合,并确定我持有哪只手牌。最后我打印结果。
def middle_index(ints: list) -> int: for i in range(len(ints)): if sum(ints[:i]) == sum(ints[i + 1:]): # It is, so return this position return i return -1
这是最简单的部分:)
对于 get_hands 函数,我首先创建一个按排名(卡片上的数字)和花色(卡片上的符号)排序的列表字典。我还计算排名的频率,因为这通常用于确定手牌。
$ ./ch-1.py 2 3 -1 8 4 3 $ ./ch-1.py 1 -1 4 2 $ ./ch-1.py 2 5 -1
因此对于卡片 10s、10h、9d、8h、2d,将设置以下内容:
然后是时候确定我握着哪只手了。我们将从同花顺和同花开始。这些是唯一考虑纸牌花色的手牌,并且所有五张牌都是相同花色的。这是当 cards_by_suit 字典只有一个值时确定的。
为了确定它是否是同花顺,我按数字对牌进行排序(从 1 到 13)。如果第一张牌是 1(A)而最后一张牌是 13(K),我会删除第一张牌并将 14 添加到列表的末尾。这使得 10、J、Q、K 和 A 被视为同花顺。当第一张牌的数字与最后一张牌的数字之差为四时,即为同花顺。
from collections import Counter, defaultdict from itertools import combinations def main(): deck = [(rank, suit) for rank in range(1, 14) for suit in ('s', 'c', 'd', 'h')] hands = defaultdict(int) for cards in combinations(deck, 5): hand = get_hand(cards) hands[hand] += 1 display_results(hands)
对于四张同花牌(四张一牌,随机最后一张牌)和葫芦(三张一牌,两张不同牌),我可以使用 count_by_rank 字典来查看这手牌是否匹配指定的标准。
def get_hand(cards): cards_by_rank = defaultdict(list) cards_by_suit = defaultdict(list) for card in cards: number, suit = card cards_by_rank[number].append(card[1]) cards_by_suit[suit].append(card[0]) count_by_rank = Counter(len(cards_by_rank[r]) for r in cards_by_rank)
为了确定这手牌是否是直牌,我使用与同花顺类似的逻辑。我首先检查我是否有五个唯一的等级(卡号),对它们进行排序,如果需要则移动 A,并检查高低之间的差异是否为 4。
if len(cards_by_suit) == 1: cards = sorted(cards_by_rank) if cards[0] == 1 and cards[4] == 13: cards.pop(0) cards.append(14) if cards[4] - cards[0] == 4: return 'Straight flush' return 'Flush'
三张同种(三张同点数的牌,两张不同点数的牌),两对(两张同点数的牌,两张不同点数的牌,随机最后一张牌),一对(两张同点数的牌)等级(每张不同等级的三张牌)都可以使用 count_by_rank 字典来计算。
if count_by_rank[4]: return 'Four of a kind' if count_by_rank[3] and count_by_rank[2]: return 'Full house'
最后,如果没有匹配项,则返回“高牌”。如果你拿着这手牌,你绝对不会想拿你的房子去赌:)
if len(cards_by_rank) == 5: # Get the card ranks in the possible flush cards = sorted(cards_by_rank) if cards[0] == 1 and cards[4] == 13: cards.pop(0) cards.append(14) if cards[4] - cards[0] == 4: return 'Straight'
display_results 函数只是以统一的布局显示结果(按排名排序)。正如开头提到的,每个组合都有 120 种排列方式,可以订购卡片。
if count_by_rank[3]: return 'Three of a kind' if count_by_rank[2] == 2: return 'Two pair' if count_by_rank[2]: return 'One pair'
return 'High card'
在我的家用电脑上运行大约需要 15 秒。
从底行可以看到,我们有 2,598,960 种组合和 311,875,200 种排列。这与我们期望在输出中看到的内容相符。
以上是指数和扑克游戏的详细内容。更多信息请关注PHP中文网其他相关文章!