穆罕默德·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中文網其他相關文章!