2010-04-15 35 views
6

Escribo un analizador rodante de dados personalizado (snicker si es necesario) en python. Básicamente, quiero utilizar la evaluación estándar de matemáticas además de añadir la 'd' del operador:Cómo evaluar una expresión matemática personalizada en Python

#xdy 
sum = 0 
for each in range(x): 
    sum += randInt(1, y) 
return sum 

Así que, por ejemplo, 1d6 + 2d6 + 2d6-72 + 4d100 = (5) + (1 + 1) + (6 + 2) -72+ (5 + 39 + 38 + 59) = 84

Estaba usando regex para reemplazar todos los 's con la suma y luego usar eval, pero mi expresión regular se vino abajo cuando se trata de paréntesis en cualquier lado. ¿Hay una forma más rápida de hacer esto que implementar mi propio análisis recursivo? Tal vez agregar un operador a eval?

Editar: Parece que he dado un mal ejemplo, ya que el ejemplo anterior funciona con mi versión actual. Lo que estoy buscando es una forma de evaluar, por ejemplo, (5+ (6d6)) d (7-2 * (1d4)).
Por "se vino abajo", solo quería decir que mi expresión actual de expresiones regulares falló. He sido demasiado vago sobre mi fracaso, lo siento por la confusión. Aquí está mi código actual:

def evalDice(roll_matchgroup): 
    roll_split = roll_matchgroup.group('roll').split('d') 
    print roll_split 
    roll_list = [] 

    for die in range(int(roll_split[0])): 
     roll = random.randint(1,int(roll_split[1])) 
     roll_list.append(roll) 

def EvalRoll(roll): 
    if not roll: return 0 
    rollPattern = re.compile('(?P<roll>\d*d\d+)') 
    roll_string = rollPattern.sub(evalDice, roll.lower()) 

para esto, "1d6 + 4d100" funciona muy bien, pero "(1d6 + 4) d100" o incluso "1d6 + 4d (100)" falla.

+0

¿Puede mostrarnos qué ha intentado y cómo ha fallado? –

+0

Terminó haciendo una función auxiliar recursiva. ¡Gracias por toda la ayuda! – taynaron

Respuesta

5

Python no le permite escribir nuevos operadores, y no puede hacer paréntesis con un lenguaje común. Tendrás que escribir un analizador de descenso recursivo. Sin embargo, esto debería ser bastante simple para su lenguaje de lanzamiento de dados.

Como alternativa, podría cooperar con un operador de Python existente y utilizar las herramientas de análisis Pythons para convertir el texto en AST.

+0

Creo que los parens fueron solo un resultado intermedio demostrativo, no parte de la propia DSL. Escribir '1d6 + 2d6 + 2d6-72 + 4d100 = 84' no hubiera sido tan explicativo. +1 para la sugerencia de descenso de rec, sin embargo. –

+0

Entonces estoy confundido. ¿Por qué los OP "regex [se separan] cuando se trata de los paréntesis"? –

+1

Fui bastante más vago de lo que pensaba, lo siento. El ejemplo de arriba funciona bien. Lo que quiero decir es que si pones paréntesis a cada lado de la d (como (4 + 2) d6) el intérprete no podría manejar la evaluación de eso. – taynaron

6

Puede usar callback function con re.sub. Cuando sigue el enlace, buscar hasta el párrafo que comienza con "Si repl es una función ..."

import re 
import random 

def xdy(matchobj): 
    x,y=map(int,matchobj.groups()) 
    s = 0 
    for each in range(x): 
     s += random.randint(1, y) 
    return str(s) 
s='1d6+2d6+2d6-72+4d100' 
t=re.sub('(\d+)d(\d+)',xdy,s) 
print(t) 
# 5+10+8-72+197 
print(eval(t)) 
# 148 
0

Este utiliza eval, que es realmente bastante horrible, pero aquí vas

>>> x = '1d6+2d6+2d6-72+4d100' 
>>> eval(re.sub(r'(\d+)d(\d+)',r'sum((random.randint(1,x) for x in \1 * [\2]))', x)) 

Algunas notas rápidas:

Esto reemplaza, por ejemplo, con 4d6sum((random.randint(1,x) for x in 4 * [6])).

4 * [6] produce la lista [6,6,6,6].

((random.randint(1,x) for x in [6,6,6,6])) es el generador equivalente de una lista de comprensión; este en particular devolverá cuatro números aleatorios entre 1 y 6.

2

Eche un vistazo a la biblioteca PyParsing. En particular, la página examples tiene una sample bastante cerca de lo que quiere:

dice2.py

Un analizador tirada de dados y evaluador para evaluar cadenas como "4d20 + 5,5 + 4d6.takeHighest (3)" .

0

En mi Supybot dice plugin que analizar la expresión con

r'(?P<sign>[+-])((?P<dice>\d*)d(?P<sides>\d+)|(?P<mod>\d+))' 

a continuación, obtener los números totales de cada dado y un modificador total, el rollo de ellos y obtener un resultado total de (quería mostrar los números totales de cada dado) .

Cuestiones relacionadas