update dice parser

This commit is contained in:
Denis-Cosmin Nutiu 2024-01-21 22:25:23 +02:00
parent a9ea30dec9
commit 1285190ee7
5 changed files with 21 additions and 14 deletions

0
src/__init__.py Normal file
View file

View file

@ -5,18 +5,19 @@ from src.dice.parser import DieParser
class DiceRoller: class DiceRoller:
""" """
DiceRoller is a simple class that allows you to roll dices. DiceRoller is a simple class that allows you to roll dices.
A die can be rolled using the following expression: A die can be rolled using the following expression:
- 1d20 will roll a 20-faceted die and output the result a random number between 1 and 20. - 1d20 will roll a 20-faceted die and output the result a random number between 1 and 20.
- 1d100 will roll a 100 faceted die. - 1d100 will roll a 100 faceted die.
- 2d20 will roll a two d20 dies and multiply the result by two. - 2d20 will roll a two d20 dies and multiply the result by two.
- 2d20+5 will roll a two d20 dies and multiply the result by two and ads 5. - 2d20+5 will roll a two d20 dies and multiply the result by two and ads 5.
""" """
_parser = DieParser() _parser = DieParser()
@staticmethod @staticmethod
def roll(expression: str, advantage: typing.Optional[bool]) -> int: def roll(expression: str, advantage: typing.Optional[bool] = None) -> int:
""" """
Roll die and return the result. Roll die and return the result.
:param expression: The die expression. :param expression: The die expression.

View file

@ -8,9 +8,9 @@ DIE_GRAMMAR = """
@@grammar::Die @@grammar::Die
@@whitespace :: None @@whitespace :: None
start = die:die [modifier:die_modifier] $; start = die:die $;
die = [number_of_dies:number] die_type:die_type die_number:number; die = [number_of_dies:number] die_type:die_type die_number:number [modifier:die_modifier];
die_modifier = op:operator modifier:number; die_modifier = op:operator modifier:number;
operator = '+' | '-'; operator = '+' | '-';

View file

@ -8,9 +8,7 @@ class DieSemantics:
return int(ast) return int(ast)
def start(self, ast): def start(self, ast):
modifier = ast.get("modifier") or 0 return ast.get("die")
die = ast.get("die")
return die + modifier
def die(self, ast): def die(self, ast):
if not isinstance(ast, AST): if not isinstance(ast, AST):
@ -18,14 +16,22 @@ class DieSemantics:
number_of_dies = ast.get("number_of_dies") or 1 number_of_dies = ast.get("number_of_dies") or 1
die_type = ast.get("die_type") die_type = ast.get("die_type")
die_number = ast.get("die_number") or 1 die_number = ast.get("die_number") or 1
die_modifier = ast.get("modifier") or 0
if die_number <= 0: if die_number <= 0:
return 0 return 0
# normal die # normal die
if die_type == "d": if die_type == "d":
return sum([random.randint(1, die_number) for _ in range(number_of_dies)]) die_sum = sum(
[random.randint(1, die_number) for _ in range(number_of_dies)]
)
# do not let die to underflow
return max(die_sum + die_modifier, 1)
# zero-based die can output 0. # zero-based die can output 0.
if die_type == "zd": if die_type == "zd":
return sum([random.randint(0, die_number) for _ in range(number_of_dies)]) die_sum = sum(
[random.randint(0, die_number) for _ in range(number_of_dies)]
)
return max(die_sum + die_modifier, 0)
raise ValueError(f"Invalid die type: {die_type}") raise ValueError(f"Invalid die type: {die_type}")
def die_modifier(self, ast): def die_modifier(self, ast):

0
tests/__init__.py Normal file
View file