| Category: | Fun Stuff |
| Author/Contact Info | hakim@earthling.net |
| Description: | OK I discovered Dice::Dice and RPG::Dice here on Perlmonks but this wheel was such fun to reinvent... this code is more like RPG::Dice, but written in a different way, so I thought it might be worth posting. update: I quited liked the way I was handling tt clauses, but it was unnecessary. Combined parsing of template into one regex substitution and put the logic into the _roll sub. |
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 expressio
+n
my ($total, $template, @dice)=@roll;
=head1 DESCRIPTION
There are a number of Dice throwing modules (L<Dice::Dice>, L<RPG::Dic
+e>).
Dice::Dice has an OO interface and allows some interesting possibiliti
+es but
I didn't feel I needed its complexity. This module, Dice::Simple does
+n't
really do anything that RPG::Dice does apart from more flexible dice t
+emplates.
However, if you are going to use the function a lot C<roll> is a lot q
+uicker to
type than C<computeDice> ;->
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 i
+mported is
C<roll>. To do this insert C<use Dice::Simple qw(roll)> at the beginn
+ing of
your script.
If you don't want to import the function you can still call it using
C<Dice::Simple::roll()>.
=over 4
=item C<roll>
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 t
+imes
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<t
+t>
tt3 6d6 Roll 6 six-sided dice and keep the best 3
I<NB:> we are not bound by those troublesome laws of reality we can cr
+eate C<d5>, C<d7> etc.
If called in a scalar context, C<roll> returns the total of the expres
+sion requested.
my $total=roll '2d4+4';
If called in a list context, C<roll> returns
=over 4
=item 1
the sum
=item 2
the template (e.g. the first value passed to C<roll>)
=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<NB:> C<roll> may optionally be passed a list of dice rolls which wil
+l be used
B<in stead> of a randomly rolled integer. No error checking is curren
+tly
done to check that the value passed could have rolled by the dice spec
+ified.
This is not necessarily useful just yet..., however it means that the
+result of
a C<roll> call in list context can be passed back to C<roll> just by s
+hifting
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 tot
+al
}egx; # eg modifiers: apply this functi
+on to
# each occurrence of the #d# pa
+ttern
if ($dice=~/^[0-9+*()\/ -]*$/) { # eval should be safe because onl
+y
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;
|
|
|
|---|
| Replies are listed 'Best First'. | |
|---|---|
|
Dice::Simpler with Filter::Simple (Re: Reinventing Dice...)
by osfameron (Hermit) on Dec 08, 2001 at 23:58 UTC | |
by TheDamian (Vicar) on Dec 09, 2001 at 04:09 UTC | |
|
Submit to CPAN? Re: Reinventing Dice...
by osfameron (Hermit) on Dec 08, 2001 at 15:54 UTC | |
by Ovid (Cardinal) on Dec 09, 2001 at 02:19 UTC |