Charles Lu <[EMAIL PROTECTED]> wrote:
:
: If I want to randomly generate a dice (4 side) roll, I can use
: the following expression:
:
: $roll = 1 + int( rand(4));
:
: This assumes that every side of this dice has equal chance of
: being rolled (0.25). Thats easy. Now What if I say, that the
: probability of rolling a 3 is 70% and the probability of rolling
: a 1 or 2 or 4 is 10%.
:
: i.e.
: $probability = { '1' => 0.1,
: '2' => 0.1,
: '3' => 0.7,
: '4' => 0.1,
: }
:
: Notice the total probability still addes up to 1. So If I want
: to roll this "loaded" dice, how should I modify the above code
: to accurately reflect the different weight of this new dice?
Perhaps this is overkill, but ...
Well, okay it is overkill, but I was bored and thought:
Why stop at just four sides?
And what about 1-sided dice for testing?
And unloaded dice?
#!/usr/bin/perl
use strict;
use warnings;
#use Data::Dumper;
#
load_die(
1 => 0.1,
2 => 0.1,
3 => 0.7,
4 => 0.1,
);
printf "%s\n", roll_loaded_die() foreach ( 0 .. 9 );
printf "%s\n", roll_unloaded_die() foreach ( 0 .. 9 );
#
load_die(
'misses' => 1/3,
'hits' => 1/2,
'loses weapon' => 2/18,
'killed it' => 1/18,
'Huh!' => 0, # just because! :)
);
printf "Boris %s!\n", roll_loaded_die() foreach ( 0 .. 39 );
printf "Boris %s!\n", roll_unloaded_die() foreach ( 0 .. 39 );
printf "On the last roll Boris %s.\n", last_roll();
#
load_die(
1 => 1/100,
2 => 1/100,
3 => 1/100,
4 => 1/100,
5 => 1/100,
6 => 1/100,
7 => 1/100,
8 => 1/100,
9 => 1/100,
10 => 2/100,
11 => 2/100,
12 => 2/100,
13 => 2/100,
14 => 2/100,
15 => 2/100,
16 => 2/100,
17 => 2/100,
18 => 2/100,
19 => 2/100,
20 => 2/100,
21 => 11/100,
22 => 11/100,
23 => 11/100,
24 => 11/100,
25 => 11/100,
26 => 14/100,
);
printf "%s\n", roll_loaded_die() foreach ( 0 .. 39 );
{
# these variables are only accessible within this scope
# the subroutines in here can "see" them, but not the main
# program
my %sides; # holds die side names and probabilities
my $sum; # used as a check for total probability
my $last_roll; # remembers the last roll of the die
sub load_die {
die "load_die() expected a list of sides and probabilities"
unless @_ > 1;
die "load_die() expected even number of arguments.\n"
if @_ % 2;
$sum = 0;
%sides = ();
my %probability = @_;
foreach my $value ( sort { $a <=> $b } values %probability ) {
die "Sorry, no imaginary dice!" if $value < 0;
# cumulate values
$sum += sprintf '%.5f', $value;
# store cumulative probabilities
$value = $sum;
}
# print Dumper \%probability;
# precision is just a guess - needs testing
die "load_die() expected sides to sum to 1.\n"
unless $sum > .9999 && $sum < 1.0001;
# each value is now unique
# convert human-readable format
# to algorithm-readable format
%sides = reverse %probability;
# print Dumper \%sides;
}
# once the die is loaded it can be rolled multiple times
sub roll_loaded_die {
die "Please load the side ratios first.\n"
unless keys %sides;
my $roll = rand;
foreach my $probability ( sort { $a <=> $b } keys %sides ) {
next if $roll > $probability;
$last_roll = $sides{ $probability };
last;
}
return $last_roll;
}
sub roll_unloaded_die {
die "Please load the side ratios first.\n"
unless keys %sides;
# the first 'values %sides' is in list context and
# the second is in scalar context :)
$last_roll = ( values %sides )[ rand values %sides ];
return $last_roll;
}
# return the last roll
sub last_roll {
return $last_roll;
}
}
HTH,
Charles K. Clarkson
--
Head Bottle Washer,
Clarkson Energy Homes, Inc.
Mobile Home Specialists
254 968-8328
Alright, I said I was bored!
--
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]
<http://learn.perl.org/> <http://learn.perl.org/first-response>