How can I compare the values of two playing cards when they have a value and a suit? Python3

后端 未结 4 493
傲寒
傲寒 2020-12-07 05:42

I am trying to make a text based object oriented card game. Two players draw a card each from a deck of cards, and the player with the strongest card wins. I have four class

4条回答
  •  感情败类
    2020-12-07 06:22

    Here is a sketch of an approach. You can easily combine this with your own approach, the biggest change being for the Card class. Here, I've used namedtuple to make a Card class, but your current class can simply wrap a tuple value:

    import enum
    from functools import total_ordering
    from collections import namedtuple
    
    @total_ordering
    class OrderedEnum(enum.Enum):
        def __lt__(self, other):
            if isinstance(other, type(self)):
                return self.value < other.value
            return NotImplemented
    
    Rank = OrderedEnum('Rank', ['one', 'two', 'three', 'four', 'five', 'six',
                        'seven', 'eight', 'nine', 'jack', 'queen','king', 'ace'])
    
    Suit = OrderedEnum('Suit', ['clubs', 'diamonds', 'hearts', 'spades'])
    
    Card = namedtuple('Card', ['rank', 'suit'])
    
    c1 = Card(Rank.four, Suit.clubs)
    c2 = Card(Rank.four, Suit.spades)
    c3 = Card(Rank.ace, Suit.diamonds)
    

    Now, in action:

    >>> c1
    Card(rank=, suit=)
    >>> c2
    Card(rank=, suit=)
    >>> c1 < c2
    True
    >>> c1 > c3
    False
    

    Tuple sorting is lexicographic! Nice!

    >>> hand = [c2, c1, c3]
    >>> hand
    [Card(rank=, suit=), Card(rank=, suit=), Card(rank=, suit=)]
    >>> sorted(hand)
    [Card(rank=, suit=), Card(rank=, suit=), Card(rank=, suit=)]
    >>>
    

    Note, I've used the total_ordering decorator, which is simply a shortcut, and indeed, I think it might be better to simply do the whole class by hand. Here's a recipe.

    EDIT So, to elaborate, here is how I would implement your Card and Deck classes. Notice how much more readable your code becomes when you use the enum and namedtuple.

    import enum
    from functools import total_ordering
    from collections import namedtuple
    from random import shuffle 
    
    @total_ordering
    class OrderedEnum(enum.Enum):
        def __lt__(self, other):
            if isinstance(other, type(self)):
                return self.value < other.value
            return NotImplemented
    
    Rank = OrderedEnum('Rank', ['one', 'two', 'three', 'four', 'five', 'six',
                        'seven', 'eight', 'nine', 'jack', 'queen','king', 'ace'])
    Suit = OrderedEnum('Suit', ['clubs', 'diamonds', 'hearts', 'spades'])
    CardValue = namedtuple('CardValue', ['rank', 'suit'])
    
    @total_ordering
    class Card(object):
        def __init__(self, rank, suit):
            self.value = CardValue(rank, suit)
        def __repr__(self):
            return "Card({:s}, {:s})".format(self.value.rank, self.value.suit)
        def __lt__(self, other):
            if isinstance(other, __class__):
                return self.value < other.value
            return NotImplemented
        def __eq__(self, other):
            if isinstance(other, __class__):
                return self.value == other.value
            return NotImplemented
    
    class Deck(object):
        def __init__(self):
            self.cards = []
            for rank in Rank:
                for suit in Suit:
                    self.cards.append(Card(rank, suit))
            shuffle(self.cards)
    

    Now, in action:

    >>> deck = Deck()
    >>> c1 = deck.cards.pop()
    >>> c2 = deck.cards.pop()
    >>> c1
    Card(Rank.queen, Suit.hearts)
    >>> c2
    Card(Rank.king, Suit.clubs)
    >>> c1 == c2
    False
    >>> c1 > c2
    False
    >>> c1 < c2
    True
    >>> c1.value
    CardValue(rank=, suit=)
    >>> c2.value
    CardValue(rank=, suit=)
    

    Also, notice that __repr__ should try to represent the object, if you want a pretty message, use __str__. See this question

提交回复
热议问题