首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >从python的rpg Traveller系统生成行星

从python的rpg Traveller系统生成行星
EN

Code Review用户
提问于 2018-01-28 14:39:12
回答 1查看 302关注 0票数 4

我一直在努力教自己如何使用面向对象的代码,我认为一种有趣的学习方法是编写一组行星,基于Mongoose的规则系统。

当一个行星物体被创建时,它会算法地生成一个行星。我定义了一个string方法和一个json方法来返回行星数据。函数two_dice()模拟两个骰子的和。

代码语言:javascript
复制
from models.common import two_dice
from random import randint

# Translate int values to string equivalent
numMap = {0: '0', 1: '1', 2: '2', 3: '3', 4: '4', 5: '5', 6: '6', 7: '7', 8: '8', 9: '9', 10: 'A', 11: 'B', 12: 'C',
          13: 'D', 14: 'E', 15: 'F', '-': '-'}


class Planet(object):
    def __init__(self, name, **kwargs):
        """
        creates a planet object with algorithmically defined attributes
        Attributes can be passed as keywords and creation process will account for them
        """
        self.name = name
        # Size is 2D - 2
        self.size = self._check_kwargs("size", 10, 0, kwargs)
        if self.size is None:
            self.size = two_dice()-2
        # Atmosphere is Size + 2D - 7. If size = 0, atmosphere = 0
        self.atmosphere = self._check_kwargs('atmosphere', 15, 0, kwargs)
        if self.atmosphere is None:
            self.atmosphere = self.size+two_dice()-7
            if self.size == 0:
                self.atmosphere = 0
            self.atmosphere = max(0, self.atmosphere)
        # Temperature is 2D. Affected by atmosphere type
        self.temperature = self._check_kwargs('temperature', 12, 0, kwargs)
        if self.temperature is None:
            self.temperature = two_dice()
            if self.atmosphere in [2, 3]:
                self.temperature -= 2
            elif self.atmosphere in [4, 5, 14]:
                self.temperature -= 2
            elif self.atmosphere in [8, 9]:
                self.temperature += 1
            elif self.atmosphere in [10, 13, 15]:
                self.temperature += 2
            elif self.atmosphere in [11, 12]:
                self.temperature += 6
            self.temperature = max(0, self.temperature)
            self.temperature = min(12, self.temperature)
        # Hydrographics is atmosphere + 2D - 7. Affected by size, temperature and atmosphere
        self.hydrographics = self._check_kwargs('hydrographics', 10, 0, kwargs)
        if self.hydrographics is None:
            if self.size <= 1:
                self.hydrographics = 0
            else:
                self.hydrographics = self.atmosphere + two_dice() - 7
                if self.atmosphere in [0, 1, 10, 11, 12]:
                    self.hydrographics -= 4
                if self.atmosphere != 13:
                    if self.temperature in [10, 11]:
                        self.hydrographics -= 2
                    elif self.temperature >= 12:
                        self.hydrographics -= 6
            self.hydrographics = max(0, self.hydrographics)
            self.hydrographics = min(10, self.hydrographics)
        # Population is 2D - 2.
        self.population = self._check_kwargs('population', 12, 0, kwargs)
        if self.population is None:
            self.population = two_dice() - 2
        # Government is population + 2D - 7.
        self.government = self._check_kwargs('government', 15, 0, kwargs)
        if self.government is None:
            self.government = self.population + two_dice() - 7
            if self.population == 0:
                self.government = 0
            self.government = max(0, self.government)
            self.government = min(15, self.government)
        # Culture is determined by rolling two dice, and concatenating the result.
        self.culture = randint(1, 6) + randint(1, 6) * 10
        if self.population == 0:
            self.culture = 0
        # Law level is government + 2D - 7
        self.law_level = self._check_kwargs('law_level', 9, 0, kwargs)
        if self.law_level is None:
            self.law_level = self.government + two_dice() - 7
            if self.population == 0:
                self.law_level = 0
            self.law_level = max(0, self.law_level)
            self.law_level = min(9, self.law_level)
        # Starport level is 2D, affected by population
        self.starport = self._check_kwargs('starport', 12, 0, kwargs)
        if self.starport is None:
            self.starport = two_dice()
            if self.population >= 10:
                self.starport += 2
            elif self.population >= 8:
                self.starport += 1
            elif self.population <= 2:
                self.starport -= 2
            elif self.population <= 4:
                self.starport -= 1
            self.starport = min(12, self.starport)
            self.starport = max(0, self.starport)
        # tech level is 1D, affected by lots of modifiers
        self.tech_level = self._check_kwargs('tech_level', 15, 0, kwargs)
        if self.tech_level is None:
            self.tech_level = randint(1, 6)
            if self.atmosphere <= 3 or self.atmosphere >= 10:
                self.tech_level += 1
            if self.size in [0, 1]:
                self.tech_level += 2
            elif self.size in [2, 3, 4]:
                self.tech_level += 1
            if self.hydrographics in [0, 9]:
                self.tech_level += 1
            elif self.hydrographics == 10:
                self.tech_level += 2
            if self.population in [1, 2, 3, 4, 5, 8]:
                self.tech_level += 1
            elif self.population == 9:
                self.tech_level += 2
            elif self.population == 10:
                self.tech_level += 4
            if self.government in [0, 5]:
                self.tech_level += 1
            elif self.government in [13, 14]:
                self.tech_level -= 2
            elif self.government == 7:
                self.tech_level += 2
            if self.starport >= 11:
                self.tech_level += 6
            elif self.starport >= 9:
                self.tech_level += 4
            elif self.starport >= 7:
                self.tech_level += 2
            elif self.starport <= 2:
                self.tech_level -= 4
            if self.population == 0:
                self.tech_level = 0
            self.tech_level = max(0, self.tech_level)
            self.tech_level = min(15, self.tech_level)

    @staticmethod
    def _check_kwargs(keyword, maxvalue, minvalue, kwargs):
        """
        Checks the given keyword exists, and is between given max & min values
        Returns keyword value if exists, otherwise None
        """
        if keyword in kwargs:
            if maxvalue >= kwargs[keyword] >= minvalue:
                return kwargs[keyword]
            else:
                raise ValueError("{} must be between {} and {}".format(keyword, maxvalue, minvalue))
        else:
            return None

    def json(self):
        return {'name': self.name,
                'size': self.size,
                'atmosphere': self.atmosphere,
                'temperature': self.temperature,
                'hydrographics': self.hydrographics,
                'population': self.population,
                'government': self.government,
                'culture': self.culture,
                'law_level': self.law_level,
                'starport': self.starport,
                'tech_level': self.tech_level}

    def __str__(self):
        attributes_list = [self.size, self.atmosphere, self.hydrographics, self.population, self.government,
                           self.law_level, '-', self.tech_level]
        if self.starport <= 2:
            starport = 'X'
        elif self.starport <= 4:
            starport = 'E'
        elif self.starport <= 6:
            starport = 'D'
        elif self.starport <= 8:
            starport = 'C'
        elif self.starport <= 10:
            starport = 'B'
        else:
            starport = 'A'
        return self.name + ' ' + starport + ''.join(list(map(lambda X: numMap[X],attributes_list)))

