import time, random ranks = ('2', '3', '4', '5', '6', '7', '8', '9', '10', 'J', 'Q', 'K', 'A') suits = ('Hearts', 'Clubs', 'Spades', 'Diamonds') faces = ('J', 'Q', 'K', 'A') hand_types = ( 'high card', 'pair', 'two pair', 'three of a kind', 'straight', 'flush', 'full house', 'four of a kind', 'straight flush', 'royal flush', ) card_value = { '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9, '10': 10, 'J': 11, 'Q': 12, 'K': 13, 'A': 14, } class Card: def __init__(self, rank, suit): self.rank = rank self.suit = suit self.value = card_value[rank] def __str__(self): return self.rank + '-' + self.suit class Deck: def __init__(self): self.cards = [] for rank in ranks: for suit in suits: c = Card(rank, suit) self.cards.append(c) def shuffle(self): random.shuffle(self.cards) def draw_cards(self, n=1): cards = [] for i in range(n): if not self.cards: raise Exception("No more cards: empty deck!") card = self.cards.pop() cards.append(card) return cards def __str__(self): cards = [] for c in self.cards: cards.append(str(c)) return str(cards) class Hand: """A collection of cards that a player gets from the dealer in a game. in some card games, a player may hold several hands! In our case, each player has exactly one hand (as a member) """ def __init__(self, cards): self.cards = cards # Initial list of cards in hand def add(self, cards): # Add a list of cards to the hand during the game self.cards.extend(cards) def type(self): def f(card): return card.value self.cards.sort(key = f) ### checking flush ... count = dict() for suit in suits: count[suit] = 0 for card in self.cards: count[card.suit] += 1 for suit in count: if count[suit] == 5: # check if have 'straight flush' and then 'royal flush' first ... # after that ... return 'flush', None, None ### checking four/three/pair ... cards_dict = dict() for rank in ranks: cards_dict[rank] = [] for card in self.cards: rank = card.rank cards_dict[rank].append(card) for rank in cards_dict: if len(cards_dict[rank]) == 4: fifth_card = set(self.cards).difference(cards_dict[rank]).pop() return 'four of a kind', rank, fifth_card.rank elif len(cards_dict[rank]) == 3: # check first for 'full house' # if not, then ... other_two_cards = set(self.cards).difference(cards_dict[rank]) return 'three of a kind', rank, other_two_cards elif len(cards_dict[rank]) == 2: # check first for 'two pair' # if not, then ... other_three_cards = set(self.cards).difference(cards_dict[rank]) return 'pair', rank, other_three_cards # This is just the start ... # there are 10 types to check # 'royal flush', # 'straight flush', # 'four of a kind', # 'full house', # 'flush', # 'straight', # 'three of a kind', # 'two pair', # 'pair', # 'high card', # could it be that the same hand will belong to two types? # Temporary line - should be removed after all 10 types are handled! return None, None, None def __eq__(self, other): # self equals other pass def __lt__(self, other): # self less than other # Compare two hands and decide which is less than the other? # Usage: h1 < h2 # max([h1, h2, h3, h4]) # start: # type1,b1,c1 = self.type() # type2,b1,c1 = other.type() # i1 = hand_types.index(type1) # i2 = hand_types.index(type2) # if i1 < i2: # return True # elif i1 > i2: # return False # else: # same type - now the hard work starts ... pass def __str__(self): cards = [] for c in self.cards: cards.append(str(c)) return str(cards) class Player: def __init__(self, name, budget, strategy=None): self.name = name # Player's name self.budget = budget # Number of dollars for bets (one bet = 1 dollar) self.strategy = strategy # Strategy function (see below) self.hand = None # player's hand (in some version, a player may have several hands!) self.state = 'idle' # must be 'idle', 'active', 'fold' def bet(self, bool): "bool is a Boolean value: True means bet, False means fold" pass def exchange(self): "Exchange 1 to 3 cards" # Use self.strategy to decide which cards to replace? # Give them to the dealer and receive new cards pass def __str__(self): # Make sure to have a good string to print here ... pass class Dealer(Player): def __init__(self): self.deck = Deck() self.deck.shuffle() pass class Game: def __init__(players): self.dealer = Dealer() self.players = players self.log # keep track of what is going during the game (info for debug) def run(self): "Manage all 6 stages ..." pass def stage1(self): pass def stage2(self): pass def stage3(self): pass def stage4(self): pass def stage5(self): pass def stage6(self): # showdown pass #-------------------- STRATEGIES -------------------- # A strategy is any function f(stage, player_hand, bets) which accepts a stage, player hand and bets state # and returns a next move advise for the player: which cards to exchange? bet? raise bet?? # Here is a simple example (which is probably very bad) def strategy1(stage, hand, bets): type, a, b = hand.type() i = hand_types.index(type) if stage == 3: if i<2: return 'fold' else: return 'bet' elif stage == 4: if type == 'pair' or type == 'three of a kind' or type == 'four of a kind': return b elif stage == 5: active_players = [x for x in bets if x==1 or x==2] if len(active_players) == 0: return 'bet' if type == 'pair' and a >= 12 or i>=2: return 'bet' else: return 'fold' # Tests are done in a separate file: tests.py