2010-04-15 6 views
6

Sto scrivendo un parser di dadi personalizzato (snicker se necessario) in python. Fondamentalmente, io voglio usare la valutazione matematica standard, ma aggiungere l'operatore 'd':Come valutare un'espressione matematica personalizzata in Python

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

modo che, ad esempio, 1d6 + 2d6 + 2d6-72 + 4d100 = (5) + (1 + 1) + (6 + 2) -72+ (5 + 39 + 38 + 59) = 84

Stavo usando regex per sostituire tutti i 'd' s con la somma e poi usare eval, ma il mio regex è andato in pezzi quando si trattava di parentesi su entrambi i lati. C'è un modo più veloce per fare questo che implementare la mia analisi ricorsiva? Forse aggiungendo un operatore per valutare?

Modifica: mi sembra di aver dato un cattivo esempio, come l'esempio precedente funziona con la mia versione corrente. Quello che sto cercando è un modo per valutare, diciamo, (5+ (6d6)) d (7-2 * (1d4)).
Con "caduto a pezzi", volevo solo dire che la mia espressione regex corrente non funzionava. Sono stato troppo vago per il mio fallimento, mi dispiace per la confusione. Ecco il mio codice corrente:

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

per questo, "1d6 + 4d100" funziona bene, ma "(1d6 + 4) d100" o anche "1d6 + 4d (100)" fallisce.

+0

Puoi mostrarci cosa hai provato e come è fallito? –

+0

Finito solo facendo una funzione di supporto ricorsivo. Grazie per tutto l'aiuto! – taynaron

risposta

5

Python non consente di scrivere nuovi operatori e non è possibile eseguire parentesi con una lingua normale. Dovrai scrivere un parser di discesa ricorsivo. Questo dovrebbe essere piuttosto semplice per il tuo linguaggio a dadi.

In alternativa, è possibile cooptare un operatore Python esistente e utilizzare gli strumenti di analisi Python per convertire il testo in un AST.

+0

Penso che i paren fossero solo un risultato intermedio dimostrativo, non facente parte della stessa DSL. Scrivere '1d6 + 2d6 + 2d6-72 + 4d100 = 84' non sarebbe stato del tutto esplicativo. +1 per il suggerimento di rec desc, però. –

+0

Allora sono confuso. Perché l'OP ha "regex [caduto] a parte quando ha a che fare con le parentesi"? –

+1

Ero piuttosto più vago di quanto pensassi, mi dispiace. L'esempio sopra funziona bene. Quello che intendevo è che se mettevi parentesi su entrambi i lati della d (come (4 + 2) d6) l'interprete non poteva gestire la valutazione di quello. – taynaron

6

È possibile utilizzare un callback function con re.sub. Quando si segue il link, la ricerca verso il paragrafo che inizia con "Se repl è una funzione ..."

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

Questo utilizza eval, che è abbastanza terribile davvero, ma qui si va

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

Alcune note rapide:

Questo sostituisce, per esempio, con 4d6sum((random.randint(1,x) for x in 4 * [6])).

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

((random.randint(1,x) for x in [6,6,6,6])) è l'equivalente generatore di una lista di comprensione; questo particolare restituirà quattro numeri casuali tra 1 e 6.

2

Dai un'occhiata alla libreria PyParsing. In particolare, la pagina ha un examplessample abbastanza vicino a quello che si vuole:

dice2.py

Un rotolo parser dadi e valutatore per valutare le stringhe quali "4d20 + 5.5 + 4d6.takeHighest (3)" .

0

Nel mio Supybot dice plugin ho analizzare l'espressione con

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

quindi ottenere numero totale di ogni dado e un modificatore totale, arrotolarle e ottenere risultato complessivo (Volevo mostrare numero totale di ogni dado) .

Problemi correlati