File Coverage

blib/lib/Games/Dice.pm
Criterion Covered Total %
statement 9 51 17.6
branch 0 28 0.0
condition 0 9 0.0
subroutine 3 7 42.8
pod 0 2 0.0
total 12 97 12.3


line stmt bran cond sub pod time code
1 1     1   465 use strict;
  1         1  
  1         30  
2 1     1   4 use warnings;
  1         1  
  1         68  
3             package Games::Dice;
4             # ABSTRACT: Perl module to simulate die rolls
5             $Games::Dice::VERSION = '0.045';
6             require Exporter;
7              
8             our @ISA = qw(Exporter);
9             our @EXPORT_OK = qw( roll roll_array);
10              
11             # Preloaded methods go here.
12              
13             # Win32 has crummy built in rand() support
14             # So let's use something that's decent and pure perl
15 1     1   464 use if $^O eq "MSWin32", 'Math::Random::MT::Perl' => qw(rand);
  1         6  
  1         5  
16              
17             sub roll ($) {
18 0     0 0   my($line, $dice_string, $sign, $offset, $sum, @throws, @result);
19              
20 0           $line = shift;
21              
22 0 0         return $line if $line =~ /\A[0-9]+\z/;
23              
24 0 0         return undef unless $line =~ m{
25             ^ # beginning of line
26             ( # dice string in $1
27             (?:\d+)? # optional count
28             [dD] # 'd' for dice
29             (?: # type of dice:
30             \d+ # either one or more digits
31             | # or
32             % # a percent sign for d% = d100
33             | # pr
34             F # a F for a fudge dice
35             )
36             )
37             (?: # grouping-only parens
38             ([-+xX*/bB]) # a + - * / b(est) in $2
39             (\d+) # an offset in $3
40             )? # both of those last are optional
41             \s* # possibly some trailing space (like \n)
42             $
43             }x; # whitespace allowed
44              
45 0           $dice_string = $1;
46 0   0       $sign = $2 || '';
47 0   0       $offset = $3 || 0;
48              
49 0           $sign = lc $sign;
50              
51 0           @throws = roll_array( $dice_string );
52 0 0         return undef unless @throws;
53              
54 0 0         if( $sign eq 'b' ) {
55 0 0         $offset = 0 if $offset < 0;
56 0 0         $offset = @throws if $offset > @throws;
57              
58 0           @throws = sort { $b <=> $a } @throws; # sort numerically, descending
  0            
59 0           @result = @throws[ 0 .. $offset-1 ]; # pick off the $offset first ones
60             } else {
61 0           @result = @throws;
62             }
63              
64 0           $sum = 0;
65 0           $sum += $_ foreach @result;
66 0 0         $sum += $offset if $sign eq '+';
67 0 0         $sum -= $offset if $sign eq '-';
68 0 0 0       $sum *= $offset if ($sign eq '*' || $sign eq 'x');
69 0 0         do { $sum /= $offset; $sum = int $sum; } if $sign eq '/';
  0            
  0            
70              
71 0           return $sum;
72             }
73              
74             sub roll_array ($) {
75 0     0 0   my($line, $num, $type, @throws);
76              
77 0           $line = shift;
78              
79 0 0         return $line if $line =~ /\A[0-9]+\z/;
80              
81 0 0         return undef unless $line =~ m{
82             ^ # beginning of line
83             (\d+)? # optional count in $1
84             [dD] # 'd' for dice
85             ( # type of dice in $2:
86             \d+ # either one or more digits
87             | # or
88             % # a percent sign for d% = d100
89             | # pr
90             F # a F for a fudge dice
91             )
92             }x; # whitespace allowed
93              
94 0   0       $num = $1 || 1;
95 0           $type = $2;
96              
97 0     0     my $throw = sub { int (rand $_[0]) + 1 };
  0            
98              
99 0 0         if ( $type eq '%' ) {
    0          
100 0           $type = 100;
101             } elsif ( $type eq 'F' ) {
102 0     0     $throw = sub { int( rand 3 ) - 1 };
  0            
103             }
104              
105 0           @throws = ();
106 0           for( 1 .. $num ) {
107 0           push @throws, $throw->($type);
108             }
109              
110 0           return @throws;
111             }
112              
113             1;
114              
115             =pod
116              
117             =encoding UTF-8
118              
119             =head1 NAME
120              
121             Games::Dice - Perl module to simulate die rolls
122              
123             =head1 VERSION
124              
125             version 0.045
126              
127             =head1 SYNOPSIS
128              
129             use Games::Dice 'roll';
130             $strength = roll '3d6+1';
131              
132             use Games::Dice 'roll_array';
133             @rolls = roll_array '4d8';
134              
135             =head1 DESCRIPTION
136              
137             Games::Dice simulates die rolls. It uses a function-oriented (not
138             object-oriented) interface. No functions are exported by default. At
139             present, there are two functions which are exportable: C and
140             C. The latter is used internally by C, but can also be
141             exported by itself.
142              
143             The number and type of dice to roll is given in a style which should be
144             familiar to players of popular role-playing games: IdI[+-*/b]I.
145             I is optional and defaults to 1; it gives the number of dice to roll.
146             I indicates the number of sides to each die; the most common,
147             cube-shaped die is thus a d6. % can be used instead of 100 for I;
148             hence, rolling 2d% and 2d100 is equivalent. If F is used for I fudge
149             dice are used, which either results in -1, 0 or 1. C simulates I
150             rolls of I-sided dice and adds together the results. The optional end,
151             consisting of one of +-*/b and a number I, can modify the sum of the
152             individual dice. +-*/ are similar in that they take the sum of the rolls
153             and add or subtract I, or multiply or divide the sum by I. (x can
154             also be used instead of *.) Hence, 1d6+2 gives a number in the range
155             3..8, and 2d4*10 gives a number in the range 20..80. (Using / truncates
156             the result to an int after dividing.) Using b in this slot is a little
157             different: it's short for "best" and indicates "roll a number of dice,
158             but add together only the best few". For example, 5d6b3 rolls five six-
159             sided dice and adds together the three best rolls. This is sometimes
160             used, for example, in role-playing to give higher averages.
161              
162             Generally, C probably provides the nicer interface, since it does
163             the adding up itself. However, in some situations one may wish to
164             process the individual rolls (for example, I am told that in the game
165             Feng Shui, the number of dice to be rolled cannot be determined in
166             advance but depends on whether any 6s were rolled); in such a case, one
167             can use C to return an array of values, which can then be
168             examined or processed in an application-dependent manner.
169              
170             This having been said, comments and additions (especially if accompanied
171             by code!) to Games::Dice are welcome. So, using the above example, if
172             anyone wishes to contribute a function along the lines of roll_feng_shui
173             to become part of Games::Dice (or to support any other style of die
174             rolling), you can contribute it to the author's address, listed below.
175              
176             =head1 NAME
177              
178             =head1 AUTHORS
179              
180             =over 4
181              
182             =item *
183              
184             Philip Newton
185              
186             =item *
187              
188             Ricardo Signes
189              
190             =back
191              
192             =head1 CONTRIBUTORS
193              
194             =for stopwords Mario Domgoergen Mark Allen
195              
196             =over 4
197              
198             =item *
199              
200             Mario Domgoergen
201              
202             =item *
203              
204             Mark Allen
205              
206             =back
207              
208             =head1 COPYRIGHT AND LICENSE
209              
210             This software is Copyright (c) 1999 by Philip Newton.
211              
212             This is free software, licensed under:
213              
214             The MIT (X11) License
215              
216             =cut
217              
218             __END__