2010-04-15 9 views
6

Ich schreibe einen benutzerdefinierten Würfel Rollen Parser (sicker, wenn Sie müssen) in Python. Grundsätzlich mag ich Standard-Mathematik-Auswertung verwenden, aber den 'd' Operator hinzufügen:Wie evaluiere ich einen benutzerdefinierten mathematischen Ausdruck in Python

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

Damit zum Beispiel 1W6 + 2W6 + 2d6-72 + 4d100 = (5) + (1 + 1) + (6 + 2) -72+ (5 + 39 + 38 + 59) = 84

Ich benutzte Regex, um alle 'd's durch die Summe zu ersetzen und dann eval zu verwenden, aber meine Regex fiel auseinander, wenn es um Klammern ging jeder Seite. Gibt es einen schnelleren Weg, als das eigene rekursive Parsing zu implementieren? Vielleicht einen Operator zu Eval hinzufügen?

Edit: Ich habe ein schlechtes Beispiel angegeben, wie das obige Beispiel mit meiner aktuellen Version funktioniert. Nach was ich suche, ist eine Weise, zum Beispiel auszuwerten, (5+ (6d6)) d (7-2 * (1d4)).
Mit "auseinanderfallen" meinte ich nur, dass mein aktueller Regex-Ausdruck fehlschlug. Ich war zu vage über mein Versagen, Entschuldigung für die Verwirrung. Hier ist mein aktueller Code:

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()) 

für diesen "1W6 + 4d100" funktioniert gut, aber "(1W6 + 4) d100" oder sogar "1W6 + 4d (100)" schlägt fehl.

+0

Können Sie uns zeigen, was Sie versucht haben und wie es versagt hat? –

+0

Am Ende nur eine rekursive Hilfsfunktion. Danke für die Hilfe! – taynaron

Antwort

5

In Python können Sie keine neuen Operatoren schreiben, und Sie können keine Klammern mit einer normalen Sprache verwenden. Sie müssen einen rekursiven Descent-Parser schreiben. Dies sollte jedoch ziemlich einfach für Ihre Würfel-Roll-Sprache sein.

Alternativ können Sie einen vorhandenen Python-Operator übernehmen und Pythons-Parsingtools verwenden, um den Text in einen AST zu konvertieren.

+0

Ich denke, die Parens waren nur als demonstratives Zwischenergebnis, nicht Teil des DSL selbst. Das Schreiben von '1d6 + 2d6 + 2d6-72 + 4d100 = 84' wäre nicht so erklärend gewesen. +1 für den rec-Abstieg-Vorschlag, obwohl. –

+0

Dann bin ich verwirrt. Warum ist die "Regex" des OP bei den Klammern auseinander gefallen? –

+1

Ich war etwas vager als ich dachte, sorry. Das obige Beispiel funktioniert gut. Was ich meinte ist, dass der Interpreter, wenn man Klammern auf beide Seiten des d setzt (wie (4 + 2) d6), nicht damit fertig wird, das auszuwerten. – taynaron

6

Sie könnten eine callback function mit re.sub verwenden. Wenn Sie dem Link folgen, Suche nach dem Absatz nach unten beginnend mit „Wenn ers eine Funktion ist ...“

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

Dies verwendet eval, die wirklich ziemlich schrecklich ist, aber hier gehen Sie

>>> 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)) 

Einige schnelle Anmerkungen:

Dies ersetzt, sagen wir, 4d6 mit sum((random.randint(1,x) for x in 4 * [6])).

4 * [6] ergibt die Liste [6,6,6,6].

((random.randint(1,x) for x in [6,6,6,6])) ist das Generatoräquivalent eines Listenverständnisses; dieser bestimmte wird vier Zufallszahlen zwischen 1 und 6 zurückgeben.

2

Werfen Sie einen Blick auf die Bibliothek PyParsing. Insbesondere hat die examples Seite eine sample ziemlich nah an, was Sie wollen:

dice2.py

Ein Würfelwurf-Parser und Evaluator für Strings wie "4D20 + 5,5 + 4d6.takeHighest (3)" Auswertung .

0

In meinem Supybot dice plugin ich den Ausdruck mit

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

analysieren dann Gesamtzahlen der einzelnen Würfel und insgesamt Modifikator erhalten, rollen sie und erhalten Gesamtergebnis (wollte ich Gesamtzahlen der einzelnen Würfel zeigen) .

Verwandte Themen