Un buon modo per fare lezioni per tipi di carte da gioco più complessi di quelli trovati in un mazzo standard?


9

Sono estremamente nuovo nella programmazione orientata agli oggetti e sto cercando di iniziare ad imparare in Python realizzando un semplice gioco di carte (come sembra essere tradizionale!). Ho fatto il seguente esempio che funziona bene e mi insegna a creare più istanze della PlayingCard()classe per creare un'istanza della 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()



Voglio fare qualcosa ora con carte più complesse, non solo un mazzo standard 52 (che ha valori gradevolmente incrementanti). Il mazzo che ho in mente è il gioco di carte Monopoli:

inserisci qui la descrizione dell'immagine

Esistono 3 tipi fondamentali di carte: carte AZIONE, CARTE DI PROPRIETÀ e carte SOLDI. Le carte azione eseguono azioni diverse, le carte proprietà appartengono a set di colori diversi e le carte denaro possono avere valori diversi. Inoltre, le carte proprietà possono essere "caratteri jolly" e possono essere utilizzate come parte di uno dei due set. Infine, ogni carta ha anche un valore monetario equivalente (indicato nell'angolo in alto di ogni carta). Nelle carte azione in affitto, la carta può essere applicata solo alla proprietà del colore indicata sulla carta.

La mia domanda è in genere come gestire una situazione come questa, e quale sarebbe un bel modo per includere queste diverse carte in un programma Python basato su classi? Dovrei mantenere la mia PlayingCard()classe singola e avere solo molti input, come PlayingCard(type="PROPERTY", value="3M"). O sarebbe meglio creare classi separate, come ActionPlayingCard(), PropertyPlayingCard(), ecc? O c'è un modo migliore? Come ho detto, sono all'inizio del mio apprendimento qui e su come organizzare questo tipo di situazioni in termini di progettazione di livello superiore.

Grazie molto.


Se scopri che i diversi tipi di carte condividono alcune caratteristiche, potresti usare l'ereditarietà o persino una classe astratta. Puoi leggere e utilizzare il modello di fabbrica in modo da poter passare il tipo di carta e verrà utilizzata la classe appropriata
Tomerikoo

@Tomerikoo Grazie per averlo sottolineato - ho letto un po 'del modello di fabbrica che hai citato. A quanto ho capito, questo è molto utile quando non sai in anticipo quali classi di oggetti dovrai creare (forse conoscendo solo in fase di esecuzione). Tuttavia, poiché in questo caso so come dovrebbe apparire l'intero mazzo (quanti di ogni tipo di carta, cosa fanno ciascuno, ecc.), Il modello di fabbrica è applicabile qui?
giovedì

Risposte:


3

Quando stai affrontando un problema con OOP , di solito vuoi modellare il comportamento e le proprietà in modo riutilizzabile, cioè, dovresti pensare alle astrazioni e organizzare la tua gerarchia di classi sulla base di ciò.

Vorrei scrivere qualcosa di simile al seguente:

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)

A causa del fatto che Python è un linguaggio tipizzato in modo dinamico, OOP è un po 'più difficile da giustificare secondo me, dal momento che possiamo semplicemente fare affidamento sulla tipizzazione delle anatre e sul legame dinamico , il modo in cui organizzi la tua gerarchia è meno importante.

Se per esempio modellassi questo problema in C # , utilizzerei senza dubbio la gerarchia mostrata sopra, perché potrei fare affidamento sul polimorfismo per rappresentare diversi tipi e guidare il flusso della mia logica in base al tipo di carta che viene analizzata.

Un paio di osservazioni finali:

  1. Python ha tipi incorporati molto potenti, ma la maggior parte delle volte l'utilizzo di nuovi tipi personalizzati basati su di essi ti semplifica la vita.
  2. Non è necessario ereditare da objectpoiché i tipi in Python 3 (che è l'unico mantenuto fino ad oggi) ereditano objectda default.

Ma alla fine della giornata non c'è una risposta perfetta, il modo migliore sarebbe provare entrambi gli approcci e vedere con cosa ti senti più a tuo agio.


7

Queste sono quelle che chiamiamo "decisioni di progettazione". Spesso il modo "corretto" è una questione di opinione. Come un principiante, penso che sarebbe istruttivo provare entrambe le implementazioni per vedere come funzionano. Ci saranno compromessi, indipendentemente da quale scegli. Devi decidere quale di questi compromessi è più importante. Prendere questo tipo di decisioni verrà informato man mano che acquisisci più esperienza.


Sì, grazie, sto facendo esattamente come dici tu - sto solo cercando la guida di persone che hanno abbastanza esperienza per conoscere istintivamente un buon approccio e speriamo di capire il perché.
teeeeee,

2

Potresti usare l'eredità. Qui è dove si crea una classe principale, quindi si hanno sottoclassi che contengono ancora funzioni e valori della classe madre, ma possono anche avere valori e funzioni extra per quella classe specifica.

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

Ora la classe iPhone ha le stesse funzioni della classe Apple e una sua funzione. Se desideri saperne di più sull'eredità, ti consiglio di fare qualche ricerca.


Grazie, capisco l'eredità e come funziona. Sono più interessato a come potrebbe essere applicato alla mia situazione specifica, date le proprietà che ha il mazzo Monopoli.
teeeeee,

@teeeeee Poiché ogni carta ha un valore, puoi scambiarle e giocarle, puoi creare funzioni / procedure in una classe per gestire questi eventi e quindi avere attributi e funzioni extra per certe carte in una sottoclasse.
MoriartyPy

0

Per monopolio, progetterei il punto di vista degli atterraggi di gioco. Non carte. Le carte rappresentano semplicemente gli atterraggi per il mondo reale.


Per favore, elabora.
martedì
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.