2009-08-23, 01:45 PM
Okay I went to Wikipedia's page on Dice and found an algorithm to calculate the odds of getting a certain sum with i s-sided dice. Wrote a Perl script to test it.
![[Image: distt.png]](http://img38.imageshack.us/img38/7766/distt.png)
95% means you'll be doing that at least that number 95% of the time. So if it says 95% = 100, you can 95% 1hko anything with 100 HP.
Only problem is that it's massively recursive so that it takes forever to calculate anything with more than 3 dice, and that's on 2-digit ranges. Does not work at all for large ranges.
Here's the code:
![[Image: distt.png]](http://img38.imageshack.us/img38/7766/distt.png)
95% means you'll be doing that at least that number 95% of the time. So if it says 95% = 100, you can 95% 1hko anything with 100 HP.
Only problem is that it's massively recursive so that it takes forever to calculate anything with more than 3 dice, and that's on 2-digit ranges. Does not work at all for large ranges.
Here's the code:
Code:
#!usr/bin/perl
use strict;
use warnings;
die "Usage: $0 min max hits %dmg\n" if (@ARGV != 4);
#main
my $sides = $ARGV[1] - $ARGV[0] + 1;
my $dice = $ARGV[2];
my $offset_add = ($ARGV[0] - 1);
my $offset_mult = $ARGV[3];
my $poss = &power($sides, $dice);
my $sum = 0;
my %distr;
my @checkpoints = qw(100 095 075 050 025 005 001);
my $counter = 0;
for (my $i = $dice; $i <= $sides*$dice; $i++)
{
if (100*$sum/$poss >= 100 - $checkpoints[$counter])
{
$distr{$checkpoints[$counter]} = $i;
$counter++; #find next distribution checkpoint
last if ($counter >= @checkpoints);
}
$sum += &recf($sides, $dice, $i);
}
print "Distribution:\n",
foreach my $key (sort keys %distr)
{
my $vl = ($distr{$key} + $offset_add*$dice) * $offset_mult/100;
printf "%3d%% = %d\n", $key, $vl;
}
sub recf #(sds, ithd, num)
#Recursive function to find possible ways to roll a particular number. algorithm is
#F[sds,ithd](num) = sum(F[sds,1](n)*F[sds,i-1](num-n), n) for all integer n
#base case is f[sds,1](num) = 1 if 1 <= num <= sds, 0 else
{
my ($sds, $ithd, $num) = @_;
return ($num >= 1 && $num <= $sds)? 1 : 0 if ($ithd == 1);
my $total = 0;
for (my $i = 1; $i <= $sds; $i++)
{
my $j = $num - $i;
$total += &recf($sds, 1, $i) * &recf($sds, $ithd - 1, $j);
}
return $total;
}
sub power #(base, expo)
{
my ($base, $expo) = @_;
if ($expo == 0) { return 1; }
elsif ($expo % 2 == 1) { return $base * &power($base, $expo - 1); }
else
{
my $x = &power($base, $expo/2);
return $x*$x;
}
}
