【问题标题】:How can I compare the values of two playing cards when they have a value and a suit? Python3当两张扑克牌有价值和花色时,我如何比较它们的价值? Python3
【发布时间】:2017-02-22 17:45:59
【问题描述】:

我正在尝试制作基于文本的面向对象的纸牌游戏。两名玩家从一副牌中各抽一张牌,拥有最强牌的玩家获胜。我为这个游戏设置了四个类:Card、Deck、Player、Game。我的问题是:我如何比较每个玩家的牌并确定最强的牌。欢迎有关代码的所有其他建议。最好的问候 HWG。

这是我的代码:

卡片

class Card():

    values = [None, None, 2, 3, 4, 5, 6, 7, 8, 9, 10, "Jack", "Queen", "King",
        "Ace"]
    suits = ["hearts", "spades", "diamond", "clubs"]

    def __init__(self, value, suit):
        self.value = value
        self.suit = suit

    def __repr__(self):
        return str(self.values[self.value]) + " of " + str(self.suits[self.suit])

甲板

from random import shuffle
from card import Card

class Deck():

    def __init__(self):
        self.cards = []
        for v in range(2, 15):
            for s in range(4):
                self.cards.append(Card(v, s))
        shuffle(self.cards)

播放器

from deck import Deck

class Player():

    def __init__(self, name):
        self.name = name
        self.card = None
        self.wins = 0

游戏

from player import Player
from deck import Deck
import getch

class Game():

    def __init__(self):
        player1_name = input("Player One Name: ")
        player2_name = input("Player Two Name: ")
        self.deck = Deck()
        self.player1 = Player(player1_name)
        self.player2 = Player(player2_name)
        self.cards = self.deck.cards

    def game_loop(self):
        while len(self.cards) >= 2:
            print("\nPress enter to draw")
            getch.getch()
            player1_card = self.cards.pop()
            player2_card = self.cards.pop()

【问题讨论】:

  • 我认为您应该仔细考虑您的表示形式 - 值是 intstr 的混合体,仅适用于 str... 实际上,实际实例本身具有以下属性ints 对应于 Card 类级变量中的索引。你看有什么问题吗?这是enum 的典型用例
  • 我能否以某种方式使用列表中的价值和花色索引(价值和花色)来比较两张牌?
  • 是的,当然。对我来说似乎很乱。我肯定会使用enums。您的代码将更具可读性、美观和整洁。但可以肯定的是,您可以使用索引。

标签: python python-3.x


【解决方案1】:

这是一种方法的草图。您可以轻松地将其与您自己的方法结合起来,最大的变化是 Card 类。在这里,我使用namedtuple 创建了一个Card 类,但是您当前的类可以简单地包装一个tuple 值:

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)

现在,行动起来:

>>> c1
Card(rank=<Rank.four: 4>, suit=<Suit.clubs: 1>)
>>> c2
Card(rank=<Rank.four: 4>, suit=<Suit.spades: 4>)
>>> c1 < c2
True
>>> c1 > c3
False

元组排序是字典顺序的!不错!

>>> hand = [c2, c1, c3]
>>> hand
[Card(rank=<Rank.four: 4>, suit=<Suit.spades: 4>), Card(rank=<Rank.four: 4>, suit=<Suit.clubs: 1>), Card(rank=<Rank.ace: 13>, suit=<Suit.diamonds: 2>)]
>>> sorted(hand)
[Card(rank=<Rank.four: 4>, suit=<Suit.clubs: 1>), Card(rank=<Rank.four: 4>, suit=<Suit.spades: 4>), Card(rank=<Rank.ace: 13>, suit=<Suit.diamonds: 2>)]
>>>

注意,我使用了total_ordering 装饰器,它只是一个快捷方式,而且确实,我认为手动完成整个课程可能会更好。 Here's 一个食谱。

编辑 所以,详细地说,这里是我将如何实现你的 CardDeck 类。请注意,当您使用 enumnamedtuple 时,您的代码的可读性会提高多少。

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)

现在,行动起来:

>>> 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=<Rank.queen: 11>, suit=<Suit.hearts: 3>)
>>> c2.value
CardValue(rank=<Rank.king: 12>, suit=<Suit.clubs: 1>)

另外,请注意__repr__ 应该尝试表示对象,如果您想要漂亮的消息,请使用__str__。见this question

【讨论】:

    【解决方案2】:

    您可以为您的 Card 类实现运算符 __gt__(), __lt__(), 等等...

    您可以使用一些标准库函数,例如 max() 来确定更高价值的卡片或牌组,甚至可以使用 sort() 来简单地对“手”进行排序,例如列表 [Card, Card, .. .].

    【讨论】:

      【解决方案3】:

      枚举 (https://docs.python.org/3.5/library/enum.html) 将是合适的。对于丰富的比较(和排序),您还应该考虑在 @ 上实现部分或全部 __eq____ne____lt____le____gt____ge__ 方法(来自 https://docs.python.org/3/reference/datamodel.html) 987654329@班级。

      【讨论】:

        【解决方案4】:

        我建议您将每张卡片的值存储为 int,以便您可以比较它们,并且不要使用诸如“King”或“Ace”之类的字符串。您可以这样做并更改 repr() 以使用这些字符串打印人类可读的版本。

        Card 类可能如下所示:

        class Card(object):
             suits = ["Clubs", "Diamonds", "Hearts", "Spades"] #list of suits
             values = [None, "Ace", "2", "3", "4", "5", "6", "7", "8", "9", "10", "Jack", "Queen", "King"] #list of card values
        
             def __init__(self, suit= 0, value= 2):
                 """
                 Initializes card
                 :param suit: Suit of card int value 0-3
                 :param value: Value of card int value 0-13
                 """
                 self.suit = suit
                 self.value = value
        
             def __str__(self):
                 """
                 Returns a readable format of the card
                 """
                 return "%s of %s" %(Card.values[self.value],
                                     Card.suits[self.suit])
        

        注意卡的值是如何一直存储为 int 的。

        在 Game 类中,你可以有一个比较两张牌的函数,我不确定你想怎么做,但它可能看起来像这样:

        def compare(card1, card2):
             """
             Compares the value of two cards and returns the greater of the two
             :param card1: A card object
             :param card2: A second card object
             :return: The higher value card, if tie returns 0
             """
             if card1.value > card2.value:
                 return card1
             elif card2.value == card1.value:
                 return 0
             else:
                 return card2
        

        【讨论】:

        • 是的,但现在 card1.value &gt; 48 将被实际评估。不好。这是enum 的典型案例。如果你已经有一个类,你的compare 函数是非常不应该做的,相反,你会实现丰富的比较运算符。
        猜你喜欢
        • 2014-04-09
        • 1970-01-01
        • 2017-08-27
        • 1970-01-01
        • 1970-01-01
        • 2021-12-06
        • 2013-09-18
        • 1970-01-01
        • 2017-07-11
        相关资源
        最近更新 更多