File Coverage

blib/lib/Games/Die.pm
Criterion Covered Total %
statement 26 27 96.3
branch 1 2 50.0
condition n/a
subroutine 8 8 100.0
pod 1 2 50.0
total 36 39 92.3


line stmt bran cond sub pod time code
1 1     1   48716 use strict;
  1         2  
  1         33  
2 1     1   5 use warnings;
  1         1  
  1         42  
3              
4             package Games::Die;
5             # ABSTRACT: Program that simulates ADVANCED die rolls using a grammar.
6 1     1   4 use base qw(Exporter);
  1         7  
  1         123  
7             our @EXPORT = qw(roll);
8 1     1   1824 use Parse::RecDescent;
  1         57637  
  1         10  
9 1     1   1357 use Data::Dumper;
  1         8017  
  1         107  
10 1     1   11 use List::Util qw(max reduce);
  1         2  
  1         979  
11              
12             #$::RD_TRACE=30;
13             #Parse::RecDescent::redirect_reporting_to(*STDOUT);
14             #$::RD_HINT = '1';
15             my $g = Parse::RecDescent->new(<<'EOG');
16             main: first /\Z/ {$item[1]}
17             first: multiple | more
18             multiple: more /x/ num {[$item[0],$item[1],$item[3]];}
19             more: { [$item[0], @{$item[1]}]; }
20             double: cond '>>' cond {[$item[0],$item[1],$item[3]];}
21             double: cond
22             cond: sum ('=='|'>='|'<='|'<>'|'='|'<'|'>'|'!=') sum {[$item[0],$item[1],$item[2], $item[3]];}
23             cond: sum
24             sum: { [$item[0], @{$item[1]}]; }
25             summand: dice | num
26             dice: 'd' num { [$item[0],['scalar',1],['scalar',0],$item[2]]}
27             dice: num 'd' '{' num '}' num {[$item[0],$item[1],$item[4],$item[6]]}
28             dice: num 'd' num {[$item[0],$item[1],['scalar',0],$item[3]]}
29             num: /\d+/ { ['scalar', $item[1]]; }
30             num: '(' double ')' {$item[2]}
31             EOG
32             my %table;
33              
34             sub ezec {
35 95     95 0 180 my ( $func, @args ) = @_;
36 95         224 $table{$func}->(@args);
37             }
38              
39             #dispatch table
40             $table{sum} = sub {
41              
42             my $v = ezec( @{ shift() } );
43             my $x = $v;
44             $v =~ s/\*//g;
45             while (@_) {
46             my $op = shift;
47             my $p = ezec( @{ shift() } );
48             $v = $v + $p if $op eq '+';
49             $v = max( $v - $p, 1 ) if $op eq '-';
50             }
51             return "$v*" if $x =~ /\*/;
52             return $v;
53             };
54             $table{cond} = sub {
55             my $l = ezec( @{ $_[0] } );
56             my $r = ezec( @{ $_[2] } );
57             my $op = $_[1];
58             $op = '==' if $op eq '=';
59             $op = '!=' if $op eq '<>';
60             if ( eval("$l$op$r") ) {
61             return "$l*";
62             }
63             else { return $l; }
64             };
65             $table{'scalar'} = sub {
66             return shift;
67             };
68             $table{'more'} = sub {
69             my @rolls;
70             my $v = ezec( @{ shift() } );
71             push @rolls, $v;
72             while (@_) {
73             my $p = ezec( @{ shift() } );
74             push @rolls, $p;
75             }
76             return join( "; ", @rolls );
77             };
78             $table{'multiple'} = sub {
79             my @rolls;
80             my $op = shift();
81             my $multiple = ezec( @{ shift() } );
82             for ( 1 .. $multiple ) {
83             push @rolls, ezec(@$op);
84             }
85             return join( "\n", @rolls );
86             };
87             $table{double} = sub {
88             my $f = ezec( @{ $_[0] } );
89             my $s = ezec( @{ $_[1] } );
90             return "$f>>" . ( $f + $s );
91             };
92             $table{dice} = sub {
93             my $v = 0;
94             my $ct = ezec( @{ $_[0] } );
95             my @rolls;
96             push @rolls, int( 1 + rand( ezec( @{ $_[2] } ) ) ) for ( 1 .. $ct );
97             map { $v += $_ } sort @rolls[ 0 .. $#rolls - ezec( @{ $_[1] } ) ];
98             return $v;
99             };
100              
101             sub roll {
102 11     11 1 144 my $output = $g->main( join( " ", @_ ) );
103 11         392393 my $result;
104 11         35 eval { $result = ezec(@$output); };
  11         50  
105 11 50       26 if ($@) {
106 0         0 $result = "dice not recognized";
107             }
108              
109             #print "->" . Dumper( $output, $@ );
110 11         111 return $result;
111             }
112              
113             1;
114              
115              
116             __END__