与标准卡组相比,为更复杂的扑克牌类型创建类的好方法吗?


9

我对面向对象的编程非常陌生,并且正尝试通过制作简单的纸牌游戏(似乎很传统!)来开始使用python学习。我已经完成了下面的示例,该示例运行良好,并且教会了我有关制作PlayingCard()该类的多个实例以创建该类的实例的信息Deck()

class PlayingCard(object):
    def __init__(self, suit, val):
        self.suit = suit
        self.value = val

    def print_card(self):
        print("{} of {}".format(self.value, self.suit))

class Deck(object):
    def __init__(self):
        self.playingcards = []
        self.build()

    def build(self):
        for s in ["Spades", "Clubs", "Diamonds", "Hearts"]:
            for v in range(1,14):
                self.playingcards.append(PlayingCard(s,v))

deck = Deck()



我现在想用更复杂的卡做一些事情,而不仅仅是一个标准的52副牌(具有很好的递增值)。我想到的套牌是“大富翁”纸牌游戏:

在此处输入图片说明

卡共有3种基本类型-ACTION卡,PROPERTY卡和MONEY卡。操作卡执行不同的操作,属性卡属于不同的颜色集,而货币卡可以具有不同的值。此外,属性卡可以是“通配符”,并且可以用作两个集合之一的一部分。最后,每张卡还具有同等的货币价值(在每张卡的左上角指示)。在租赁行动卡中,该卡只能应用于卡上指示的颜色属性。

我的问题只是一般如何处理这种情况,在基于类的python程序中包括这些不同的卡的最佳方法是什么?我应该保持我的单一PlayingCard()班级,并且只有很多输入,例如PlayingCard(type="PROPERTY", value="3M")。还是会更好地创建单独的类,如ActionPlayingCard()PropertyPlayingCard()等?或者,还有更好的方法?就像我说的那样,我正在这里开始学习,以及如何根据更高级别的设计来组织这类情况。

非常感谢。


如果发现不同类型的卡共享某些功能,则可以使用继承,甚至使用Abstract类。您可以阅读并使用“工厂模式”,以便通过卡的类型,然后使用适当的类
Tomerikoo

@Tomerikoo感谢您指出-我已经读了一些有关您提到的工厂模式的信息。据我了解,当您事先不知道需要创建哪些类的对象(也许仅在运行时知道)时,这将非常有用。但是,由于在这种情况下,我知道整个卡座应该是什么样子(每种类型的卡有多少张,它们各自做什么,等等),工厂模式在这里适用吗?
teeeeee

Answers:


3

当您使用OOP解决问题时,通常希望以可重用的方式对行为和属性进行建模,即,您应该考虑抽象并以此为基础组织类的层次结构。

我会写类似以下内容:

class Card:
    def __init__(self, money_value=0):
        self.money_value = money_value

class ActionCard(Card):
    def __init__(self, action, money_value=0):
        super().__init__(money_value=money_value)

        self.action = action

class RentActionCard(ActionCard):
    def __init__(self, action, color, money_value=0):
        super().__init__(action, money_value=money_value)

        self.color = color

    def apply(self, property_card):
        if property_card.color != self.color:
            # Don't apply
        # Apply

class PropertyCard(Card):
    def __init__(self, color, money_value=0):
        super().__init__(money_value=money_value)

        self.color = color

class WildcardPropertyCard(PropertyCard):
    def __init__(self, color, money_value=0):
        super().__init__(color, money_value=money_value)

class MoneyCard(Card):
    def __init__(self, money_value=0):
        super().__init__(money_value=money_value)

由于Python是一种动态类型的语言,在我看来,OOP很难证明其合理性,因为我们只能依靠鸭子类型动态绑定,因此组织层次结构的方式就不那么重要了。

例如,如果要在C#中对这个问题进行建模,则毫无疑问,我将使用上面显示的层次结构,因为我可以依靠多态来表示不同的类型,并根据要分析的卡类型来指导我的逻辑流程。

最后几点:

  1. Python具有非常强大的内置类型,但是大多数时候使用基于它们的新自定义类型可以使您的生活更轻松。
  2. 您不必继承,object因为默认情况下Python 3(到目前为止是唯一维护的一种)中的类型都继承自object

但是,归根结底,还没有一个完美的答案,最好的方法是尝试两种方法,看看自己更喜欢什么。


7

这些就是我们所谓的“设计决策”。通常,“正确”的方法只是一个见解。作为一个初学者,我认为尝试这两种实现以了解它们如何工作将是有益的。无论您选择哪一种,都将需要取舍。您必须决定哪些权衡最重要。随着您获得更多的经验,做出此类决定将是明智的。


是的,谢谢,我的做法与您所说的完全一样-只是寻求经验丰富的人的指导,这些人本能地知道一种好的方法,并希望理解为什么。
teeeeee

2

您可以使用继承。在这里,您可以创建一个主类,然后具有子类,这些子类仍包含来自父类的函数和值,但是对于该特定类也可以具有其他值和函数。

class Apple:
    def __init__(self, yearMade):
        pass

    def ring(self):
        print('ring ring')

class iPhone(Apple):
    def __init__(self, number)
        number = number

    def func():
        pass

现在,iPhone类具有与Apple类相同的功能,并且具有自己的功能。如果您想了解有关继承的更多信息,建议您做一些研究。


谢谢,我了解继承及其运作方式。鉴于“专卖”平台具有的特性,我对如何将其应用于我的特定情况更感兴趣。
teeeeee

@teeeeee由于每张卡都有其价值,因此您可以交易并可以使用它们,可以在类中创建函数/过程来处理这些事件,然后为子类中的某些卡具有额外的属性和功能。
MoriartyPy

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.