#!perl -l
use strict;
use warnings;
$|++;
#162 chars, including sub decl.
sub A{my($d,$s,$l,$y,$c,$t,$z)=@_;$c||=\$z;if(!$d){
$t+=$_ for(sort{$a<=>$b}@$y)[$l..$#$y];$$c++}else{$t+=A
($d-1,$s,$l,[@{$y||[]},$_],$c)for 1..$s}$y?$t:$t/$z}
####
sub avg_roll{
my($num_dice,
$sides_of_dice,
$num_to_lose,
# We only expect the below to be provided when called
# recursively
$rolled_ref,
$counter_ref)=@_;
my ($total,$counter); # we declare these with the @_ in the golf
# version here we seperate them to show they
# arent really parameters.
$counter_ref||=\$counter; # make a reference to our counter,
# unless we were called recursively;
unless ($num_dice){ # we are done, no more dice
$total+=$_ # increment the total by the value of the dice
for (
sort {$a<=>$b} @$rolled_ref # sort the results numerically
# to make avg_roll(4,12,1) work.
)[$num_to_lose..$#$rolled_ref]; # take a slice
$$counter_ref++ # incrememnt the counter
} else { # we havent finished rolling
$total+= # so increment the total
avg_roll( # by the result
$num_dice-1, # of the next die
$sides_of_dice,
$num_to_lose,
[ # pass in a ref,
@{$rolled_ref||[]}, # containing the previous rolls
$_ # and the new one
],
$counter_ref # and a way to access the counter
)
for 1..$sides_of_dice # for each possible roll of the die
}
$rolled_ref ? $total # if we are not the root of the recursion
# return the total, whatever it may be
: $total/$counter # return the average.
}
####
print A(4,6,1);
print avg_roll(4,6,1);
__END__
12.2445987654321
12.2445987654321
####
sub B{my($d,$s,$l,$c,@y,$t,$z)=@_;$c||=\$z;if(!$d){$t+=$_
for(sort{$a<=>$b}@y)[$l..$#y];$$c++}else{$t+=B($d-1,$s,$l,
$c,@y,$_)for 1..$s}@y?$t:$t/$z}