2012-04-02 09:17:55 -07:00
# Written by Scaevolus, updated by Lukeroge
2011-11-20 22:23:31 +13:00
import re
import random
from util import hook
whitespace_re = re . compile ( r ' \ s+ ' )
2012-03-19 23:31:54 +13:00
valid_diceroll = r ' ^([+-]?(?: \ d+| \ d*d(?: \ d+|F))(?:[+-](?: \ d+| \ d*d(?: \ d+| ' \
2012-03-13 00:40:37 +13:00
' F)))*)( .+)?$ '
2011-11-20 22:23:31 +13:00
valid_diceroll_re = re . compile ( valid_diceroll , re . I )
sign_re = re . compile ( r ' [+-]?(?: \ d*d)?(?: \ d+|F) ' , re . I )
split_re = re . compile ( r ' ([ \ d+-]*)d?(F| \ d*) ' , re . I )
2014-02-13 20:51:11 +13:00
def n_rolls ( count , n ) :
2013-09-04 18:30:04 +08:00
""" roll an n-sided die count times """
2011-11-20 22:23:31 +13:00
if n == " F " :
return [ random . randint ( - 1 , 1 ) for x in xrange ( min ( count , 100 ) ) ]
if n < 2 : # it's a coin
if count < 100 :
return [ random . randint ( 0 , 1 ) for x in xrange ( count ) ]
else : # fake it
2012-03-13 00:40:37 +13:00
return [ int ( random . normalvariate ( .5 * count , ( .75 * count ) * * .5 ) ) ]
2011-11-20 22:23:31 +13:00
else :
if count < 100 :
return [ random . randint ( 1 , n ) for x in xrange ( count ) ]
else : # fake it
2012-03-13 00:40:37 +13:00
return [ int ( random . normalvariate ( .5 * ( 1 + n ) * count ,
2013-09-04 18:30:04 +08:00
( ( ( n + 1 ) * ( 2 * n + 1 ) / 6. -
( .5 * ( 1 + n ) ) * * 2 ) * count ) * * .5 ) ) ]
2011-11-20 22:23:31 +13:00
@hook.command ( ' roll ' )
#@hook.regex(valid_diceroll, re.I)
@hook.command
def dice ( inp ) :
2014-02-13 20:51:11 +13:00
""" dice <dice roll> -- Simulates dice rolls. Example of <dice roll>:
2013-09-04 18:30:04 +08:00
' dice 2d20-d5+4 roll 2 ' . D20s , subtract 1 D5 , add 4 """
2011-11-20 22:23:31 +13:00
try : # if inp is a re.match object...
( inp , desc ) = inp . groups ( )
except AttributeError :
( inp , desc ) = valid_diceroll_re . match ( inp ) . groups ( )
if " d " not in inp :
return
spec = whitespace_re . sub ( ' ' , inp )
if not valid_diceroll_re . match ( spec ) :
2014-02-13 14:34:50 +13:00
return " Invalid dice roll "
2011-11-20 22:23:31 +13:00
groups = sign_re . findall ( spec )
total = 0
rolls = [ ]
for roll in groups :
count , side = split_re . match ( roll ) . groups ( )
count = int ( count ) if count not in " +- " else 1
if side . upper ( ) == " F " : # fudge dice are basically 1d3-2
2014-02-13 20:51:11 +13:00
for fudge in n_rolls ( count , " F " ) :
2011-11-20 22:23:31 +13:00
if fudge == 1 :
rolls . append ( " \x03 3+ \x0F " )
elif fudge == - 1 :
rolls . append ( " \x03 4- \x0F " )
else :
rolls . append ( " 0 " )
total + = fudge
elif side == " " :
total + = count
else :
side = int ( side )
try :
if count > 0 :
2014-02-13 20:51:11 +13:00
d = n_rolls ( count , side )
2014-02-13 14:34:50 +13:00
rolls + = map ( str , d )
total + = sum ( d )
2011-11-20 22:23:31 +13:00
else :
2014-02-13 20:51:11 +13:00
d = n_rolls ( - count , side )
2014-02-13 14:34:50 +13:00
rolls + = [ str ( - x ) for x in d ]
total - = sum ( d )
2011-11-20 22:23:31 +13:00
except OverflowError :
2014-02-13 20:51:11 +13:00
# I have never seen this happen. If you make this happen, you win a cookie
2011-11-20 22:23:31 +13:00
return " Thanks for overflowing a float, jerk >:[ "
if desc :
2013-09-05 09:46:49 +08:00
return " {} : {} ( {} ) " . format ( desc . strip ( ) , total , " , " . join ( rolls ) )
2011-11-20 22:23:31 +13:00
else :
2013-09-05 09:46:49 +08:00
return " {} ( {} ) " . format ( total , " , " . join ( rolls ) )