Source code for poker.card

# -*- coding: utf-8 -*-
from __future__ import unicode_literals, absolute_import, division, print_function

import itertools
from functools import total_ordering
from ._common import PokerEnum, _ReprMixin


__all__ = ['Suit', 'Rank', 'Card', 'FACE_RANKS', 'BROADWAY_RANKS']


[docs]class Suit(PokerEnum): __order__ = 'CLUBS DIAMONDS HEARTS SPADES' CLUBS = '♣', 'c', 'clubs' DIAMONDS = '♦', 'd', 'diamonds' HEARTS = '♥', 'h', 'hearts' SPADES = '♠', 's', 'spades'
# Can't make alias with redefined value property # because of a bug in stdlib enum module (line 162) # C = '♣', 'c', 'C', 'clubs'
[docs]class Rank(PokerEnum): __order__ = 'DEUCE THREE FOUR FIVE SIX SEVEN EIGHT NINE TEN JACK QUEEN KING ACE' DEUCE = '2', 2 THREE = '3', 3 FOUR = '4', 4 FIVE = '5', 5 SIX = '6', 6 SEVEN = '7', 7 EIGHT = '8', 8 NINE = '9', 9 TEN = 'T', 10 JACK = 'J', QUEEN = 'Q', KING = 'K', ACE = 'A', 1
[docs] @classmethod def difference(cls, first, second): """Tells the numerical difference between two ranks.""" # so we always get a Rank instance even if string were passed in first, second = cls(first), cls(second) rank_list = list(cls) return abs(rank_list.index(first) - rank_list.index(second))
FACE_RANKS = Rank('J'), Rank('Q'), Rank('K') BROADWAY_RANKS = Rank('T'), Rank('J'), Rank('Q'), Rank('K'), Rank('A') class _CardMeta(type): def __new__(metacls, clsname, bases, classdict): """Cache all possible Card instances on the class itself.""" cls = super(_CardMeta, metacls).__new__(metacls, clsname, bases, classdict) cls._all_cards = list(cls('{}{}'.format(rank, suit)) for rank, suit in itertools.product(Rank, Suit)) return cls def make_random(cls): """Returns a random Card instance.""" self = object.__new__(cls) self.rank = Rank.make_random() self.suit = Suit.make_random() return self def __iter__(cls): return iter(cls._all_cards)
[docs]@total_ordering class Card(_ReprMixin): """Represents a Card, which consists a Rank and a Suit.""" __metaclass__ = _CardMeta __slots__ = ('rank', 'suit') def __new__(cls, card): if isinstance(card, cls): return card if len(card) != 2: raise ValueError('length should be two in %r' % card) self = object.__new__(cls) self.rank = Rank(card[0]) self.suit = Suit(card[1]) return self def __hash__(self): return hash(self.rank) + hash(self.suit) def __getstate__(self): return {'rank': self.rank, 'suit': self.suit} def __setstate__(self, state): self.rank, self.suit = state['rank'], state['suit'] def __eq__(self, other): if self.__class__ is other.__class__: return self.rank == other.rank and self.suit == other.suit return NotImplemented def __lt__(self, other): if self.__class__ is not other.__class__: return NotImplemented # with same ranks, suit counts if self.rank == other.rank: return self.suit < other.suit return self.rank < other.rank def __unicode__(self): return '{}{}'.format(self.rank, self.suit) @property def is_face(self): return self.rank in FACE_RANKS @property def is_broadway(self): return self.rank in BROADWAY_RANKS