package Dice::Simple; =head1 NAME Dice::Simple - a simple module to throw dice =head1 SYNOPSIS use Dice::Simple qw(roll); my $total=roll '3d6'; # simple die roll print "You threw $total\n"; my @roll=roll '(2d4+d6)/2+20'; # more complicated dice expression my ($total, $template, @dice)=@roll; =head1 DESCRIPTION There are a number of Dice throwing modules (L, L). Dice::Dice has an OO interface and allows some interesting possibilities but I didn't feel I needed its complexity. This module, Dice::Simple doesn't really do anything that RPG::Dice does apart from more flexible dice templates. However, if you are going to use the function a lot C is a lot quicker to type than C ;-> This was a surprisingly fun wheel to reinvent. =cut use strict; use warnings; BEGIN { use Exporter; our ($VERSION, @ISA, @EXPORT, @EXPORT_OK, %EXPORT_TAGS); $VERSION = 0.02; @ISA = qw(Exporter); @EXPORT = qw(); %EXPORT_TAGS = (); @EXPORT_OK = qw(roll); } =head1 FUNCTIONS No functions are exported by default. The only function that can be imported is C. To do this insert C at the beginning of your script. If you don't want to import the function you can still call it using C. =over 4 =item C Roll takes a dice template corresponding to the standard Role Playing Game dice conventions d4 4-sided dice d6 6-sided dice d100 100-sided dice Each dice may be optionally prefaced by a number indicating how many times to roll the dice. 3d6 Roll 3 six-sided dice, (total between 3 and 18) And may have a simple arithmetic modifier 2d4+2 Roll 2 four-sided dice, and add 2 to the total Other arithmetic can be performed using the symbols + - * / ( ) for example: (3d6+2d4)/2 And we can optionally choose only the best dice using the notation C tt3 6d6 Roll 6 six-sided dice and keep the best 3 I we are not bound by those troublesome laws of reality we can create C, C etc. If called in a scalar context, C returns the total of the expression requested. my $total=roll '2d4+4'; If called in a list context, C returns =over 4 =item 1 the sum =item 2 the template (e.g. the first value passed to C) =item 3 the results of each die, in order they were thrown (e.g. as specified by the template). =back For example, C<2d4 + d6 + 3> might return (13, "2d4 + d6 + 3", 3, 2, 5) Total: 13 Template: "2d4 + d6 + 3" Dice: 3, 2, 5 Note that the dice rolls do not retain any memory of which dice rolled them. =for undocumented I C may optionally be passed a list of dice rolls which will be used B of a randomly rolled integer. No error checking is currently done to check that the value passed could have rolled by the dice specified. This is not necessarily useful just yet..., however it means that the result of a C call in list context can be passed back to C just by shifting off the result. =back =cut use vars qw(@DICE); sub roll { my $template=shift || $_; @DICE=@_; my @scores; (my $dice=$template)=~ s{(?:tt(\d+)\s+)?(\d+)?d(\d+)} # e.g. tt{n}? d4, 3d6, 2d8 {my($tot,@sc) # get total & dice for that role =_roll($2||1,$3,$1); push@scores,@sc; # add to overall dice. $tot # replace #d# expression with total }egx; # eg modifiers: apply this function to # each occurrence of the #d# pattern if ($dice=~/^[0-9+*()\/ -]*$/) { # eval should be safe because only my $eval=eval($dice); # accept specified characters return wantarray ? ($eval, $template, @scores) : $eval } undef; # return undef on failure } sub _roll { my ($count, $die, $topn)=@_; my $total=0; my @scores=map {shift @DICE || int(rand $die)+1} 1..$count; if ($topn) { # restrict to best dice only @scores=(sort {$b<=>$a} @scores)[0..$topn-1] # In v0.01 I made sure that the dice were returned # in the order thrown. Don't think this is needed # so just returning sorted values. } $total+=$_ for @scores; return $total, @scores; } =head1 AUTHOR, BUGS, LICENSE Version: 0.02 7th Dec 2001 Untested. No warranty implied. May be distributed under the same terms as Perl itself. (c) hakim@earthling.net http://www.perlmonks.org /msg osfameron =cut int(rand 6)+1;