Un bon moyen de créer des cours pour des types de cartes à jouer plus complexes que ceux que l'on trouve dans un jeu standard?

9

Je suis extrêmement nouveau dans la programmation orientée objet et j'essaie de commencer à apprendre en python en faisant un simple jeu de cartes (comme cela semble être traditionnel!). J'ai fait l'exemple suivant qui fonctionne bien et m'apprend à créer plusieurs instances de la PlayingCard()classe pour créer une instance de la Deck()classe:

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()



Je veux faire quelque chose maintenant avec des cartes plus complexes, pas seulement un jeu de 52 cartes standard (qui a des valeurs bien incrémentées). Le jeu auquel je pense est le jeu de cartes Monopoly:

entrez la description de l'image ici

Il existe 3 types fondamentaux de cartes: les cartes ACTION, les CARTES DE PROPRIÉTÉ et les cartes ARGENT. Les cartes d'action effectuent différentes actions, les cartes de propriété appartiennent à différents jeux de couleurs et les cartes d'argent peuvent avoir des valeurs différentes. De plus, les cartes de propriété peuvent être des "caractères génériques" et peuvent être utilisées dans le cadre de l'un des deux ensembles. Enfin, chaque carte a également une valeur monétaire équivalente (indiquée dans le coin supérieur de chaque carte). Dans les cartes d'action de location, la carte ne peut s'appliquer qu'à la propriété de couleur indiquée sur la carte.

Ma question est simplement de savoir comment gérer une situation comme celle-ci, et quelle serait une bonne façon d'inclure ces différentes cartes dans un programme python basé sur une classe? Dois-je garder ma PlayingCard()classe unique et avoir juste de nombreuses entrées, telles que PlayingCard(type="PROPERTY", value="3M"). Ou serait - il préférable de créer des classes séparées telles que ActionPlayingCard(), PropertyPlayingCard(), etc? Ou existe-t-il une meilleure façon? Comme je l'ai dit, je suis au début de mon apprentissage ici, et comment organiser ces types de situations en termes de conception de niveau supérieur.

Merci beaucoup.

teeeeee
la source
Si vous constatez que les différents types de cartes partagent certaines fonctionnalités, vous pouvez utiliser l'héritage, ou même une classe abstraite. Vous pouvez lire et utiliser le modèle d'usine afin de pouvoir passer le type de la carte et la classe appropriée sera utilisée
Tomerikoo
@Tomerikoo Merci d'avoir souligné cela - j'ai lu un peu sur le modèle d'usine que vous avez mentionné. Si je comprends bien, cela est très utile lorsque vous ne savez pas à l'avance quelles classes d'objets vous devrez créer (peut-être seulement au moment de l'exécution). Cependant, puisque dans ce cas, je sais à quoi devrait ressembler l'ensemble du jeu (combien de chaque type de carte, ce qu'ils font chacun, etc.), le modèle d'usine est-il applicable ici?
teeeeee

Réponses:

3

Lorsque vous vous approchez d'un problème avec la POO , vous voulez généralement modéliser le comportement et les propriétés de manière réutilisable, c'est-à-dire que vous devriez penser aux abstractions et organiser votre hiérarchie de classes en fonction de cela.

J'écrirais quelque chose comme ceci:

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)

En raison du fait que Python est un langage typé dynamiquement, la POO est un peu plus difficile à justifier à mon avis, car nous pouvons simplement nous appuyer sur la frappe de canard et la liaison dynamique , la façon dont vous organisez votre hiérarchie est moins importante.

Si je modélisais ce problème en C # par exemple, j'utiliserais sans aucun doute la hiérarchie montrée ci-dessus, car je pourrais compter sur le polymorphisme pour représenter différents types et guider le flux de ma logique en fonction du type de carte analysé.

Quelques remarques finales:

  1. Python a des types intégrés très puissants, mais la plupart du temps, l'utilisation de nouveaux types personnalisés qui s'appuient sur eux vous facilite la vie.
  2. Vous n'avez pas besoin d'hériter de objectpuisque les types en Python 3 (qui est le seul maintenu à ce jour) héritent de objectpar défaut.

Mais, à la fin de la journée, il n'y a pas de réponse parfaite, la meilleure façon serait d'essayer les deux approches et de voir avec quoi vous êtes plus à l'aise.

alex
la source
7

Ce sont ce que nous appelons des «décisions de conception». Souvent, la manière "correcte" est une question d'opinion. En tant que débutant, je pense qu'il serait instructif d'essayer les deux implémentations pour voir comment elles fonctionnent. Il y aura des compromis, peu importe celui que vous choisissez. Vous devez décider lesquels de ces compromis sont les plus importants. Prendre ce type de décisions sera informé à mesure que vous gagnerez en expérience.

Code-Apprenti
la source
Oui, merci, je fais exactement ce que vous dites - je cherche simplement des conseils de personnes suffisamment expérimentées pour connaître instinctivement une bonne approche et, espérons-le, comprendre pourquoi.
teeeeee
2

Vous pouvez utiliser l'héritage. C'est là que vous créez une classe principale puis que vous avez des sous-classes qui contiennent toujours des fonctions et des valeurs de la classe mère, mais peuvent également avoir des valeurs et des fonctions supplémentaires pour cette classe spécifique.

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

Maintenant, la classe iPhone a les mêmes fonctions que la classe Apple et sa propre fonction. Si vous souhaitez en savoir plus sur l'héritage, je vous recommande de faire quelques recherches.

MoriartyPy
la source
Merci, je comprends l'héritage et comment cela fonctionne. Je suis plus intéressé par la façon dont il pourrait être appliqué à ma situation spécifique, compte tenu des propriétés du pont Monopoly.
teeeeee
@teeeeee Comme chaque carte a une valeur, vous pouvez les échanger et les jouer, vous pouvez créer des fonctions / procédures dans une classe pour gérer ces événements, puis avoir des attributs et des fonctions supplémentaires pour certaines cartes d'une sous-classe.
MoriartyPy
0

Pour le monopole, je concevrais le point de vue des atterrissages de jeu. Pas des cartes. Les cartes représentent simplement les atterrissages pour le monde réel.

Ali Berat Çetin
la source
Veuillez développer.
teeeeee