Хороший способ создавать классы для более сложных типов игральных карт, чем в стандартной колоде? - PullRequest
9 голосов
/ 19 февраля 2020

Я чрезвычайно новичок в объектно-ориентированном программировании и пытаюсь начать обучение в 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 (которая имеет приличные значения). Я имею в виду колоду карт монополии:

enter image description here

Существует 3 основных типа карт - карты ДЕЙСТВИЙ, КАРТОЧКИ СОБСТВЕННОСТИ и карты ДЕНЬГИ , Карты действий выполняют разные действия, карты свойств принадлежат разным наборам цветов, а карты денег могут иметь разные значения. Кроме того, карты свойств могут быть «подстановочными знаками» и могут использоваться как часть одного из двух наборов. Наконец, каждая карта также имеет эквивалентную денежную стоимость (указывается в верхнем углу каждой карты). В арендных картах действия карта может применяться только к свойству цвета, указанному на карте.

Мой вопрос, как правило, состоит в том, как справиться с подобной ситуацией, и как было бы неплохо включить эти разные карты в классной программе python? Должен ли я сохранить свой единственный PlayingCard() класс и просто иметь много входных данных, например PlayingCard(type="PROPERTY", value="3M"). Или было бы лучше создать отдельные классы, такие как ActionPlayingCard(), PropertyPlayingCard(), et c? Или есть лучший способ? Как я уже сказал, я нахожусь в начале своего обучения здесь, и как организовать эти типы ситуаций с точки зрения дизайна более высокого уровня.

Большое спасибо.

Ответы [ 4 ]

7 голосов
/ 19 февраля 2020

Это то, что мы называем «дизайнерские решения». Часто «правильный» путь - это вопрос мнения. Как новичок, я думаю, что было бы полезно попробовать обе реализации, чтобы увидеть, как они работают. Там будут компромиссы, независимо от того, какой вы выберете. Вы должны решить, какие из этих компромиссов являются наиболее важными. Принятие такого рода решений будет проинформировано, когда вы приобретете больше опыта.

3 голосов
/ 01 марта 2020

Когда вы подходите к проблеме с 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 является немного сложнее оправдать, на мой взгляд, поскольку мы можем просто положиться на утку, набрав и dynamici c привязку , способ организации вашей иерархии менее важен.

Если бы я смоделировал эту проблему, например, в C#, я без сомнения использовал бы иерархию, показанную выше, потому что я мог бы полагаться на полиморфизм для представления различных типов и руководства поток моих логи c в зависимости от типа анализируемой карты.

Пара заключительных замечаний:

  1. Python имеет очень мощные встроенные типы, но большую часть времени используют новые пользовательские типы, основанные на них, облегчают вашу жизнь.
  2. Вам не нужно наследовать от object, поскольку типы в Python 3 (который является единственным поддерживаемым с сегодня) наследуются от object по умолчанию.

Но, в конце концов, нет идеального ответа, лучший способ - попробовать оба подхода и посмотреть, что вам удобнее.

2 голосов
/ 26 февраля 2020

Вы можете использовать наследование. Здесь вы создаете главный класс, а затем имеете подклассы, которые все еще содержат функции и значения из родительского класса, но также могут иметь дополнительные значения и функции для этого указанного c класса.

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, и свою собственную функцию. Если вы хотите sh узнать больше о наследовании, я рекомендую провести небольшое исследование.

0 голосов
/ 28 февраля 2020

Для монополии я бы разработал точку зрения на игру. Не карты. Карты просто представляют приземления для реального мира.

...