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>


Reply via email to