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%

Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
"Science is about questioning the status quo. Questioning authority".
In the absence of evidence, opinion is indistinguishable from prejudice.
"Too many [] have been sedated by an oppressive environment of political correctness and risk aversion."

In reply to Re: Rolling For Initiative by BrowserUk
in thread Rolling For Initiative by SuicideJunkie

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post, it's "PerlMonks-approved HTML":



  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, details, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.