这是我第一次尝试写一门课。虽然它目前是独立的,但我希望它能够适应一个更大的项目。有什么方法可以改进这一点,使它更好地遵循最佳实践,并删除重复的代码?

EN

回答 1

Code Review用户

回答已采纳

发布于 2018-01-29 09:41:00

  1. 似乎没有将culture作为关键字参数传递的方法。这看起来像是个疏忽。
  2. 没有检查无效的关键字参数。这意味着,如果我们做了一个排版错误,我们不会发现它,但结果将是错误的:>>>行星=行星(‘Hrod’,atmopshere=10) >>> planet.atmosphere 7最好是这样的异常: TypeError:'atmopshere‘是这个函数的无效关键字参数。
  3. 函数two_dice似乎有些奇怪的具体。Traveller使用了很多2d6卷,但是在代码中我可以看到像randint(1, 6)two_dice() - 7这样的表达式。我认为这样的东西会有帮助:导入roll (骰子):“”滚骰子并返回它们的和。参数必须是一个描述滚动的字符串,例如'2d6+3‘来滚动两个6边的骰子并添加三个。“match = re.match(r'(\d*)d(\d*)(\d+)?$',如果不匹配的话):举起ValueError(f“预期的骰子,但得到{ dice !r}") n,边,红利= match.groups()边=int(边)返回和_ in范围(int(N))+int(红利或0),这样读者可能会更清楚地写出roll('1d6')roll('2d6-7'),并且更容易对照规则簿进行检查。
  4. 对于两组不同的大气值,温度由相同的值(−2)调节:如果self.atmosphere in : self.temperature -= 2 elif self.atmosphere in : self.temperature -= 2是self.temperature -= 1的最后一行吗?
  5. numMap将整数从0映射到15,映射为它们的十六进制等价物,并将连字符映射到它自己。如果不是因为连字符,您可以编写format(n, 'X')而不需要numMap。从numMap的使用来看,连字符的重点似乎是在__str__方法中实现一个特殊情况。但正如它在Python的禅宗中所说的那样,特例不足以打破规则。因此,我建议让__str__变得更复杂一些,以消除特例,这将允许您使用format(..., 'X'),而这又将允许您摆脱numMap
  6. 有很多重复。对于每个属性,我们都有一个名称,我们有一个最大值,我们可能需要在字符串代码中包含它的十六进制数字。我们可以将这些数据放入一个表中,比如:_ATTRIBUTES =,我们可以将生成每个属性的规则放入它们自己的方法中,类似于这样: def _size_default(self):回滚(‘2D6-2’) def _atmosphere_default(self):如果self.size == 0:返回0:返回self.size + roll('2d6-7') _TEMPERATURE_ADJUST = def _temperature_default(self):回滚(‘2D6’)+ self._TEMPERATURE_ADJUST def _hydrographics_default(self):如果self.size <= 1:返回0水文= self.atmosphere + roll('2d6-7'),如果self.atmosphere在(0,1,10,11,12):水文-= 4如果self.atmosphere != 13: if self.temperature in (10,( 11):水文学-= 2 elif self.temperature >= 12:水文资料-= 6返回水文资料(自):返回卷(‘2D6-2’) def _government_default(self):如果self.population == 0:返回0其他:返回self.population + roll('2d6-7') def _culture_default(自我):if self.population== 0:返回0 return :返回滚(‘1d6’)* 10 +滚(‘1d6’) def _law_level_default(self):如果self.population == 0:返回0:返回self.government + roll('2d6-7') _STARPORT_ADJUST = def _starport_default(self):回滚(‘2D6’)+ self._STARPORT_ADJUST _TECH_LEVEL__tech_level_default(self):如果self.population == 0:返回0 tech_level = roll('1d6')属性,Self._TECH_LEVEL_ADJUST中的调整: tech_level += adjustment.get(getattr(self,attribute),0)返回tech_level,现在我们可以系统地处理关键字参数,比如上面的不动点§1和§2,并且避免重复:对于属性,最大值,_ in self._ATTRIBUTES: if属性in kwargs: value =kwargs.pop(属性)如果不是(0 <=值<=最大值):引发ValueError(f"{ attribute !r}必须介于0和“{max}包含”)否则: value = getattr(self,'_‘+ attribute + '_default')()值= max(0,min(值),)如果kwargs: kwarg =next(TypeError(Kwargs))引发_check_kwargs (f“{kwarg!r}是”这个函数“的一个无效关键字参数),那么我们就不再需要D28了,json__str__方法变成: def json(self):D30= dict(name=self.name) for attribute,_,_ in self._ATTRIBUTES:_STARPORT_CODE = getattr(self,attribute )返回结果_STARPORT_CODE= 'XXXEEDDCCBBAAAAA‘def __str__(self):返回"{} -{}“.format( self.name,self._STARPORT_CODE,’.联接)(格式(getattr(self,attribute),'X')用于属性,_,self._ATTRIBUTES中的代码,如果是代码),格式(self.tech_level,‘X’)
票数 5
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/186197

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档