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>