Лучший способ представить "удвоенное" значение перечисления - PullRequest
1 голос
/ 21 марта 2020

Я в первую очередь разработчик C ++, но довольно часто я пишу Python скрипты. В настоящее время я пишу симулятор игры в кости для игры, и я не уверен, что лучше всего в Python решить мою проблему.

Есть три навыка игрока, и каждый игрок силен в один, средний в один и слабый в один. Я написал несколько классов, которые вычисляют лица d ie для каждого из навыков игрока.

Навыки живут в перечислении, а не пишут строки повсюду. Тем не менее, есть также шанс, что навык будет «удвоен» и станет сильнее.

Учитывая, что я возвращаю список элемента перечисления навыка, какой лучший способ указать, что навык имеет был удвоен?

Вещи, которые я рассмотрел до сих пор:

  • Расширение Enum Skill для включения удвоенных умений, но это усложняет сопоставление умений игрока с лицами
  • Создание Enum DoubleSkill, но затем любые изменения в Enum Skill необходимо будет реплицировать в DoubleSkill
  • Мой предпочтительный вариант - создание класса-оболочки DoubleSkill, который может быть создан из Skill. Однако, это не тип enum, что заставляет мои строго типизированные инстинкты C ++ нервничать
import random
from abc import ABC, abstractmethod
from enum import Enum
from collections import namedtuple

class Skill(Enum):
    Might = 1,
    Wisdom = 2,
    Cunning = 3

class Die(ABC):
    @abstractmethod
    def _faces(self):
        '''Returns the faces of this die'''
        pass

    def roll(self):
        '''Returns a random face'''
        return random.choice(self._faces())

PlayerSkills = namedtuple("PlayerSkills", ("strong", "medium", "weak"))

class PlayerDie(Die):
    @abstractmethod
    def _skills(self):
        '''Returns the characer's skills'''
        pass

    def _faces(self):
        '''Work out the faces of the die based off the skills'''
        skills = self._skills()

        #I want this to return a representation of the skill, not a string.
        #But then I'd be mixing Enums and not-Enums
        return [
            self._double(skills.strong),
            self._double(skills.medium),
            skills.strong.name,
            skills.strong.name,
            skills.medium.name,
            skills.weak.name
        ]

    def _double(self, skill):
        return f"Double {skill.name} (block)"

class CookDie(PlayerDie):
    def _skills(self):
        return PlayerSkills(Skill.Might, Skill.Cunning, Skill.Wisdom)

print(CookDie().roll())

1 Ответ

1 голос
/ 21 марта 2020

Один из возможных способов - сделать перечисление Flag вместо этого:

from enum import Flag, auto
class Skill(Flag):
    Might = auto()
    Wisdom = auto()
    Cunning = auto()
    Doubled = auto()

и использовать:

>>> for i in (1, 2, 4, 9, 10, 12):
...    i, Skill(i)

(1, <Skill.Might: 1>)
(2, <Skill.Wisdom: 2>)
(4, <Skill.Cunning: 4>)
(9, <Skill.Doubled|Might: 9>)
(10, <Skill.Doubled|Wisdom: 10>)
(12, <Skill.Doubled|Cunning: 12>)

Если вы хотите красивее str() (или один для объединенного члена), вы можете добавить свой собственный __str__:

class Skill(Flag):
    Might = auto()
    Wisdom = auto()
    Cunning = auto()
    Doubled = auto()
    #
    def __str__(self):
        cls = self.__class__
        cls_name = cls.__name__
        doubled = (self & cls.Doubled or "") and " x2"
        base = (self & ~cls.Doubled) or self
        name = base.name
        if name is None:
            name = '|'.join(s.name for s in Skill if s & base)
        return "%s.%s%s" % (cls_name, name, doubled)

и использовать:

for i in (1, 2, 4, 9, 10, 12):
    i, str(Skill(i))

(1, 'Skill.Might')
(2, 'Skill.Wisdom')
(4, 'Skill.Cunning')
(9, 'Skill.Might x2')
(10, 'Skill.Wisdom x2')
(12, 'Skill.Cunning x2')
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...