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

This code:
#! /usr/local/bin/perl use diagnostics ; use warnings ; use strict ; my $roll = 6 ; until ($roll == 0) { chomp $roll ; $roll -- ; my $d61 = int(rand(5) + 2) ; my $d62 = int(rand(5) + 2) ; my $d63 = int(rand(5) + 2) ; my $d64 = int(rand(5) + 2) ; my @d1s = sort { $b <=> $a } $d61 ; my @d2s = sort { $b <=> $a } $d62 ; my @d3s = sort { $b <=> $a } $d63 ; my @d4s = sort { $b <=> $a } $d64 ; my @all = sort { $b <=> $a } @d1s, @d2s, @d3s, @d4s ; print "\n@all \n\n" ; }
produces:
4 4 3 2 6 6 2 2 6 6 5 2 5 3 3 2 5 4 4 3 6 4 3 2
Which is great; but for the next step I need to remove the lowest number (and ultimately add together the remaining three) but I can't seem to ask the correct question of perldocs to get to my answer on hw to remove the lowest number.

Anyone got a way to shove me in the right direction?
--
ellem@optonline.net
There's more than one way to do it, but only some of them actually work.

Replies are listed 'Best First'.
Re: Remove lowest number
by davorg (Chancellor) on Aug 06, 2003 at 15:25 UTC

    You want to remove the lowest number from @all? And you've already sorted it in descending numerical order.

    pop @all;
    --
    <http://www.dave.org.uk>

    "The first rule of Perl club is you do not talk about Perl club."
    -- Chip Salzenberg

      And then to sum up the rest ...
      use List::Util qw(sum); my $sum = sum(@all);
      Update: or just drop the pop and dice up a slice:
      my $sum = sum( @all[0 .. $#all-1] );

      jeffa

      L-LL-L--L-LL-L--L-LL-L--
      -R--R-RR-R--R-RR-R--R-RR
      B--B--B--B--B--B--B--B--
      H---H---H---H---H---H---
      (the triplet paradiddle with high-hat)
      
      I appreciate the answer. You obviously know Perl really well. Me; not so good. So what would I ask perldocs to get to pop (which I am now looking up in perldocs)?

      To clarify, how would I phrase my question in perldocs to get perldocs to tell me about pop without me mentioning pop?
      --
      ellem@optonline.net
      There's more than one way to do it, but only some of them actually work.
        pop is a built-in function. You can find docs on these funtions with the -f option:
        perldoc -f pop

        jeffa

        L-LL-L--L-LL-L--L-LL-L--
        -R--R-RR-R--R-RR-R--R-RR
        B--B--B--B--B--B--B--B--
        H---H---H---H---H---H---
        (the triplet paradiddle with high-hat)
        
        perldoc -f pop
Re: Remove lowest number
by Mr. Muskrat (Canon) on Aug 06, 2003 at 15:38 UTC

    I took some of your code, some of my own and added in jeffa's summation snippet for good measure.

    #! /usr/local/bin/perl use diagnostics; use warnings; use strict; use Games::Dice 'roll_array'; # this module rocks (well rolls anyway + ;-) use List::Util qw(sum); my $rolls = 6; for my $roll (1 .. $rolls) { # how many sets of dice rolls determin +ed by the value of $rolls my @rolls = roll_array '4d6'; # magic ;-) print "raw rolls: @rolls\n"; @rolls = sort @rolls; # sorted lowest to highest shift @rolls; # remove the lowest value by shifting +it off print "top three rolls: @rolls\n"; my $sum = sum(@rolls); # List::Util's sum print "total: $sum\n"; }

      Uhh ... Musky? ellem was making all 1's into 2's. Your code doesn't do that. :-)

      ------
      We are the carpenters and bricklayers of the Information Age.

      The idea is a little like C++ templates, except not quite so brain-meltingly complicated. -- TheDamian, Exegesis 6

      Please remember that I'm crufty and crochety. All opinions are purely mine and all code is untested, unless otherwise specified.

        I know :-)
        I don't use "fixed" dice.

      Way more Perly, but I have to read this code six months from now and my code (at least to me) makes sense without commenting it to death.

      My biggest Perl obstacle is I don't use it everyday.
      --
      ellem@optonline.net
      There's more than one way to do it, but only some of them actually work.
Re: Remove lowest number
by Abigail-II (Bishop) on Aug 06, 2003 at 15:49 UTC
    my @d1s = sort { $b <=> $a } $d61 ; my @d2s = sort { $b <=> $a } $d62 ; my @d3s = sort { $b <=> $a } $d63 ; my @d4s = sort { $b <=> $a } $d64 ;

    What is the point of this? Sorting lone scalars, and putting them in one element arrays? What's the point of chomping $roll? I would write that as:

    #!/usr/bin/perl use strict; use warnings; my $tosses = 5; my $dice = 4; foreach (1 .. $tosses) { my @rolls = sort {$b <=> $a} map {2 + int rand 5} 1 .. $dice; pop @rolls; my $sum = 0; $sum += $_ for @rolls; print "\n@rolls: $sum\n\n"; } __END__

    And that includes finding the top-3 rolls and summing them.

    Abigail

      First let's understand that I have no idea what I am doing and only a murky idea of what I want to do!

      OK I'll give you the chomp I think that had something to do with an older version of this. See mostly I make Perl read logs and take data from different sources and shove it all together. But I don't do this everyday and as such I suck at it.

      OK, so I thought:
      my @num = (8, 9, 3, 5, 1, 2, 6, 7) ; my @all = sort { $b <=> $a } @num ;
      thus:
      my $num5 = 5 ; my $num4 = 4 ; my $num3 = 3 ; my $num2 = 2 ; my @all = sort { $b <=> $a } $num4, $num2, $num5, $num3 ;
      So when I was writing this code:
      my @d1s = sort { $b <=> $a } $d61 ;
      I thought I was sorting $d61 and I thought it might be hard to get at the lowest number inside $. Apparently I was wrong, but your code is over my head.
      $sum += $_ for @rolls;
      Doesn't mean a lot to me. The whole $_ thing confuses me.

      UPDATE:

      I really looked at this answer, suggestion and I started commenting things out to see which part of my code was really useless. Here's what is left:
      #! /usr/local/bin/perl use diagnostics ; use warnings ; use strict ; use List::Util qw (sum) ; #not in the standard distro my $roll = 6 ; until ($roll == 0) { #rolls the dice 6 times $roll -- ; my @d61 = int(rand(5) + 2) ; #6 sided die with no 1 my @d62 = int(rand(5) + 2) ; my @d63 = int(rand(5) + 2) ; my @d64 = int(rand(5) + 2) ; my @all = sort #split line for looks { $b <=> $a } @d61, @d62, @d63, @d64 ; #sorts rolls #to prepare for pop @all ; #pop removing #the lowest roll my $sum = sum(@all) ; #before adding print "\n@all - $sum\n" ; }

      --
      ellem@optonline.net
      There's more than one way to do it, but only some of them actually work.
Re: Remove lowest number
by dragonchild (Archbishop) on Aug 06, 2003 at 15:49 UTC
    Heh. Gotta love AD&D auto-dicerollers. 4d6, all 1's are 2's, drop the lowest. *laughs*

    There's a much better way of doing what you're doing.

    sub roll_die { my ($sides, $min) = @_; return int(rand($sides - $min + 1) + $min); } sub my_roller { my ($num_dice, $sides, $min_value, $num_to_drop) = @_; $num_dice ||= 3; $min_value ||= 1; $num_to_drop ||= 0; return () unless $num_dice >= 1; return () unless $num_dice > $num_to_drop; my @values = sort { $a <=> $b } map { roll_die($sides, $min_value) } 1 .. $num_dice; return @values[$num_to_drop .. $#values]; } my @values = my_roller(4, 6, 2, 1); print "@values\n";
    This code has been tested relatively thoroughly. You should be able to just drop the functions into your existing code, or run it separately as provided.

    Improvements made over what you posted:

    1. I separated out the thing that actually does the rolling from the thing that does the collating of the values. This is important because you might want to change them separately.
    2. I also made a function to do the collating. This is important because you want to roll dice for reasons other than generating stats. For example, you can get a combat roll by my $roll = my_roller(1, 20); In other words, 1d20.
    If you want an explanation of how the code works, please ask.

    ------
    We are the carpenters and bricklayers of the Information Age.

    The idea is a little like C++ templates, except not quite so brain-meltingly complicated. -- TheDamian, Exegesis 6

    Please remember that I'm crufty and crochety. All opinions are purely mine and all code is untested, unless otherwise specified.

Re: Remove lowest number
by monktim (Friar) on Aug 06, 2003 at 16:33 UTC
    You don't need all this sorting and all these arrays in your code.
    my @d1s = sort { $b <=> $a } $d61 ; my @d2s = sort { $b <=> $a } $d62 ; my @d3s = sort { $b <=> $a } $d63 ; my @d4s = sort { $b <=> $a } $d64 ; my @all = sort { $b <=> $a } @d1s, @d2s, @d3s, @d4s ; print "\n@all \n\n" ;
    You can replace it with this which has the sum snippit someone else posted:
    my @all = sort { $b <=> $a } $d61, $d62, $d63, $d64; use List::Util qw(sum); my $sum = sum( @all[0 .. $#all-1] ); print "@all $sum\n";
    You can even do this with less code put I was beat to the punch.
Re: Remove lowest number
by blue_cowdawg (Monsignor) on Aug 06, 2003 at 15:55 UTC

    Here is a subset of code that I had written to solve the problem. The essential ingredients are there.

        #!/usr/bin/perl -w use strict; use warnings; use diagnostics; my @rolls=(); foreach (0..7){ $rolls[$_]=d2d6(); } my @keys=sort {$a cmp $b} @rolls; my %ptr=map { $_ => 1 } @keys; $ptr{$keys[0]}=0; my @cull = grep $ptr{$_} ,@rolls; print "Sorted: ",join(" ",@keys),"\n"; print "Before culling: ",join(" ",@rolls),"\n"; print "After culling: ",join(" ",@cull),"\n"; exit(0); sub d1d6 { return int(rand(6))+1; } sub d2d6 { return d1d6() + d1d6(); }

    Running the code produces:

        # perl dice.pl Sorted: 3 3 4 5 7 7 7 9 Before culling: 3 5 7 4 7 9 7 3 After culling: 5 7 4 7 9 7
    You can see the problem with is that it removes duplicates of the rolled number as well. You can modify the code to count the number of occurances and then ignore the first occurance and print the rest of the occurances.

    I've used variants this code to generate FRP gaming information in the past where the system was to roll N+2 number of rolls plus one and ignore the lowest and highest roll.


    Peter @ Berghold . Net

    Sieze the cow! Bite the day!

    Test the code? We don't need to test no stinkin' code! All code posted here is as is where is unless otherwise stated.

    Brewer of Belgian style Ales

Re: Remove lowest number
by KPeter0314 (Deacon) on Aug 06, 2003 at 15:42 UTC
    Since it is sorted, print everything up to the next-to-last element.
    foreach $i ( 0..$#all-1 ) { print "$all[$i]"; }
    I know there is a shorter way of writing this...

    -Kurt

    davorg: Good one, forgot about pop. But only if you don't want to preserve the array.