我一直在努力教自己如何使用面向对象的代码,我认为一种有趣的学习方法是编写一组行星,基于Mongoose的规则系统。
当一个行星物体被创建时,它会算法地生成一个行星。我定义了一个string方法和一个json方法来返回行星数据。函数two_dice()模拟两个骰子的和。
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)))这是我第一次尝试写一门课。虽然它目前是独立的,但我希望它能够适应一个更大的项目。有什么方法可以改进这一点,使它更好地遵循最佳实践,并删除重复的代码?
发布于 2018-01-29 09:41:00
culture作为关键字参数传递的方法。这看起来像是个疏忽。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'),并且更容易对照规则簿进行检查。self.temperature -= 1的最后一行吗?numMap将整数从0映射到15,映射为它们的十六进制等价物,并将连字符映射到它自己。如果不是因为连字符,您可以编写format(n, 'X')而不需要numMap。从numMap的使用来看,连字符的重点似乎是在__str__方法中实现一个特殊情况。但正如它在Python的禅宗中所说的那样,特例不足以打破规则。因此,我建议让__str__变得更复杂一些,以消除特例,这将允许您使用format(..., 'X'),而这又将允许您摆脱numMap。_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’)https://codereview.stackexchange.com/questions/186197
复制相似问题