2

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:

  • Extending the Skill Enum to include doubled skills, but that makes the mapping of player skills to faces harder
  • Creating a DoubleSkill Enum, but then any changes to the Skill Enum would need to be replicated in DoubleSkill
  • My preferred option, which is creating a wrapper DoubleSkill class that can be constructed from a Skill. However, then it isn't of type enum, which makes my strongly-typed C++ instincts nervous
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
    You need to remove the comma after each line of the Enum definition (otherwise you get a value of (1, ), a tuple, and not the int 1). Commented Mar 21, 2020 at 15:54

1 Answer 1

2

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') 
Sign up to request clarification or add additional context in comments.

4 Comments

This sounds like it could be useful... It also opens the possibility of rolling combinations. So rather than rolling "Double Might" you could roll "Might + Cunning"
The main downside I'm seeing is that flags or'd together don't have a name property, which makes printing them slight less elegant
I haven't been able to find any information on printing them nicely, so I asked it as a new question
@Korosia: Updated my answer and included a bit to have a name for __str__.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.