Dec-28-2021, 09:04 PM
(Dec-28-2021, 08:58 PM)deanhystad Wrote: I added in some poker rules to identify different hands. Still having a problem with two pair.
import collections import copy import random class Card(): """A playing card that has a rank and suit""" # These are class variables. They are associated with the class, not instances of the class suit_names = ["Clubs", "Diamonds", "Hearts", "Spades"] short_suit_names = ["C", "D", "H", "S"] rank_names = ["", "Ace", "2", "3", "4", "5", "6", "7", "8", "9", "10", "Jack", "Queen", "King", "Ace"] short_rank_names = ["", "A", "2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K", "A"] rank_range = range(2, 15) def __init__(self, rank, suit=None): # These are instance variables. Each instance has their own rank an suit if suit is None: # Assume rank is a card repr. Extract rank and suit suit = Card.suit_names[Card.short_suit_names.index(rank[-1])] rank = Card.short_rank_names[2:].index(rank[:-1])+2 self.rank = rank self.suit = suit def __lt__(self, other): """For sorting and comparing by rank""" return self.rank < other.rank # self.rank is my rank. other.rank is the rank of another card def __gt__(self, other): """For sorting and comparing by rank""" return self.rank > other.rank def __eq__(self, other): """For sorting and comparing by rank""" return self.rank == other.rank def name(self): """Get long name for card""" return f"{self.rank_names[self.rank]} {self.suit}" def __repr__(self): """Get short name for card""" return f"{self.short_rank_names[self.rank]}{self.suit[0]}" class Hand(): """A list of cards""" def __init__(self, cards=None): self.cards = [] if cards is None else cards def ranks(self): """Group cards into ranks. Sort ranks by number of cards in a rank""" def sort_key(item): """Sorting primarily on number of matching cards and secondarily on rank value""" return (len(item), item[0].rank) ranks = {} for card in self.cards: if card.rank in ranks: ranks[card.rank].append(card) else: ranks[card.rank] = [card] ranks = list(ranks.values()) ranks.sort(key=sort_key, reverse=True) return ranks def suits(self): """Group cards into suits. Sort suits by number of cards in a suit""" suits = {} for card in self.cards: if card.suit in suits: suits[card.suit].append(card) else: suits[card.suit] = [card] suits = list(suits.values()) for suit in suits: suit.sort(reverse=True) suits.sort(key=len, reverse=True) return suits def __add__(self, other): """Create a new hand by combining two existing hands""" return Hand(self.cards + other.cards) def __repr__(self): """Print cards in hand""" return ", ".join([str(card) for card in self.cards]) class Deck(): """Deck of cards""" def __init__(self, shuffle=False): self.cards = [Card(rank, suit) for rank in Card.rank_range for suit in Card.suit_names] if shuffle: random.shuffle(self.cards) def __len__(self): """Return number of cards in deck""" return len(self.cards) def deal(self, count): """Deal count cards from top of deck""" cards = self.cards[:count] self.cards = self.cards[count:] return cards class Rules(): ROYAL_FLUSH = 9 STRAIGHT_FLUSH = 8 FOUR_OF_A_KIND = 7 FULL_HOUSE = 6 FLUSH = 5 STRAIGHT = 4 THREE_OF_A_KIND = 3 TWO_PAIR = 2 ONE_PAIR = 1 HIGH_CARD = 0 HAND_NAMES = [ "High Card", "One Pair", "Two Pair", "Three of a Kind", "Straight", "Flush", "Full House", "Four of a Kind", "Straight Flush", "Royal Flush" ] @staticmethod def ofAKind(ranks, count): """Return cards if we have four card with the same rank""" for rank in ranks: if len(rank) == count: return rank return None @staticmethod def flush(suits): """Return cards if there are 5 of the same suit""" return suits[0] if len(suits[0]) > 4 else None @staticmethod def straight(ranks): """Return cards if there are 5 cards in a row""" def sort_key(item): """Sort ranks by rank value""" return item[0].rank straight = None # Sort the ranks by decreasing value ranks.sort(key=sort_key, reverse=True) if ranks[0][0].rank == 14: # If we have aces, treat them as both rank 14 and rank 1 ranks.append([Card(1, card.suit) for card in ranks[0]]) # look for 5 consecutive ranks for rank in ranks: if straight is None or straight[-1][0].rank - rank[0].rank > 1: straight = [rank] else: straight.append(rank) if len(straight) >= 5: return straight return None @staticmethod def straightFlush(suits): """Return cards if there are 5 cards in a row with the same rank""" if (cards := Rules.flush(suits)) is not None: return Rules.straight(Hand(cards).ranks()) return None @staticmethod def royalFlush(suits): """Return cards if there is an ace high straight flush""" if (cards := Rules.straightFlush(suits)) is not None and cards[0][0].rank == 14: return cards return None @staticmethod def fullHouse(ranks): """Return cards if there is a full house""" if len(ranks) > 1 and len(ranks[0]) >= 3 and len(ranks[1]) >= 2: return ranks[0] + ranks[1] return None @staticmethod def twoPair(ranks): """Return cards if there are two pairs""" if len(ranks) > 1 and len(ranks[0]) >= 2 and len(ranks[1]) >= 2: return ranks[0] + ranks[1] return None @staticmethod def highCard(ranks): """Return the high card""" def sort_key(item): """Sort ranks by rank value""" return item[0].rank ranks.sort(key=sort_key, reverse=True) return ranks[0][0].rank @classmethod def evaluate(cls, hand): ranks = hand.ranks() suits = hand.suits() high_card = cls.highCard(ranks) if (cards := cls.royalFlush(suits)): return cls.ROYAL_FLUSH, cards, high_card elif (cards := cls.straightFlush(suits)): return cls.STRAIGHT_FLUSH, cards, high_card elif (cards := cls.ofAKind(ranks, 4)): return cls.FOUR_OF_A_KIND, cards, high_card elif (cards := cls.fullHouse(ranks)): return cls.FULL_HOUSE, cards, high_card elif (cards := cls.flush(suits)): return cls.FLUSH, cards, high_card elif (cards := cls.straight(ranks)): return cls.STRAIGHT, cards, high_card elif (cards := cls.ofAKind(ranks, 3)): return cls.THREE_OF_A_KIND, cards, high_card elif (cards := cls.twoPair(ranks)): return cls.TWO_PAIR, cards, high_card elif (cards := cls.ofAKind(ranks, 2)): return cls.ONE_PAIR, cards, high_card else: return cls.HIGH_CARD, high_card, high_card # Test different hands flop = Hand([Card(card) for card in ["KS", "QS", "JS"]]) print("Royal Flush", Rules.evaluate(Hand([Card(card) for card in ["AC", "AD", "AH", "AS", "10S"]]) + flop)) print("Straight Flush", Rules.evaluate(Hand([Card(card) for card in ["KC", "KD", "JH", "10S", "9S"]]) + flop)) print("Four of a Kind", Rules.evaluate(Hand([Card(card) for card in ["AC", "AD", "AH", "AS", "10H"]]) + flop)) print("Full House", Rules.evaluate(Hand([Card(card) for card in ["KC", "KD", "QH", "5S", "4H"]]) + flop)) print("Flush", Rules.evaluate(Hand([Card(card) for card in ["2S", "4S", "2C", "4C", "5S"]]) + flop)) print("Straight", Rules.evaluate(Hand([Card(card) for card in ["AD", "2D", "3H", "4C", "5C"]]) + flop)) print("Three of a kind", Rules.evaluate(Hand([Card(card) for card in ["AC", "AD", "AH", "5H", "3D"]]) + flop)) print("Two Pair", Rules.evaluate(Hand([Card(card) for card in ["AC", "AD", "2S", "2D", "3D"]]) + flop)) print("One Pair", Rules.evaluate(Hand([Card(card) for card in ["AS", "AD", "3H", "4C", "5C"]]) + flop))
Is this the right thread?
I welcome all feedback.
The only dumb question, is one that doesn't get asked.
My Github
How to post code using bbtags
The only dumb question, is one that doesn't get asked.
My Github
How to post code using bbtags