Remove diceply.py
This commit is contained in:
parent
4f56e40ca7
commit
c2280aaf1e
218
modules/Dice.py
218
modules/Dice.py
@ -22,20 +22,234 @@ from extlib import irclib
|
|||||||
|
|
||||||
from Module import Module
|
from Module import Module
|
||||||
|
|
||||||
import diceply
|
import ply.lex as lex
|
||||||
import ply.yacc as yacc
|
import ply.yacc as yacc
|
||||||
|
|
||||||
# Rolls dice, for RPGs mostly
|
# Rolls dice, for RPGs mostly
|
||||||
|
|
||||||
class Dice(Module):
|
class Dice(Module):
|
||||||
|
|
||||||
|
tokens = ['NUMBER', 'TEXT']
|
||||||
|
literals = ['#', '/', '+', '-', 'd', ';']
|
||||||
|
|
||||||
|
def build(self):
|
||||||
|
lex.lex(module=self)
|
||||||
|
yacc.yacc(module=self)
|
||||||
|
|
||||||
|
t_TEXT = r'\s+[^;]+'
|
||||||
|
|
||||||
|
def t_NUMBER(self, t):
|
||||||
|
r'\d+'
|
||||||
|
t.value = int(t.value)
|
||||||
|
return t
|
||||||
|
|
||||||
|
def t_error(self, t):
|
||||||
|
t.lexer.skip(1)
|
||||||
|
|
||||||
|
precedence = (
|
||||||
|
('left', ';'),
|
||||||
|
('left', '+', '-'),
|
||||||
|
('right', 'd'),
|
||||||
|
('left', '#'),
|
||||||
|
('left', '/')
|
||||||
|
)
|
||||||
|
|
||||||
|
output = ""
|
||||||
|
|
||||||
|
# Takes the parsed dice string for a single roll (eg 3/4d20) and performs
|
||||||
|
# the actual roll. Returns a string representing the result
|
||||||
|
def roll_dice(self, keep, dice, size):
|
||||||
|
a = range(dice)
|
||||||
|
for i in range(dice):
|
||||||
|
a[i] = random.randint(1, size)
|
||||||
|
if keep != dice:
|
||||||
|
b = sorted(a, reverse=True)
|
||||||
|
b = b[0:keep]
|
||||||
|
else:
|
||||||
|
b = a
|
||||||
|
total = sum(b)
|
||||||
|
outstr = "[";
|
||||||
|
if len(b) != len(a):
|
||||||
|
# Bold is \002
|
||||||
|
outstr += ",".join(str(i) for i in b) + ","
|
||||||
|
temp = sorted(a, reverse=True)
|
||||||
|
temp = temp[keep:]
|
||||||
|
bstr = ",".join(str(i) for i in temp)
|
||||||
|
outstr += bstr
|
||||||
|
else:
|
||||||
|
outstr += ",".join(str(i) for i in a)
|
||||||
|
outstr += "]"
|
||||||
|
|
||||||
|
return (total, outstr)
|
||||||
|
|
||||||
|
# Processes rolls coming from the parser. This generates the inputs
|
||||||
|
# for the roll_dice() command, and returns the full string representing
|
||||||
|
# the whole current dice string (the part up to a semicolon or end of line)
|
||||||
|
def process_roll(self, trials, mods, comment):
|
||||||
|
output = ""
|
||||||
|
mode = 1
|
||||||
|
repeat = 1
|
||||||
|
if trials != None:
|
||||||
|
repeat = trials
|
||||||
|
for i in range(repeat):
|
||||||
|
total = 0
|
||||||
|
curr_str = ""
|
||||||
|
if i > 0:
|
||||||
|
output += ", "
|
||||||
|
for m in mods:
|
||||||
|
keep = 0
|
||||||
|
dice = 1
|
||||||
|
res = 0
|
||||||
|
# if m is a tuple, then it is a die roll
|
||||||
|
# m[0] = (keep, num dice)
|
||||||
|
# m[1] = num faces on the die
|
||||||
|
if type(m) == tuple:
|
||||||
|
if m[0] != None:
|
||||||
|
if m[0][0] != None:
|
||||||
|
keep = m[0][0]
|
||||||
|
dice = m[0][1]
|
||||||
|
size = m[1]
|
||||||
|
if keep > dice or keep == 0:
|
||||||
|
keep = dice
|
||||||
|
res = self.roll_dice(keep, dice, size)
|
||||||
|
curr_str += "%d%s" % (res[0], res[1])
|
||||||
|
res = res[0]
|
||||||
|
elif m == "+":
|
||||||
|
mode = 1
|
||||||
|
curr_str += "+"
|
||||||
|
elif m == "-":
|
||||||
|
mode = -1
|
||||||
|
curr_str += "-"
|
||||||
|
else:
|
||||||
|
res = m
|
||||||
|
curr_str += str(m)
|
||||||
|
total += mode * res
|
||||||
|
output += "%d (%s)" % (total, curr_str)
|
||||||
|
if comment != None:
|
||||||
|
output = "%s: %s" % (comment.strip(), output)
|
||||||
|
return output
|
||||||
|
|
||||||
|
# General idea I had when creating this grammar: A roll string is a chain
|
||||||
|
# of modifiers, which may be repeated for a certain number of trials. It can
|
||||||
|
# have a comment that describes the roll
|
||||||
|
# Multiple roll strings can be chained with semicolon
|
||||||
|
def p_roll_r(self, p):
|
||||||
|
'roll : roll ";" roll'
|
||||||
|
global output
|
||||||
|
p[0] = p[1] + "; " + p[3]
|
||||||
|
output = p[0]
|
||||||
|
|
||||||
|
# The basic roll string
|
||||||
|
def p_roll(self, p):
|
||||||
|
'roll : trial modifier comment'
|
||||||
|
global output
|
||||||
|
mods = []
|
||||||
|
if type(p[2]) == list:
|
||||||
|
mods = p[2]
|
||||||
|
else:
|
||||||
|
mods = [p[2]]
|
||||||
|
p[0] = self.process_roll(p[1], mods, p[3])
|
||||||
|
output = p[0]
|
||||||
|
|
||||||
|
# Trial is optional so have a rule without it
|
||||||
|
def p_roll_no_trials(self, p):
|
||||||
|
'roll : modifier comment'
|
||||||
|
global output
|
||||||
|
mods = []
|
||||||
|
if type(p[1]) == list:
|
||||||
|
mods = p[1]
|
||||||
|
else:
|
||||||
|
mods = [p[1]]
|
||||||
|
p[0] = self.process_roll(None, mods, p[2])
|
||||||
|
output = p[0]
|
||||||
|
|
||||||
|
def p_comment(self, p):
|
||||||
|
'''comment : TEXT
|
||||||
|
|'''
|
||||||
|
if len(p) == 2:
|
||||||
|
p[0] = p[1]
|
||||||
|
else:
|
||||||
|
p[0] = None
|
||||||
|
|
||||||
|
def p_modifier(self, p):
|
||||||
|
'''modifier : modifier "+" modifier
|
||||||
|
| modifier "-" modifier'''
|
||||||
|
# Use append to prevent nested lists (makes dealing with this easier)
|
||||||
|
if type(p[1]) == list:
|
||||||
|
p[1].append(p[2])
|
||||||
|
p[1].append(p[3])
|
||||||
|
p[0] = p[1]
|
||||||
|
elif type(p[3]) == list:
|
||||||
|
p[3].insert(0, p[2])
|
||||||
|
p[3].insert(0, p[1])
|
||||||
|
p[0] = p[3]
|
||||||
|
else:
|
||||||
|
p[0] = [p[1], p[2], p[3]]
|
||||||
|
|
||||||
|
# Return the left side before the "d", and the number of faces
|
||||||
|
def p_die(self, p):
|
||||||
|
'modifier : left NUMBER'
|
||||||
|
p[0] = (p[1], p[2])
|
||||||
|
|
||||||
|
def p_die_num(self, p):
|
||||||
|
'modifier : NUMBER'
|
||||||
|
p[0] = p[1]
|
||||||
|
|
||||||
|
# left is the number of dice we are rolling, and how many we are keeping
|
||||||
|
def p_left(self, p):
|
||||||
|
'left : keep dice'
|
||||||
|
if p[1] == None:
|
||||||
|
p[0] = [None, p[2]]
|
||||||
|
else:
|
||||||
|
p[0] = [p[1], p[2]]
|
||||||
|
|
||||||
|
def p_left_all(self, p):
|
||||||
|
'left : dice'
|
||||||
|
p[0] = [None, p[1]]
|
||||||
|
|
||||||
|
def p_left_e(self, p):
|
||||||
|
'left :'
|
||||||
|
p[0] = None
|
||||||
|
|
||||||
|
def p_total(self, p):
|
||||||
|
'trial : NUMBER "#"'
|
||||||
|
if len(p) > 1:
|
||||||
|
p[0] = p[1]
|
||||||
|
else:
|
||||||
|
p[0] = None
|
||||||
|
|
||||||
|
def p_keep(self, p):
|
||||||
|
'keep : NUMBER "/"'
|
||||||
|
if p[1] != None:
|
||||||
|
p[0] = p[1]
|
||||||
|
else:
|
||||||
|
p[0] = None
|
||||||
|
|
||||||
|
def p_dice(self, p):
|
||||||
|
'dice : NUMBER "d"'
|
||||||
|
p[0] = p[1]
|
||||||
|
|
||||||
|
def p_dice_one(self, p):
|
||||||
|
'dice : "d"'
|
||||||
|
p[0] = 1
|
||||||
|
|
||||||
|
# Provide the user with something (albeit not much) when the roll can't be parsed
|
||||||
|
def p_error(self, p):
|
||||||
|
global output
|
||||||
|
output = "Unable to parse roll"
|
||||||
|
|
||||||
|
def get_result(self):
|
||||||
|
global output
|
||||||
|
return output
|
||||||
|
|
||||||
def do(self, connection, event, nick, userhost, replypath, what, admin_unlocked):
|
def do(self, connection, event, nick, userhost, replypath, what, admin_unlocked):
|
||||||
whats = what.split(' ')
|
whats = what.split(' ')
|
||||||
|
|
||||||
if whats[0] == 'roll':
|
if whats[0] == 'roll':
|
||||||
dicestr = ' '.join(whats[1:])
|
dicestr = ' '.join(whats[1:])
|
||||||
|
self.build()
|
||||||
yacc.parse(dicestr)
|
yacc.parse(dicestr)
|
||||||
reply = diceply.get_result()
|
reply = self.get_result()
|
||||||
if reply is not "":
|
if reply is not "":
|
||||||
return self.reply(connection, replypath, nick + ': ' + reply)
|
return self.reply(connection, replypath, nick + ': ' + reply)
|
||||||
if whats[0] == 'ctech':
|
if whats[0] == 'ctech':
|
||||||
|
@ -1,246 +0,0 @@
|
|||||||
# diceply.py
|
|
||||||
# Dice string grammar using PLY
|
|
||||||
# After initial run, parser.out should have the full grammar and the states
|
|
||||||
# and any shift/reduce or reduce/reduce conflicts.
|
|
||||||
#
|
|
||||||
# The current state of the grammar has some shift/reduce conflicts, because
|
|
||||||
# I don't know LR parsers well enough to prevent them. Also, currently spaces
|
|
||||||
# in the roll string aren't working if we want comments (for now)
|
|
||||||
#
|
|
||||||
# This script can be run standalone if you enable the tests at the bottom
|
|
||||||
|
|
||||||
import sys
|
|
||||||
import random
|
|
||||||
|
|
||||||
tokens = ['NUMBER', 'TEXT']
|
|
||||||
|
|
||||||
literals = ['#', '/', '+', '-', 'd', ';']
|
|
||||||
|
|
||||||
t_TEXT = r'\s+[^;]+'
|
|
||||||
|
|
||||||
def t_NUMBER(t):
|
|
||||||
r'\d+'
|
|
||||||
t.value = int(t.value)
|
|
||||||
return t
|
|
||||||
|
|
||||||
def t_error(t):
|
|
||||||
t.lexer.skip(1)
|
|
||||||
|
|
||||||
import ply.lex as lex
|
|
||||||
lex.lex()
|
|
||||||
|
|
||||||
precedence = (
|
|
||||||
('left', ';'),
|
|
||||||
('left', '+', '-'),
|
|
||||||
('right', 'd'),
|
|
||||||
('left', '#'),
|
|
||||||
('left', '/')
|
|
||||||
)
|
|
||||||
|
|
||||||
output = ""
|
|
||||||
|
|
||||||
# Takes the parsed dice string for a single roll (eg 3/4d20) and performs
|
|
||||||
# the actual roll. Returns a string representing the result
|
|
||||||
def roll_dice(keep, dice, size):
|
|
||||||
a = range(dice)
|
|
||||||
for i in range(dice):
|
|
||||||
a[i] = random.randint(1, size)
|
|
||||||
if keep != dice:
|
|
||||||
b = sorted(a, reverse=True)
|
|
||||||
b = b[0:keep]
|
|
||||||
else:
|
|
||||||
b = a
|
|
||||||
total = sum(b)
|
|
||||||
outstr = "[";
|
|
||||||
if len(b) != len(a):
|
|
||||||
# Bold is \002
|
|
||||||
outstr += ",".join(str(i) for i in b) + ","
|
|
||||||
temp = sorted(a, reverse=True)
|
|
||||||
temp = temp[keep:]
|
|
||||||
bstr = ",".join(str(i) for i in temp)
|
|
||||||
outstr += bstr
|
|
||||||
else:
|
|
||||||
outstr += ",".join(str(i) for i in a)
|
|
||||||
outstr += "]"
|
|
||||||
|
|
||||||
return (total, outstr)
|
|
||||||
|
|
||||||
# Processes rolls coming from the parser. This generates the inputs
|
|
||||||
# for the roll_dice() command, and returns the full string representing
|
|
||||||
# the whole current dice string (the part up to a semicolon or end of line)
|
|
||||||
def process_roll(trials, mods, comment):
|
|
||||||
output = ""
|
|
||||||
mode = 1
|
|
||||||
repeat = 1
|
|
||||||
if trials != None:
|
|
||||||
repeat = trials
|
|
||||||
for i in range(repeat):
|
|
||||||
total = 0
|
|
||||||
curr_str = ""
|
|
||||||
if i > 0:
|
|
||||||
output += ", "
|
|
||||||
for m in mods:
|
|
||||||
keep = 0
|
|
||||||
dice = 1
|
|
||||||
res = 0
|
|
||||||
# if m is a tuple, then it is a die roll
|
|
||||||
# m[0] = (keep, num dice)
|
|
||||||
# m[1] = num faces on the die
|
|
||||||
if type(m) == tuple:
|
|
||||||
if m[0] != None:
|
|
||||||
if m[0][0] != None:
|
|
||||||
keep = m[0][0]
|
|
||||||
dice = m[0][1]
|
|
||||||
size = m[1]
|
|
||||||
if keep > dice or keep == 0:
|
|
||||||
keep = dice
|
|
||||||
res = roll_dice(keep, dice, size)
|
|
||||||
curr_str += "%d%s" % (res[0], res[1])
|
|
||||||
res = res[0]
|
|
||||||
elif m == "+":
|
|
||||||
mode = 1
|
|
||||||
curr_str += "+"
|
|
||||||
elif m == "-":
|
|
||||||
mode = -1
|
|
||||||
curr_str += "-"
|
|
||||||
else:
|
|
||||||
res = m
|
|
||||||
curr_str += str(m)
|
|
||||||
total += mode * res
|
|
||||||
output += "%d (%s)" % (total, curr_str)
|
|
||||||
if comment != None:
|
|
||||||
output = "%s: %s" % (comment.strip(), output)
|
|
||||||
return output
|
|
||||||
|
|
||||||
# General idea I had when creating this grammar: A roll string is a chain
|
|
||||||
# of modifiers, which may be repeated for a certain number of trials. It can
|
|
||||||
# have a comment that describes the roll
|
|
||||||
# Multiple roll strings can be chained with semicolon
|
|
||||||
def p_roll_r(p):
|
|
||||||
'roll : roll ";" roll'
|
|
||||||
global output
|
|
||||||
p[0] = p[1] + "; " + p[3]
|
|
||||||
output = p[0]
|
|
||||||
|
|
||||||
# The basic roll string
|
|
||||||
def p_roll(p):
|
|
||||||
'roll : trial modifier comment'
|
|
||||||
global output
|
|
||||||
mods = []
|
|
||||||
if type(p[2]) == list:
|
|
||||||
mods = p[2]
|
|
||||||
else:
|
|
||||||
mods = [p[2]]
|
|
||||||
p[0] = process_roll(p[1], mods, p[3])
|
|
||||||
output = p[0]
|
|
||||||
|
|
||||||
# Trial is optional so have a rule without it
|
|
||||||
def p_roll_no_trials(p):
|
|
||||||
'roll : modifier comment'
|
|
||||||
global output
|
|
||||||
mods = []
|
|
||||||
if type(p[1]) == list:
|
|
||||||
mods = p[1]
|
|
||||||
else:
|
|
||||||
mods = [p[1]]
|
|
||||||
p[0] = process_roll(None, mods, p[2])
|
|
||||||
output = p[0]
|
|
||||||
|
|
||||||
def p_comment(p):
|
|
||||||
'''comment : TEXT
|
|
||||||
|'''
|
|
||||||
if len(p) == 2:
|
|
||||||
p[0] = p[1]
|
|
||||||
else:
|
|
||||||
p[0] = None
|
|
||||||
|
|
||||||
def p_modifier(p):
|
|
||||||
'''modifier : modifier "+" modifier
|
|
||||||
| modifier "-" modifier'''
|
|
||||||
# Use append to prevent nested lists (makes dealing with this easier)
|
|
||||||
if type(p[1]) == list:
|
|
||||||
p[1].append(p[2])
|
|
||||||
p[1].append(p[3])
|
|
||||||
p[0] = p[1]
|
|
||||||
elif type(p[3]) == list:
|
|
||||||
p[3].insert(0, p[2])
|
|
||||||
p[3].insert(0, p[1])
|
|
||||||
p[0] = p[3]
|
|
||||||
else:
|
|
||||||
p[0] = [p[1], p[2], p[3]]
|
|
||||||
|
|
||||||
# Return the left side before the "d", and the number of faces
|
|
||||||
def p_die(p):
|
|
||||||
'modifier : left NUMBER'
|
|
||||||
p[0] = (p[1], p[2])
|
|
||||||
|
|
||||||
def p_die_num(p):
|
|
||||||
'modifier : NUMBER'
|
|
||||||
p[0] = p[1]
|
|
||||||
|
|
||||||
# left is the number of dice we are rolling, and how many we are keeping
|
|
||||||
def p_left(p):
|
|
||||||
'left : keep dice'
|
|
||||||
if p[1] == None:
|
|
||||||
p[0] = [None, p[2]]
|
|
||||||
else:
|
|
||||||
p[0] = [p[1], p[2]]
|
|
||||||
|
|
||||||
def p_left1(p):
|
|
||||||
'left : dice'
|
|
||||||
p[0] = [None, p[1]]
|
|
||||||
|
|
||||||
def p_left_e(p):
|
|
||||||
'left :'
|
|
||||||
p[0] = None
|
|
||||||
|
|
||||||
def p_total(p):
|
|
||||||
'trial : NUMBER "#"'
|
|
||||||
if len(p) > 1:
|
|
||||||
p[0] = p[1]
|
|
||||||
else:
|
|
||||||
p[0] = None
|
|
||||||
|
|
||||||
def p_keep(p):
|
|
||||||
'keep : NUMBER "/"'
|
|
||||||
if p[1] != None:
|
|
||||||
p[0] = p[1]
|
|
||||||
else:
|
|
||||||
p[0] = None
|
|
||||||
|
|
||||||
def p_dice(p):
|
|
||||||
'dice : NUMBER "d"'
|
|
||||||
p[0] = p[1]
|
|
||||||
|
|
||||||
def p_dice2(p):
|
|
||||||
'dice : "d"'
|
|
||||||
p[0] = 1
|
|
||||||
|
|
||||||
# Provide the user with something (albeit not much) when the roll can't be parsed
|
|
||||||
def p_error(p):
|
|
||||||
print "Unable to parse roll"
|
|
||||||
print yacc.token()
|
|
||||||
global output
|
|
||||||
output = "Unable to parse roll"
|
|
||||||
|
|
||||||
def get_result():
|
|
||||||
global output
|
|
||||||
return output
|
|
||||||
|
|
||||||
import ply.yacc as yacc
|
|
||||||
yacc.yacc()
|
|
||||||
|
|
||||||
# Testing stuff:
|
|
||||||
|
|
||||||
# rolls = (
|
|
||||||
# "5#3/4d20+1+2+d20;3/4d20;4d20",
|
|
||||||
# "d20+10 attack;d8+6 damage",
|
|
||||||
# "2#d20+10 twin strike!111;d10+9 damage",
|
|
||||||
# "d20+d20;d20+d20;d20+d20+d20",
|
|
||||||
# "error"
|
|
||||||
# )
|
|
||||||
|
|
||||||
# for roll in rolls:
|
|
||||||
# print "***** trying roll " + roll
|
|
||||||
# yacc.parse(roll, debug=0)
|
|
||||||
# print output
|
|
Loading…
Reference in New Issue
Block a user