#!/usr/bin/perl ################################################### # Scott Baker - 2008-03-06 # Released under the GPLV3 # # A simple script to roll dice, or multiple dice # Example: Roll two d20 and add 10 # ./dice_roll.pl 2d20+10 # # Roll a d6 # ./dice_roll.pl 1d6 # # Roll three d10 subtract three (10 times) # ./dice_roll.pl 3d10-3 10 ################################################### use Data::Dumper; use List::Util qw[min max sum]; # Get the dice and times my $dice = valid_dice($ARGV[0]); my $times = int($ARGV[1]); $times ||= 1; my $verbose = 0; my $args = join(" ",@ARGV); if ($args =~ /-v/) { $verbose = 1;} if (!$dice) { die(usage()); } my $res; my $gt; # Loop through for each roll for (my $i = 0; $i < $times; $i++) { # Print the roll number print "Roll #" . sprintf("%02d",($i + 1)) . ": "; # Roll the actual dice my $roll = roll_me($dice); # Get the total for summary later, and also update the grand total my $tot = $roll->{'total'}; $gt += $tot; # Store the total of the roll for stats later $res->{$tot}++; # Print the textual representation of this roll print $roll->{'textual'} . "\n"; } # If there is more than one roll show some summary stats if ($times > 1) { my $min = min(keys(%$res)); my $max = max(keys(%$res)); my $avg = sprintf("%.2f",$gt / $times); print "\n"; print "Min: $min Max: $max\n"; print "Average roll: " . round($avg) . " ($avg)\n"; } #print Dumper($res); ########################################################## sub roll_me { my $dice = shift(); $dice =~ /\s+/g; # Get the appropriate pieces of the dice syntax my ($mult,$sides,$neg,$addit) = $dice =~ /(\d+?)?d(\d+)([+\-])?(\d+)?/i; $mult = int($mult); # Can't have a mult of zero if ($mult == 0) { $mult = 1; } $addit = int($addit); # If the +/- is negative, flip addit to negative if ($neg eq '-') { $addit = -$addit; } if ($verbose) { print "\n* '$dice' means roll a $sides sided dice $mult times"; if ($addit) { print " and add $addit"; } print "\n"; } my @roll = (); # For each mult roll the dice and add it to the array for (my $i = 0; $i < $mult; $i++) { my $num = int(rand($sides)) + 1; # 10 sideo dice are weird and have numbers 0-9 (instead of 1-10) # so subtract 1 to get the right number if ($sides == 10) { $num--; } push(@roll,$num); } # Get the total of all the dice rolls my $total = sum(@roll) + $addit; my $text; # If there is an additional add that section at the end if ($addit) { $text = "(" . join(" + ", @roll) . ") + " . $addit . " = " . $total; } else { $text = "(" . join(" + ", @roll) . ") = " . $total; } # Build the big return hash my $ret; $ret->{'total'} = $total; $ret->{'additional'} = $addit; $ret->{'rolls'} = \@roll; $ret->{'textual'} = $text; return $ret; } # Only works for positive numbers (good enough) sub round { my $number = shift; return int($number + .5); } sub usage { my $ret .= "$0 [Dice] [Times]\n"; $ret .= "Example: $0 2d20+3 10\n"; } sub valid_dice { my $t = shift(); # At the minimum make sure there is a litteral d in the dice string if ($t =~ /\d?d\d/i) { return $t; } else { return 0; } }