If you total the weights, pick a rand number between 0 and that total, and then scan the weights, subtracting each from the picked number until it drops below zero; the index of the weight at that point is the ship you want.
sub pick { my( $total, @weights ) = @_; my $rand = rand $total; ( $rand -= $weights[ $_ ] ) < 0 and return $_ for 0 .. $#weights; }
This also works for real weights.
If the number of weights gets to be more than a few tens often, then switching the sub to take an array ref is simple.
And if the weights change frequently, you can do the totalling inside the sub also. I left it external for the test harness.
A little test harness to check it is fair:
#! perl -slw use strict; use List::Util qw[ sum ]; our $SHIPS ||= 10; our $REPS ||= 1e5; sub pick { my( $total, @weights ) = @_; my $rand = rand $total; ( $rand -= $weights[ $_ ] ) < 0 and return $_ for 0 .. $#weights; } my @weights = map rand( 16 ), 1 .. $SHIPS; my $total = sum @weights; my @stats; for ( 1 .. $REPS ) { ++$stats[ pick( $total, @weights ) ]; } for ( 0 .. $#stats ) { printf "%2d: Expected: %6.3f%% Actual: %6.3f%%\n", $_, $weights[ $_ ] *100 / $total, $stats[ $_ ] *100 / $REPS; } print sum( @stats ) *100 / $REPS, '%' ;
Gives:
C:\test>junk6 -SHIPS=4 -REPS=1e5 0: Expected: 16.519% Actual: 16.604% 1: Expected: 14.400% Actual: 14.466% 2: Expected: 51.934% Actual: 51.844% 3: Expected: 17.147% Actual: 17.086% 100% C:\test>junk6 -SHIPS=20 -REPS=1e5 0: Expected: 2.126% Actual: 2.103% 1: Expected: 6.746% Actual: 6.834% 2: Expected: 0.847% Actual: 0.825% 3: Expected: 4.063% Actual: 4.133% 4: Expected: 4.473% Actual: 4.412% 5: Expected: 6.020% Actual: 6.079% 6: Expected: 2.758% Actual: 2.727% 7: Expected: 5.133% Actual: 5.055% 8: Expected: 4.221% Actual: 4.215% 9: Expected: 0.189% Actual: 0.191% 10: Expected: 2.151% Actual: 2.171% 11: Expected: 9.417% Actual: 9.511% 12: Expected: 5.079% Actual: 5.148% 13: Expected: 6.905% Actual: 7.080% 14: Expected: 9.644% Actual: 9.539% 15: Expected: 6.291% Actual: 6.266% 16: Expected: 1.084% Actual: 1.073% 17: Expected: 7.653% Actual: 7.578% 18: Expected: 9.065% Actual: 9.043% 19: Expected: 6.133% Actual: 6.017% C:\test>junk6 -SHIPS=2 -REPS=1e2 0: Expected: 92.414% Actual: 96.000% 1: Expected: 7.586% Actual: 4.000% 100% C:\test>junk6 -SHIPS=2 -REPS=1e2 0: Expected: 56.789% Actual: 55.000% 1: Expected: 43.211% Actual: 45.000% 100%
In reply to Re: Rolling For Initiative
by BrowserUk
in thread Rolling For Initiative
by SuicideJunkie
| For: | Use: | ||
| & | & | ||
| < | < | ||
| > | > | ||
| [ | [ | ||
| ] | ] |