improve die parser
This commit is contained in:
parent
700007893e
commit
a59a4c203f
3 changed files with 27 additions and 16 deletions
|
@ -1,36 +1,41 @@
|
||||||
|
import logging
|
||||||
|
|
||||||
import tatsu
|
import tatsu
|
||||||
|
|
||||||
from src.dice.semantics import DieSemantics
|
from src.dice.semantics import DieSemantics
|
||||||
|
|
||||||
DIE_GRAMMAR = '''
|
DIE_GRAMMAR = """
|
||||||
@@grammar::Die
|
@@grammar::Die
|
||||||
@@whitespace :: None
|
@@whitespace :: None
|
||||||
|
|
||||||
start = [number_of_dies:number] die:die [modifier:die_modifier] $;
|
start = die:die [modifier:die_modifier] $;
|
||||||
die = die_type:die_type die_number:number;
|
|
||||||
die_modifier = op:die_modifier_op modifier:number;
|
die = [number_of_dies:number] die_type:die_type die_number:number;
|
||||||
die_modifier_op = '+' | '-';
|
die_modifier = op:operator modifier:number;
|
||||||
|
|
||||||
|
operator = '+' | '-';
|
||||||
|
|
||||||
die_type = 'd' | 'zd';
|
die_type = 'd' | 'zd';
|
||||||
|
|
||||||
number = /[0-9]+/ ;
|
number = /[0-9]+/ ;
|
||||||
'''
|
"""
|
||||||
|
|
||||||
|
|
||||||
class DieParser:
|
class DieParser:
|
||||||
"""
|
"""
|
||||||
Parser for the die grammar defined above.
|
Parser for the die grammar defined above.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self._parser = tatsu.compile(DIE_GRAMMAR)
|
self._parser = tatsu.compile(DIE_GRAMMAR)
|
||||||
self._semantics = DieSemantics()
|
self._semantics = DieSemantics()
|
||||||
|
self._logger = logging.getLogger("DieParser")
|
||||||
|
|
||||||
def parse(self, expression: str) -> int:
|
def parse(self, expression: str) -> int:
|
||||||
"""
|
"""
|
||||||
Parses the die expression and returns the result.
|
Parses the die expression and returns the result.
|
||||||
"""
|
"""
|
||||||
clean_expression = "".join(expression.split())
|
clean_expression = "".join(expression.split())
|
||||||
result = self._parser.parse(clean_expression, semantics=self._semantics)
|
result = self._parser.parse(clean_expression, semantics=self._semantics)
|
||||||
number_of_dies = result.get("number_of_dies") or 1
|
logging.debug(f"rolling die for {expression} -> result={result}")
|
||||||
modifier = result.get("modifier") or 0
|
return result
|
||||||
die = result.get("die")
|
|
||||||
return number_of_dies * die + modifier
|
|
||||||
|
|
|
@ -7,19 +7,25 @@ class DieSemantics:
|
||||||
def number(self, ast):
|
def number(self, ast):
|
||||||
return int(ast)
|
return int(ast)
|
||||||
|
|
||||||
|
def start(self, ast):
|
||||||
|
modifier = ast.get("modifier") or 0
|
||||||
|
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):
|
||||||
return ast
|
return ast
|
||||||
|
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", 1)
|
die_number = ast.get("die_number") or 1
|
||||||
if die_number <= 0:
|
if die_number <= 0:
|
||||||
raise ValueError(f"Invalid die number: {die_number}")
|
return 0
|
||||||
# normal die
|
# normal die
|
||||||
if die_type == "d":
|
if die_type == "d":
|
||||||
return random.randint(1, die_number)
|
return sum([random.randint(1, die_number) for _ in range(number_of_dies)])
|
||||||
# zero-based die can output 0.
|
# zero-based die can output 0.
|
||||||
if die_type == "zd":
|
if die_type == "zd":
|
||||||
return random.randint(0, die_number)
|
return sum([random.randint(0, die_number) for _ in range(number_of_dies)])
|
||||||
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/dice/__init__.py
Normal file
0
tests/dice/__init__.py
Normal file
Loading…
Reference in a new issue