diff --git a/diceroller.py b/diceroller.py new file mode 100755 index 0000000..adc3531 --- /dev/null +++ b/diceroller.py @@ -0,0 +1,78 @@ +#!/usr/bin/python +# +# Command-line dice roller + +import sys +sys.path.append('lib/') + +from dice import Dice +import random +import argparse + + +# This takes command-line input as dice description strings +# and builds a list of Dice objects +def parse_input(args): + dice_list = [] + for arg in args: + dice_list.append(Dice.from_str(arg)) + + return dice_list + + +def parse_args(): + parser = argparse.ArgumentParser(description='Roll dice based on descriptions passed in on the command line', formatter_class=argparse.RawTextHelpFormatter) + parser.add_argument('--repeat', '-r', metavar='N', type=int, default=1, help='repeat the given rolls N times') + parser.add_argument('--verbose', '-v', action='store_true', help='print detailed information about each roll') + parser.add_argument('dice', nargs=argparse.REMAINDER, help=""" +Dice are input in the following form: + +XdY[modifiers] + +This will roll X Y-sided dice and apply the specified modifiers. + +Modifiers can be any of the following (where N and M are integers): + +(+|-)N Add or subtract N from the total +lN Drop the lowest-rolling N dice from the total +hN Drop the highest-rolling N dice from the total +rN[xM] Any dice that roll <= N will be rerolled. + If the optional 'xM' option is specified, dice will be rerolled a maximum of M times. + Otherwise each die will be rerolled until the result is > N + +Examples: + +1d20+5 roll 1 twenty-sided die, and add 5 to the result +6d6l1h1 roll 6 six-sided dice, and drop both the highest and the lowest roll +4d6l1r2x1 roll 4 six-sided dice. Any dice rolling a 1 or 2 will be rerolled once. + If the result is still 1 or 2 it is kept. The lowest die is dropped from the result +""") + return parser.parse_args() + + + +def main(): + settings = parse_args() + dice_list = parse_input(settings.dice) + + for i in range(settings.repeat): + for dice in dice_list: + ret = dice.roll() + + if settings.verbose: + drop_info = '' + reroll_info = '' + + if ret['dropped']: + drop_info = ' [dropped {}]'.format(','.join(['{}'.format(x) for x in ret['dropped']])) + if ret['rerolled']: + reroll_info = ' [rerolled {}]'.format(','.join(['{}'.format(x) for x in ret['rerolled']])) + + print('{dice}: {rolls}{drop}{reroll} {total}'.format(dice=dice, rolls=ret['rolls'], total=ret['total'], drop=drop_info, reroll=reroll_info)) + + else: + print('{dice}: {total}'.format(dice=dice, total=ret['total'])) + + +if __name__ == '__main__': + main() diff --git a/dice.py b/lib/dice.py old mode 100755 new mode 100644 similarity index 57% rename from dice.py rename to lib/dice.py index f88cedc..1484f72 --- a/dice.py +++ b/lib/dice.py @@ -1,17 +1,14 @@ -#!/usr/bin/python +# dice.py # -# Command-line dice roller +# This module contains a class to represent various RPG-style dice expressions. +# These can then be rolled and the results, both total and individual rolls, returned. # -# It assumes that the Mersenne Twister is acceptable. -# Support for real entropy is an RFE +# This module assumes that the built-in python PRNG (Mersenne Twister) is acceptable. +# Support for real entropy is an RFE. import random -import sys import re -import argparse - -# Implements a "dice" - that is, a series of dice plus modifiers class Dice(): # This builds dice out of a simple input format # All of the dark regex magic is contained to this function, @@ -132,71 +129,3 @@ class Dice(): mod_info = '-{}'.format(self.mod) return "{num}d{sides}{mod}{drop}{reroll}".format(num=self.num, sides=self.sides, mod=mod_info, drop=drop_info, reroll=reroll_info) - - -# This takes command-line input as dice description strings -# and builds a list of Dice objects -def parse_input(args): - dice_list = [] - for arg in args: - dice_list.append(Dice.from_str(arg)) - - return dice_list - - -def parse_args(): - parser = argparse.ArgumentParser(description='Roll dice based on descriptions passed in on the command line', formatter_class=argparse.RawTextHelpFormatter) - parser.add_argument('--repeat', '-r', metavar='N', type=int, default=1, help='repeat the given rolls N times') - parser.add_argument('--verbose', '-v', action='store_true', help='print detailed information about each roll') - parser.add_argument('dice', nargs=argparse.REMAINDER, help=""" -Dice are input in the following form: - -XdY[modifiers] - -This will roll X Y-sided dice and apply the specified modifiers. - -Modifiers can be any of the following (where N and M are integers): - -(+|-)N Add or subtract N from the total -lN Drop the lowest-rolling N dice from the total -hN Drop the highest-rolling N dice from the total -rN[xM] Any dice that roll <= N will be rerolled. - If the optional 'xM' option is specified, dice will be rerolled a maximum of M times. - Otherwise each die will be rerolled until the result is > N - -Examples: - -1d20+5 roll 1 twenty-sided die, and add 5 to the result -6d6l1h1 roll 6 six-sided dice, and drop both the highest and the lowest roll -4d6l1r2x1 roll 4 six-sided dice. Any dice rolling a 1 or 2 will be rerolled once. - If the result is still 1 or 2 it is kept. The lowest die is dropped from the result -""") - return parser.parse_args() - - - -def main(): - settings = parse_args() - dice_list = parse_input(settings.dice) - - for i in range(settings.repeat): - for dice in dice_list: - ret = dice.roll() - - if settings.verbose: - drop_info = '' - reroll_info = '' - - if ret['dropped']: - drop_info = ' [dropped {}]'.format(','.join(['{}'.format(x) for x in ret['dropped']])) - if ret['rerolled']: - reroll_info = ' [rerolled {}]'.format(','.join(['{}'.format(x) for x in ret['rerolled']])) - - print('{dice}: {rolls}{drop}{reroll} {total}'.format(dice=dice, rolls=ret['rolls'], total=ret['total'], drop=drop_info, reroll=reroll_info)) - - else: - print('{dice}: {total}'.format(dice=dice, total=ret['total'])) - - -if __name__ == '__main__': - main() diff --git a/readme.markdown b/readme.markdown index d39a118..ee78912 100644 --- a/readme.markdown +++ b/readme.markdown @@ -12,14 +12,14 @@ A battle manager - keeps track of initiative order, hit points, and conditions f Battleman also aas a sense of whose turn it is, and prints a convenient message telling you who now has initiative when you enter the 'next' command. -### dice.py -A robust command-line dice-rolling utility. Many others exist, of course, but this one accepts all of its arguments as command-line parameters, making it a simple and intuitive interface. +### diceroller.py +A robust command-line dice-rolling utility. Many others exist, of course, but this one accepts all of its arguments as command-line parameters, making it a simple and intuitive interface for Linux types. ## For programmers -### dice.py -When treated as a library, provides a robust Dice class with a convenient from_str() classmethod. +### dice +A module that provides a robust Dice class with a convenient from_str() classmethod. ### battle