When you don’t have a set of dice lying around, or when 20d6+2d4 just takes too long to add up:
#!/usr/bin/env python
import logging
import random
import re
import sys
ROLL = re.compile(r'(\d*)d(\d+)')
def roll(dice):
"""Randomly generate the result of a dice roll.
>>> 1 <= roll('d6') <= 6
True
>>> 4 <= roll('4d6') <= 24
True
>>> 2 <= roll('1d10+1d4') <= 14
True
>>> 2+1-1 <= roll('2d8+1d6-1') <= 16+6-1
True
"""
logging.debug("roll(%r)", dice)
def _roll(m):
x = m.group(1) and int(m.group(1)) or 1
y = int(m.group(2))
return '%d' % (x * random.randint(1, y))
postroll = ROLL.sub(_roll, dice)
logging.debug("roll(%r) -> %r", dice, postroll)
value = eval(postroll, {}, {})
logging.debug("eval(%r) -> %r", postroll, value)
return value
def argz():
"""Define the arguments to this script."""
from optparse import OptionParser
parser = OptionParser()
parser.set_defaults(log_level=logging.WARNING)
parser.add_option('-d', '--debug',
action='store_const', const=logging.DEBUG, dest='log_level')
parser.add_option('-v', '--verbose',
action='store_const', const=logging.INFO, dest='log_level')
parser.add_option('-q', '--quiet',
action='store_const', const=logging.ERROR, dest='log_level')
parser.add_option('--test',
action='store_true', dest='test', default=False,
help="Run the unit tests.")
parser.add_option('--stat',
action='store_true', dest='stat', default=False,
help="Roll 4d6, drop the lowest (for ability scores).")
(options, args) = parser.parse_args()
logging.basicConfig(level=options.log_level)
if options.stat:
dice = [roll('d6') for x in xrange(4)]
logging.info("rolled %r for ability", dice)
dice = sorted(dice)[1:]
logging.debug("kept %r", dice)
stat = sum(dice)
print "%d (%+01d)" % (stat, (stat - 10) / 2)
sys.exit(0)
if options.test or len(args) == 0:
import doctest
doctest.testmod()
sys.exit(0)
return (options, args)
if __name__ == '__main__':
(options, args) = argz()
for dice in args:
print roll(dice)
You can even roll stats!
$ for stat in STR DEX CON WIS INT CHA EXT
> do ./roll.py --stat
> done | sort -n | tail -n6
13 (+1)
14 (+2)
15 (+2)
16 (+3)
17 (+3)
17 (+3)