Skip to content

Instantly share code, notes, and snippets.

@McSinyx
Last active July 2, 2016 07:32
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save McSinyx/5ecd6d90e9866617e136b89713fcd23d to your computer and use it in GitHub Desktop.
Save McSinyx/5ecd6d90e9866617e136b89713fcd23d to your computer and use it in GitHub Desktop.
Probabilities of Poker hands
#!/usr/bin/env python3
"""
This module contains code from
Think Python by Allen B. Downey
http://thinkpython.com/code/Card.py
Copyright 2016 Raphael McSinyx
Copyright 2012 Allen B. Downey
License: GNU GPLv3 http://www.gnu.org/licenses/gpl.html
"""
import random
from itertools import product
from functools import total_ordering
@total_ordering
class Card():
"""
Represents a standard playing card.
Attributes:
suit: int from 0 to 3
rank: int 1 to 13
"""
suit_names = ('Clubs', 'Diamonds', 'Hearts', 'Spades')
rank_names = (None, 'Ace', 'Two', 'Three', 'Four', 'Five', 'Six', 'Seven',
'Eight', 'Nine', 'Ten', 'Jack', 'Queen', 'King')
def __init__(self, suit=0, rank=1):
self.suit = suit
self.rank = rank
def __str__(self):
return "{} of {}".format(Card.rank_names[self.rank],
Card.suit_names[self.suit])
def __eq__(self, other):
return (self.suit, self.rank) == (other.suit, other.rank)
def __lt__(self, other):
return (self.suit, self.rank) < (other.suit, other.rank)
class Deck():
"""
Represents a deck of cards.
Attributes:
cards: list of Card objects.
"""
def __init__(self):
cards = product(range(4), range(1, 14))
self.cards = [Card(suit, rank) for suit, rank in cards]
def __str__(self):
return '\n'.join(str(card) for card in self.cards)
def sort(self): # 18.2
self.cards.sort()
def shuffle(self):
random.shuffle(self.cards)
def pop_card(self):
return self.cards.pop()
def add_cards(self, cards):
if isinstance(cards, list):
self.cards.extend(cards)
else:
self.cards.append(cards)
def move_cards(self, hand, num):
hand.add_cards([self.pop_card() for _ in range(num)])
def deal_hands(self, hands, cards): # 18.3
res = []
for i in range(hands):
hand = Hand()
self.move_cards(hand, cards)
res.append(hand)
return res
def remove_card(self, card):
self.cards.remove(card)
class Hand(Deck):
"""
Represents a hand of playing cards.
"""
def __init__(self, cards=[], label=''):
self.cards = list(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)
#!/usr/bin/env python3
"""
This module contains code from
Think Python by Allen B. Downey
http://thinkpython.com/code/PokerHand.py
Copyright 2016 Raphael McSinyx
Copyright 2012 Allen B. Downey
License: GNU GPLv3 http://www.gnu.org/licenses/gpl.html
"""
from sys import argv
from itertools import islice, cycle
from functools import reduce
from operator import mul
from Card import *
class PokerHand(Hand):
def suit_hist(self):
"""
Build a histogram of the suits that appear in the hand.
Store the result in attribute suits.
"""
self.suits = {}
for card in self.cards:
self.suits[card.suit] = self.suits.get(card.suit, 0) + 1
def rank_hist(self):
"""
Build a histogram of the ranks that appear in the hand.
Store the result in attribute ranks.
"""
self.ranks = {}
for card in self.cards:
self.ranks[card.rank] = self.ranks.get(card.rank, 0) + 1
def has_2pairs(self):
"""
Return True if the hand has 2 pairs, False otherwise.
"""
self.rank_hist()
foo = True
for val in self.ranks.values():
if val >= 2:
foo = not foo
if foo:
return True
return False
def has_set_of(self, n):
"""
Return True if the hand has at least n cards of a same rank,
False otherwise.
"""
self.rank_hist()
return not all(val < n for val in self.ranks.values())
def has_straight(self):
"""
Return True if the hand has straight, False otherwise.
"""
self.rank_hist()
g = (islice(cycle(range(1, 14)), i, i + 5) for i in range(0, 10))
for i in g:
if all(j in self.ranks for j in i):
return True
return False
def has_flush(self):
"""
Return True if the hand has a flush, False otherwise.
"""
self.suit_hist()
return not all(val < 5 for val in self.suits.values())
def has_straight_flush(self, current=0):
"""
Return True if the hand has a straight flush, False otherwise.
"""
l = self.cards
length = len(l)
if length > 5:
for i in range(current, length):
p = PokerHand(islice(cycle(l), i, i + length - 1))
if p.has_straight_flush(i):
return True
elif length == 5:
return self.has_flush() and self.has_straight()
return False
def classify(self):
"""
Set the label attribute of the hand.
"""
if self.has_straight_flush():
self.label = "Straight flush"
elif self.has_set_of(4):
self.label = "Four of a kind"
elif self.has_2pairs() and self.has_set_of(3):
self.label = "Full house"
elif self.has_flush():
self.label = "Flush"
elif self.has_straight():
self.label = "Straight"
elif self.has_set_of(3):
self.label = "Three of a kind"
elif self.has_2pairs():
self.label = "Two pairs"
elif self.has_set_of(2):
self.label = "Pair"
else:
self.label = "High card"
def main(cards_per_hand=7, samples=0, *args):
try:
cards_per_hand = int(cards_per_hand) % 52
samples = abs(int(samples))
except:
print("Usage: PokerHand.py [cards per hand] [sample size]")
else:
t = ("Straight flush", "Four of a kind", "Full house", "Flush",
"Straight", "Three of a kind", "Two pairs", "Pair", "High card")
d = dict.fromkeys(t, 0)
def deal_hand():
deck = Deck()
deck.shuffle()
hand = PokerHand()
deck.move_cards(hand, cards_per_hand)
hand.classify()
d[hand.label] += 1
if samples:
for _ in range(samples):
deal_hand()
else:
while not reduce(mul, d.values()):
deal_hand()
samples += 1
print("Sample size:", samples)
print("Cards per hand:", cards_per_hand)
for s in t:
print("{}: {} ({:%})".format(s, d[s], d[s] / samples))
if __name__ == '__main__':
main(*argv[1:])
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment