Home: Need a Custom or Prewritten Perl Program?: Throw Down The Gauntlet:
D&D Roll



dw.worker.bee
Novice

Sep 23, 2011, 7:22 AM


Views: 80834
D&D Roll

Hello, I'm new to the forum and wasn't sure if this belonged in Golf or Throw Down the Gauntlet. (I'm sure you will let me know) <smile>

When I'm on a boring phone meeting these days I work on my PERL, I'm a beginner and would like to write awesome code. The below code works but is clumsy. I'm betting someone can show me how to do it without so many variables and if/then statements. Just the subroutine.

If you ever played D&D, this would provide a random number within a certain range.

#!/usr/bin/perl
use strict;


sub dieRoll {
my ($drInValue, $drOutValue);
my ($drMult, $drDie, $drOper, $drAddVal, $drHold);
$drInValue = $_[0];
($drHold, $drAddVal) = split(/[\+\-]/, $drInValue);
($drMult, $drDie) = split(/[dD]/, $drHold);
for ($drMult; $drMult >= 1; $drMult--) {
$drOutValue += int(rand()*$drDie) + 1;
}
if ($drInValue =~ /\+/) {
$drOutValue += $drAddVal;
}
if ($drInValue =~ /\-/) {
$drOutValue -= $drAddVal;
}

return $drOutValue;
}


#...begin
my $count=0;
for ($count = 5; $count >= 1; $count--) {
my $RollTheDice="4d10+5";
print "Rolling the dice: $RollTheDice: $count: " . &dieRoll($RollTheDice). "\n";
}


Rolling the dice: 4d10+5: 5: 34
Rolling the dice: 4d10+5: 4: 27
Rolling the dice: 4d10+5: 3: 19
Rolling the dice: 4d10+5: 2: 24
Rolling the dice: 4d10+5: 1: 28


BillKSmith
Veteran

Oct 31, 2011, 1:17 PM


Views: 77808
Re: [dw.worker.bee] D&D Roll

The function new_dieRoll is equivalent to your dieRoll. I have used the module Test::More to show that is the same for all the test cases you supplied and a few more that I made up.


Code
  

#!/usr/bin/perl
use strict;
use Test::More qw( no_plan);

sub dieRoll {
my ($drInValue, $drOutValue);
my ($drMult, $drDie, $drOper, $drAddVal, $drHold);
$drInValue = $_[0];
($drHold, $drAddVal) = split(/[\+\-]/, $drInValue);
($drMult, $drDie) = split(/[dD]/, $drHold);
for ($drMult; $drMult >= 1; $drMult--) {
$drOutValue += int(rand()*$drDie) + 1;
}
if ($drInValue =~ /\+/) {
$drOutValue += $drAddVal;
}
if ($drInValue =~ /\-/) {
$drOutValue -= $drAddVal;
}

return $drOutValue;
}


sub new_dieRoll {
my ($drMult, $drDie, $drAddVal) = $_[0] =~ m/(\d+)[Dd](\d+)([-+]\d+)/;
my $drOutValue = $drAddVal + $drMult ;
$drOutValue += int( rand $drDie ) for (1..$drMult);
return $drOutValue;
}

#...begin
my $count = 0;
for ( $count = 5; $count >= 1; $count-- ) {
my $RollTheDice = "4d10+5";
my $seed = rand(1000000);
my $expected = do { srand $seed; dieRoll($RollTheDice) } ;
my $new = do { srand $seed; new_dieRoll($RollTheDice) } ;
is( $new, $expected, $RollTheDice );
}

my @Rolls = (
'4d10-5',
'4d12-5',
'3d10+4',
);
for my $Roll (@Rolls) {
my $seed = rand(1000000);
my $expected = do { srand $seed; dieRoll($Roll) } ;
my $new = do { srand $seed; new_dieRoll($Roll) } ;
is( $new, $expected, $Roll );
}



Note: Parsing the input with a regular expression rather than split takes less code, no temporary variables, and it preserves the sign of drAddVal.
Good Luck,
Bill