ellem has asked for the wisdom of the Perl Monks concerning the following question:

the formula:
4d6, discard 1s and add the three highest rolls. Do this six times.

yup pretty standard D&D ability rolls :)

So here's the questions:

using
#! /usr/local/bin/perl use warnings ; use strict ; #Die Roller: uses 4d6 discarding the lowest number #rerolling any roll of 1 my $roll = 6 ; until ($roll == 0) { chomp $roll ; $roll -- ; my $d61 = int(rand(6) + 1) ; my $d62 = int(rand(6) + 1) ; my $d63 = int(rand(6) + 1) ; my $d64 = int(rand(6) + 1) ; print "$d61, $d62, $d63, $d64\n\n" ; }
I get output like:

5, 2, 5, 4
4, 3, 6, 4
3, 6, 4, 5
5, 1, 2, 3
6, 5, 5, 2
2, 6, 5, 1

OK so I'll use an if/else statment to reroll the 1s (does that sound reasonabe?) but how do I figure out and discard the lowest number?
--
ellem@optonline.net
There's more than one way to do it, just don't use my way.

Replies are listed 'Best First'.
Re: Trick die rolling
by Juerd (Abbot) on Mar 10, 2002 at 17:20 UTC

    (Warning: untested code ahead)

    sub roll { my ($max) = @_; return 1 + int rand $max; } sub sum { my $sum = 0; $sum += $_ for @_; return $sum; } my @dice; ROLL: for (1..4) { push @dice, roll 6; pop @dice and redo ROLL if $dice[-1] == 1; } # Discard lowest @dice = sort { $a <=> $b } @dice; unshift @dice; my $sum = sum @dice;

    44696420796F7520732F2F2F65206F
    7220756E7061636B3F202F6D736720
    6D6521203A29202D2D204A75657264
    

Re: Trick die rolling
by cacharbe (Curate) on Mar 10, 2002 at 17:29 UTC
    I would say something like:
    use strict; my @rolls; foreach (0..3){ my $roll = 1; while ($roll == 1) { $roll = int(rand(6) + 1) ; } $rolls[$_]= $roll; } @rolls =reverse sort @rolls; pop @rolls; print @rolls; &AddRolls(\@rolls);
    I leave the AddRolls sub as an exercise for the reader.

    C-.

Re: Trick die rolling
by atcroft (Abbot) on Mar 10, 2002 at 21:44 UTC
    Here is the code I wrote after reading the problem:
    #!/usr/bin/perl -w use strict; srand; my $numtimes = 6; for ( my $rollattempt = 0 ; $rollattempt < $numtimes ; $rollattempt++ ) { my $numdice = 4; my $numsides = 6; my $sumof = 3; my $highest = 1; my @excludes = (1); print( "Roll attempt: ", $rollattempt, "\n", "\t", "Sum: ", &exclude_and_sum( $numdice, $numsides, $sumof, $highest, @excludes ), "\n" ); } sub exclude_and_sum { my ( $nd, $ns, $so, $high, @excl ) = @_; my @droll = (); my @temproll = (); my $sum = 0; for ( my $dice = 0 ; $dice < $nd ; $dice++ ) { push ( @droll, int( rand($ns) + 1 ) ); } @temproll = sort(@droll); @droll = (); while ( my $d = pop (@temproll) ) { $d = int( rand($ns) + 1 ) if ( scalar( grep( $d, @excl ) ) ); push ( @droll, $d ); } if ($high) { @droll = sort(@droll); } else { @droll = sort( { $b <=> $a } @droll ); } for ( my $count = 0 ; $count < $so ; $count++ ) { $sum += pop (@droll); } return ($sum); }
    My output looked like:
    Roll attempt: 0
    	Sum: 12
    Roll attempt: 1
    	Sum: 10
    Roll attempt: 2
    	Sum: 10
    Roll attempt: 3
    	Sum: 11
    Roll attempt: 4
    	Sum: 9
    Roll attempt: 5
    	Sum: 12
    

    As I envision it, this code (barring any unforeseen logic errors) should allow an array of excluded numbers to be set, and allow for the number of values in the sum, the number and sides of the dice, and which numbers (highest or lowest) to be in the sum to be easily selectable. However, I can't guarantee this code free of errors in logic, so please comment if you see any. And, as always, I look forward to the comments of others, so we may each our wisdom increase.

Re: Trick die rolling
by TStanley (Canon) on Mar 11, 2002 at 01:27 UTC
    Here is an interesting node where some of us got into a short discussion on creating a die rolling program for Dungeons & Dragons.

    TStanley
    --------
    "Suppose you were an idiot... And suppose you were a
    member of Congress... But I repeat myself." -- Mark Twain

Re: Trick die rolling
by Parham (Friar) on Mar 10, 2002 at 23:17 UTC
    in any 1 roll, it rerolls the lowest number. It will also add the three highest sets of rolls and print it out. I know my version isn't as well done as others, but i didn't sit down to really work with it.. just fixed your code here and there to try and keep as much of it intact :).
    #!/usr/bin/perl use warnings; use strict; #Die Roller: uses 4d6 discarding the lowest number #rerolling any roll of 1 my $roll = 6; my @sums; until ($roll == 0) { my @d6; chomp $roll; $roll--; $d6[0] = int(rand(6) + 1); $d6[1] = int(rand(6) + 1); $d6[2] = int(rand(6) + 1); $d6[3] = int(rand(6) + 1); @d6 = sort @d6; $d6[0] = int(rand(6) + 1); #reroll lowest number my $sum = $d6[0] + $d6[1] + $d6[2] + $d6[3]; push(@sums, $sum); print "$d6[0], $d6[1], $d6[2], $d6[3] : $sum\n\n"; } @sums = sort @sums; my $three_highest = $sums[3] + $sums[4] + $sums[5]; #add three highest + numbers in array print "total of three highest roles : $three_highest";
    EDIT... posted too quick and didn't even read your post in whole (missed the reroll of ONLY 1's)... i guess you didn't want one that looked like your version either :P, nonetheless, i'll keep the code here for you :).
Re: Trick die rolling
by johannz (Hermit) on Mar 10, 2002 at 23:03 UTC
    #!perl use strict; use warnings; print roll_die(4, 6, 2, 3), "\n" for (0..5); sub roll_die { my ($number, $sides, $min, $keep) = @_; # With arrays, 'x' operator will fill with that many elements my @rolls = ( 0 ) x $number; # For each die, roll better than number # In for's, $_ is automagically local'ed for (@rolls) { while ($_ < $min) { $_ = int(rand($sides) + 1 )} }; # Now sort and select (Numerically, but in reverse order.) @rolls = sort {$b <=> $a} @rolls; splice @rolls, $keep; # And finally, return the value return eval(join('+', @rolls)); }