Reputation: 639
I'm primarily a C++ developer, but I fairly frequently end up writing Python scripts. I'm currently writing a dice simulator for a game, and I'm not certain of the best way, in Python, the solve my problem.
There are three player skills, and each player is strong at one, medium at one, and weak at one. I've written some classes that calculate the faces of the die from each of the player skils.
The skills live in an enum, rather than writing strings all over the place. However, there's also a chance that the skill will be "doubled", and become stronger.
Given that I am returning a list of Skill enum element, what is the best way to indicate a skill has been doubled?
Things I've considered so far:
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())
Upvotes: 2
Views: 215
Reputation: 69220
One possible way is to make your enumration a Flag
instead:
from enum import Flag, auto
class Skill(Flag):
Might = auto()
Wisdom = auto()
Cunning = auto()
Doubled = auto()
and in use:
>>> 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>)
If you would like a prettier str()
(or one at all for a combined member), you can add your own __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)
and in use:
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')
Upvotes: 2