"""This module contains a code example related to
Think Python, 2nd Edition
by Allen Downey
http://thinkpython2.com
Copyright 2015 Allen Downey
License: http://creativecommons.org/licenses/by/4.0/
"""
from __future__ import print_function, division
import random
class Card:
"""Represents a standard playing card.
Attributes:
suit: integer 0-3
rank: integer 1-13
"""
suit_names = ["Clubs", "Diamonds", "Hearts", "Spades"]
rank_names = [None, "Ace", "2", "3", "4", "5", "6", "7",
"8", "9", "10", "Jack", "Queen", "King"]
def __init__(self, suit=0, rank=2):
self.suit = suit
self.rank = rank
def __str__(self):
"""Returns a human-readable string representation."""
return '%s of %s' % (Card.rank_names[self.rank],
Card.suit_names[self.suit])
def __eq__(self, other):
"""Checks whether self and other have the same rank and suit.
returns: boolean
"""
return self.suit == other.suit and self.rank == other.rank
def __lt__(self, other):
"""Compares this card to other, first by suit, then rank.
returns: boolean
"""
t1 = self.suit, self.rank
t2 = other.suit, other.rank
return t1 < t2
class Deck:
"""Represents a deck of cards.
Attributes:
cards: list of Card objects.
"""
def __init__(self):
"""Initializes the Deck with 52 cards.
"""
self.cards = []
for suit in range(4):
for rank in range(1, 14):
card = Card(suit, rank)
self.cards.append(card)
def __str__(self):
"""Returns a string representation of the deck.
"""
res = []
for card in self.cards:
res.append(str(card))
return '\n'.join(res)
def add_card(self, card):
"""Adds a card to the deck.
card: Card
"""
self.cards.append(card)
def remove_card(self, card):
"""Removes a card from the deck or raises exception if it is not there.
card: Card
"""
self.cards.remove(card)
def pop_card(self, i=-1):
"""Removes and returns a card from the deck.
i: index of the card to pop; by default, pops the last card.
"""
return self.cards.pop(i)
def shuffle(self):
"""Shuffles the cards in this deck."""
random.shuffle(self.cards)
def sort(self):
"""Sorts the cards in ascending order."""
self.cards.sort()
def move_cards(self, hand, num):
"""Moves the given number of cards from the deck into the Hand.
hand: destination Hand object
num: integer number of cards to move
"""
for i in range(num):
hand.add_card(self.pop_card())
class Hand(Deck):
"""Represents a hand of playing cards."""
def __init__(self, label=''):
self.cards = []
self.label = label
def find_defining_class(obj, method_name):
"""Finds and returns the class object that will provide
the definition of method_name (as a string) if it is
invoked on obj.
obj: any python object
method_name: string method name
"""
for ty in type(obj).mro():
if method_name in ty.__dict__:
return ty
return None
if __name__ == '__main__':
deck = Deck()
deck.shuffle()
hand = Hand()
print(find_defining_class(hand, 'shuffle'))
deck.move_cards(hand, 5)
hand.sort()
print(hand)
class Markov:
def __init__(self):
self.suffix_map = {}
self.prefix = ()
下一步,我们把这些函数转换为方法。例如:下面是process_word:
def process_word(self, word, order=2):
if len(self.prefix) < order:
self.prefix += (word,)
return
try:
self.suffix_map[self.prefix].append(word)
except KeyError:
# if there is no entry for this prefix, make one
self.suffix_map[self.prefix] = [word]
self.prefix = shift(self.prefix, word)
"""This module contains a code example related to
Think Python, 2nd Edition
by Allen Downey
http://thinkpython2.com
Copyright 2015 Allen Downey
License: http://creativecommons.org/licenses/by/4.0/
"""
from __future__ import print_function, division
import sys
import string
import random
# global variables
suffix_map = {} # map from prefixes to a list of suffixes
prefix = () # current tuple of words
def process_file(filename, order=2):
"""Reads a file and performs Markov analysis.
filename: string
order: integer number of words in the prefix
returns: map from prefix to list of possible suffixes.
"""
fp = open(filename)
skip_gutenberg_header(fp)
for line in fp:
if line.startswith('*** END OF THIS'):
break
for word in line.rstrip().split():
process_word(word, order)
def skip_gutenberg_header(fp):
"""Reads from fp until it finds the line that ends the header.
fp: open file object
"""
for line in fp:
if line.startswith('*** START OF THIS'):
break
def process_word(word, order=2):
"""Processes each word.
word: string
order: integer
During the first few iterations, all we do is store up the words;
after that we start adding entries to the dictionary.
"""
global prefix
if len(prefix) < order:
prefix += (word,)
return
try:
suffix_map[prefix].append(word)
except KeyError:
# if there is no entry for this prefix, make one
suffix_map[prefix] = [word]
prefix = shift(prefix, word)
def random_text(n=100):
"""Generates random wordsfrom the analyzed text.
Starts with a random prefix from the dictionary.
n: number of words to generate
"""
# choose a random prefix (not weighted by frequency)
start = random.choice(list(suffix_map.keys()))
for i in range(n):
suffixes = suffix_map.get(start, None)
if suffixes == None:
# if the start isn't in map, we got to the end of the
# original text, so we have to start again.
random_text(n-i)
return
# choose a random suffix
word = random.choice(suffixes)
print(word, end=' ')
start = shift(start, word)
def shift(t, word):
"""Forms a new tuple by removing the head and adding word to the tail.
t: tuple of strings
word: string
Returns: tuple of strings
"""
return t[1:] + (word,)
def main(script, filename='158-0.txt', n=100, order=2):
try:
n = int(n)
order = int(order)
except ValueError:
print('Usage: %d filename [# of words] [prefix length]' % script)
else:
process_file(filename, order)
random_text(n)
print()
if __name__ == '__main__':
main(*sys.argv)
"""This module contains a code example related to
Think Python, 2nd Edition
by Allen Downey
http://thinkpython2.com
Copyright 2015 Allen Downey
License: http://creativecommons.org/licenses/by/4.0/
"""
from __future__ import print_function, division
import random
class Card:
"""Represents a standard playing card.
Attributes:
suit: integer 0-3
rank: integer 1-13
"""
suit_names = ["Clubs", "Diamonds", "Hearts", "Spades"]
rank_names = [None, "Ace", "2", "3", "4", "5", "6", "7",
"8", "9", "10", "Jack", "Queen", "King"]
def __init__(self, suit=0, rank=2):
self.suit = suit
self.rank = rank
def __str__(self):
"""Returns a human-readable string representation."""
return '%s of %s' % (Card.rank_names[self.rank],
Card.suit_names[self.suit])
def __eq__(self, other):
"""Checks whether self and other have the same rank and suit.
returns: boolean
"""
return self.suit == other.suit and self.rank == other.rank
def __lt__(self, other):
"""Compares this card to other, first by suit, then rank.
returns: boolean
"""
t1 = self.suit, self.rank
t2 = other.suit, other.rank
return t1 < t2
class Deck:
"""Represents a deck of cards.
Attributes:
cards: list of Card objects.
"""
def __init__(self):
"""Initializes the Deck with 52 cards.
"""
self.cards = []
for suit in range(4):
for rank in range(1, 14):
card = Card(suit, rank)
self.cards.append(card)
def __str__(self):
"""Returns a string representation of the deck.
"""
res = []
for card in self.cards:
res.append(str(card))
return '\n'.join(res)
def add_card(self, card):
"""Adds a card to the deck.
card: Card
"""
self.cards.append(card)
def remove_card(self, card):
"""Removes a card from the deck or raises exception if it is not there.
card: Card
"""
self.cards.remove(card)
def pop_card(self, i=-1):
"""Removes and returns a card from the deck.
i: index of the card to pop; by default, pops the last card.
"""
return self.cards.pop(i)
def shuffle(self):
"""Shuffles the cards in this deck."""
random.shuffle(self.cards)
def sort(self):
"""Sorts the cards in ascending order."""
self.cards.sort()
def move_cards(self, hand, num):
"""Moves the given number of cards from the deck into the Hand.
hand: destination Hand object
num: integer number of cards to move
"""
for i in range(num):
hand.add_card(self.pop_card())
class Hand(Deck):
"""Represents a hand of playing cards."""
def __init__(self, label=''):
self.cards = []
self.label = label
def find_defining_class(obj, method_name):
"""Finds and returns the class object that will provide
the definition of method_name (as a string) if it is
invoked on obj.
obj: any python object
method_name: string method name
"""
for ty in type(obj).mro():
if method_name in ty.__dict__:
return ty
return None
if __name__ == '__main__':
deck = Deck()
deck.shuffle()
hand = Hand()
print(find_defining_class(hand, 'shuffle'))
deck.move_cards(hand, 5)
hand.sort()
print(hand)
"""This module contains a code example related to
Think Python, 2nd Edition
by Allen Downey
http://thinkpython2.com
Copyright 2015 Allen Downey
License: http://creativecommons.org/licenses/by/4.0/
"""
from __future__ import print_function, division
from Card import Hand, Deck
class PokerHand(Hand):
"""Represents a poker hand."""
def suit_hist(self):
"""Builds a histogram of the suits that appear in the hand.
Stores the result in attribute suits.
"""
self.suits = {}
for card in self.cards:
self.suits[card.suit] = self.suits.get(card.suit, 0) + 1
def has_flush(self):
"""Returns True if the hand has a flush, False otherwise.
Note that this works correctly for hands with more than 5 cards.
"""
self.suit_hist()
for val in self.suits.values():
if val >= 5:
return True
return False
if __name__ == '__main__':
# make a deck
deck = Deck()
deck.shuffle()
# deal the cards and classify the hands
for i in range(7):
hand = PokerHand()
deck.move_cards(hand, 7)
hand.sort()
print(hand)
print(hand.has_flush())
print('')
"""This module contains a code example related to
Think Python, 2nd Edition
by Allen Downey
http://thinkpython2.com
Copyright 2015 Allen Downey
License: http://creativecommons.org/licenses/by/4.0/
"""
from __future__ import print_function, division
from Card import Hand, Deck
class Hist(dict):
"""A map from each item (x) to its frequency."""
def __init__(self, seq=[]):
"Creates a new histogram starting with the items in seq."
for x in seq:
self.count(x)
def count(self, x, f=1):
"Increments (or decrements) the counter associated with item x."
self[x] = self.get(x, 0) + f
if self[x] == 0:
del self[x]
class PokerHand(Hand):
"""Represents a poker hand."""
all_labels = ['straightflush', 'fourkind', 'fullhouse', 'flush',
'straight', 'threekind', 'twopair', 'pair', 'highcard']
def make_histograms(self):
"""Computes histograms for suits and hands.
Creates attributes:
suits: a histogram of the suits in the hand.
ranks: a histogram of the ranks.
sets: a sorted list of the rank sets in the hand.
"""
self.suits = Hist()
self.ranks = Hist()
for c in self.cards:
self.suits.count(c.suit)
self.ranks.count(c.rank)
self.sets = list(self.ranks.values())
self.sets.sort(reverse=True)
def has_highcard(self):
"""Returns True if this hand has a high card."""
return len(self.cards)
def check_sets(self, *t):
"""Checks whether self.sets contains sets that are
at least as big as the requirements in t.
t: list of int
"""
for need, have in zip(t, self.sets):
if need > have:
return False
return True
def has_pair(self):
"""Checks whether this hand has a pair."""
return self.check_sets(2)
def has_twopair(self):
"""Checks whether this hand has two pair."""
return self.check_sets(2, 2)
def has_threekind(self):
"""Checks whether this hand has three of a kind."""
return self.check_sets(3)
def has_fourkind(self):
"""Checks whether this hand has four of a kind."""
return self.check_sets(4)
def has_fullhouse(self):
"""Checks whether this hand has a full house."""
return self.check_sets(3, 2)
def has_flush(self):
"""Checks whether this hand has a flush."""
for val in self.suits.values():
if val >= 5:
return True
return False
def has_straight(self):
"""Checks whether this hand has a straight."""
# make a copy of the rank histogram before we mess with it
ranks = self.ranks.copy()
ranks[14] = ranks.get(1, 0)
# see if we have 5 in a row
return self.in_a_row(ranks, 5)
def in_a_row(self, ranks, n=5):
"""Checks whether the histogram has n ranks in a row.
hist: map from rank to frequency
n: number we need to get to
"""
count = 0
for i in range(1, 15):
if ranks.get(i, 0):
count += 1
if count == n:
return True
else:
count = 0
return False
def has_straightflush(self):
"""Checks whether this hand has a straight flush.
Clumsy algorithm.
"""
# make a set of the (rank, suit) pairs we have
s = set()
for c in self.cards:
s.add((c.rank, c.suit))
if c.rank == 1:
s.add((14, c.suit))
# iterate through the suits and ranks and see if we
# get to 5 in a row
for suit in range(4):
count = 0
for rank in range(1, 15):
if (rank, suit) in s:
count += 1
if count == 5:
return True
else:
count = 0
return False
def has_straightflush(self):
"""Checks whether this hand has a straight flush.
Better algorithm (in the sense of being more demonstrably
correct).
"""
# partition the hand by suit and check each
# sub-hand for a straight
d = {}
for c in self.cards:
d.setdefault(c.suit, PokerHand()).add_card(c)
# see if any of the partitioned hands has a straight
for hand in d.values():
if len(hand.cards) < 5:
continue
hand.make_histograms()
if hand.has_straight():
return True
return False
def classify(self):
"""Classifies this hand.
Creates attributes:
labels:
"""
self.make_histograms()
self.labels = []
for label in PokerHand.all_labels:
f = getattr(self, 'has_' + label)
if f():
self.labels.append(label)
class PokerDeck(Deck):
"""Represents a deck of cards that can deal poker hands."""
def deal_hands(self, num_cards=5, num_hands=10):
"""Deals hands from the deck and returns Hands.
num_cards: cards per hand
num_hands: number of hands
returns: list of Hands
"""
hands = []
for i in range(num_hands):
hand = PokerHand()
self.move_cards(hand, num_cards)
hand.classify()
hands.append(hand)
return hands
def main():
# the label histogram: map from label to number of occurances
lhist = Hist()
# loop n times, dealing 7 hands per iteration, 7 cards each
n = 10000
for i in range(n):
if i % 1000 == 0:
print(i)
deck = PokerDeck()
deck.shuffle()
hands = deck.deal_hands(7, 7)
for hand in hands:
for label in hand.labels:
lhist.count(label)
# print the results
total = 7.0 * n
print(total, 'hands dealt:')
for label in PokerHand.all_labels:
freq = lhist.get(label, 0)
if freq == 0:
continue
p = total / freq
print('%s happens one time in %.2f' % (label, p))
if __name__ == '__main__':
main()