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;