📚 The CoCalc Library - books, templates and other resources
License: OTHER
"""This module contains a code example related to12Think Python, 2nd Edition3by Allen Downey4http://thinkpython2.com56Copyright 2015 Allen Downey78License: http://creativecommons.org/licenses/by/4.0/9"""1011from __future__ import print_function, division1213from Card import Hand, Deck141516class Hist(dict):17"""A map from each item (x) to its frequency."""1819def __init__(self, seq=[]):20"Creates a new histogram starting with the items in seq."21for x in seq:22self.count(x)2324def count(self, x, f=1):25"Increments (or decrements) the counter associated with item x."26self[x] = self.get(x, 0) + f27if self[x] == 0:28del self[x]293031class PokerHand(Hand):32"""Represents a poker hand."""3334all_labels = ['straightflush', 'fourkind', 'fullhouse', 'flush',35'straight', 'threekind', 'twopair', 'pair', 'highcard']3637def make_histograms(self):38"""Computes histograms for suits and hands.3940Creates attributes:4142suits: a histogram of the suits in the hand.43ranks: a histogram of the ranks.44sets: a sorted list of the rank sets in the hand.45"""46self.suits = Hist()47self.ranks = Hist()4849for c in self.cards:50self.suits.count(c.suit)51self.ranks.count(c.rank)5253self.sets = list(self.ranks.values())54self.sets.sort(reverse=True)5556def has_highcard(self):57"""Returns True if this hand has a high card."""58return len(self.cards)5960def check_sets(self, *t):61"""Checks whether self.sets contains sets that are62at least as big as the requirements in t.6364t: list of int65"""66for need, have in zip(t, self.sets):67if need > have:68return False69return True7071def has_pair(self):72"""Checks whether this hand has a pair."""73return self.check_sets(2)7475def has_twopair(self):76"""Checks whether this hand has two pair."""77return self.check_sets(2, 2)7879def has_threekind(self):80"""Checks whether this hand has three of a kind."""81return self.check_sets(3)8283def has_fourkind(self):84"""Checks whether this hand has four of a kind."""85return self.check_sets(4)8687def has_fullhouse(self):88"""Checks whether this hand has a full house."""89return self.check_sets(3, 2)9091def has_flush(self):92"""Checks whether this hand has a flush."""93for val in self.suits.values():94if val >= 5:95return True96return False9798def has_straight(self):99"""Checks whether this hand has a straight."""100# make a copy of the rank histogram before we mess with it101ranks = self.ranks.copy()102ranks[14] = ranks.get(1, 0)103104# see if we have 5 in a row105return self.in_a_row(ranks, 5)106107def in_a_row(self, ranks, n=5):108"""Checks whether the histogram has n ranks in a row.109110hist: map from rank to frequency111n: number we need to get to112"""113count = 0114for i in range(1, 15):115if ranks.get(i, 0):116count += 1117if count == n:118return True119else:120count = 0121return False122123def has_straightflush(self):124"""Checks whether this hand has a straight flush.125126Clumsy algorithm.127"""128# make a set of the (rank, suit) pairs we have129s = set()130for c in self.cards:131s.add((c.rank, c.suit))132if c.rank == 1:133s.add((14, c.suit))134135# iterate through the suits and ranks and see if we136# get to 5 in a row137for suit in range(4):138count = 0139for rank in range(1, 15):140if (rank, suit) in s:141count += 1142if count == 5:143return True144else:145count = 0146return False147148def has_straightflush(self):149"""Checks whether this hand has a straight flush.150151Better algorithm (in the sense of being more demonstrably152correct).153"""154# partition the hand by suit and check each155# sub-hand for a straight156d = {}157for c in self.cards:158d.setdefault(c.suit, PokerHand()).add_card(c)159160# see if any of the partitioned hands has a straight161for hand in d.values():162if len(hand.cards) < 5:163continue164hand.make_histograms()165if hand.has_straight():166return True167return False168169def classify(self):170"""Classifies this hand.171172Creates attributes:173labels:174"""175self.make_histograms()176177self.labels = []178for label in PokerHand.all_labels:179f = getattr(self, 'has_' + label)180if f():181self.labels.append(label)182183184class PokerDeck(Deck):185"""Represents a deck of cards that can deal poker hands."""186187def deal_hands(self, num_cards=5, num_hands=10):188"""Deals hands from the deck and returns Hands.189190num_cards: cards per hand191num_hands: number of hands192193returns: list of Hands194"""195hands = []196for i in range(num_hands):197hand = PokerHand()198self.move_cards(hand, num_cards)199hand.classify()200hands.append(hand)201return hands202203204def main():205# the label histogram: map from label to number of occurances206lhist = Hist()207208# loop n times, dealing 7 hands per iteration, 7 cards each209n = 10000210for i in range(n):211if i % 1000 == 0:212print(i)213214deck = PokerDeck()215deck.shuffle()216217hands = deck.deal_hands(7, 7)218for hand in hands:219for label in hand.labels:220lhist.count(label)221222# print the results223total = 7.0 * n224print(total, 'hands dealt:')225226for label in PokerHand.all_labels:227freq = lhist.get(label, 0)228if freq == 0:229continue230p = total / freq231print('%s happens one time in %.2f' % (label, p))232233234if __name__ == '__main__':235main()236237238239