Я думаю, что ваш подход создает большую сложность: вы пытаетесь решить сложную задачу (анализ входных данных) в то же время, когда вы решаете менее сложную задачу (выполняете бросок кубиков). Проще разделить проблемы.
Класс для бросания кубиков относительно легко написать. Я делаю две вещи, которые вы не делаете: отображение знаков на операции (использование карты означает отсутствие необходимости писать логику, плюс возможность ее многократного использования) и возможность объединения Roller
объектов в простой связанный список, поэтому что вызов roll
в начале списка сворачивает их все и подводит итог.
import random
R = random.Random()
class Roller(object):
# map signs to operations
op = { "+" : lambda a,b: a+b,
"-" : lambda a,b: a-b,
"*" : lambda a,b: a*b,
"/" : lambda a,b: a/b }
def __init__(self, dice, sides, sign=None, modifier=0):
self.dice = dice
self.sides = sides
self.sign = sign
self.modifier = modifier
self.next_sign = None
self.next_roller = None
def roll(self):
self.dice_rolled = [R.randint(1, self.sides) for n in range(self.dice)]
result = sum(dice_rolled)
if self.sign:
result = self.op[self.sign](result, self.modifier)
if self.next_sign and self.next_roller:
result = self.op[self.next_sign](result, self.next_roller.roll())
return result
Это сравнительно легко проверить. Обратите внимание, что dice_rolled
сохраняется как атрибут, чтобы вам было легче писать модульные тесты.
Следующий шаг - выяснить, как анализировать входные данные. Такого рода работы:
>>> p = """
(?P<next_sign>[-+*/])?
(?P<dice>[\d]+)
[\s]*D[\s]*
(?P<sides>[\d]+)
# trailing sign and modifier are optional, but if one is present both must be
([\s]*(?P<sign>[-+/*])[\s]*(?P<modifier>[\d]+))?"""
>>> r = re.compile(p, re.VERBOSE+re.IGNORECASE)
>>> m=r.match('2 d 20 +1')
>>> m.group('dice'), m.group('sides'), m.group('sign'), m.group('modifier')
('2', '20', '+', '1')
>>> r.findall('3D6*2-1D4+1*2D6-1')
[('', '3', '6', '*2', '*', '2'), ('-', '1', '4', '+1', '+', '1'), ('*', '2', '6', '-1', '-', '1')]
Существует синтаксическая лексическая двусмысленность - 2D6+1D4
анализируется как 2D6+1
, за которым следует непревзойденный D4
, и мне не очевидно, как исправить это в регулярном выражении. Может быть, это можно исправить с помощью отрицательного прогнозирующего утверждения.
В любом случае, как только регулярное выражение будет исправлено, остается только обработать результаты r.findall
, чтобы создать цепочку из Roller
объектов. И сделайте это методом класса, если вы действительно копаете инкапсуляцию.