Stories
Slash Boxes
Comments

All the Perl that's Practical to Extract and Report

use Perl Log In

Log In

[ Create a new account ]

Sunday September 10, 2006
12:21 PM

Bar bets and Games::Dice::Advanced

[ #30954 ]

Going through some old papers yesterday, I found a statistics problem I had to prove:

This bar game uses three standard six-sided dice. The player rolls all three dice at once. If he rolls three 4s, the bar pays him $3. If he rolls two 4s, the bar pays him $2. If he rolls a single 4, the bar pays him $1. If he rolls no 4s, he pays the bar $1.

Prove that the average loss per roll is about 7 cents for a large number of rolls.

I had done all the math and so on, but I wanted to write a little simulation. The Games::Dice::Advanced can handle all sorts of die things.

#!/usr/bin/perl
 
use Games::Dice::Advanced;
 
my $total = 0;
 
my $iterations = $ARGV[0] || 100_000;
 
print "Roll  | Dice  | Win    Total    Win/Roll \n" .
      "------|-------|---------------------------\n";
 
foreach ( 1 .. $iterations )
    {
    my @n = map { Games::Dice::Advanced->roll() } 1 .. 3;
 
    my( $change ) = pay_up( \@n );
 
    $total += $change;
 
    printf "%5d | %d %d %d |  %2d   %5d     % 5.3f\n",
        $_,
        @n, $change, $total, $total / $_
            if $_ % ( $iterations / 10 ) == 0;
    }
 
sub pay_up
    {
    my $count = grep { $_ == 4 } @{ $_[0] };
 
    # return the payout based on the number of rolled 4s
    if(    $count == 3 ) {  3 }
    elsif( $count == 2 ) {  2 }
    elsif( $count == 1 ) {  1 }
    else                 { -1 }
    }

The "large number of rolls" tends to be pretty large. If you want to stick around a bar to roll dicce 4,000 times, you probably deserve to lose all of your money. Remember, you lose seven cents per roll.

Roll  | Dice  | Win    Total    Win/Roll
------|-------|---------------------------
  1000 | 1 1 2 |  -1       9      0.009
  2000 | 1 4 1 |   1     -74     -0.037
  3000 | 3 5 6 |  -1    -132     -0.044
  4000 | 1 3 6 |  -1    -251     -0.063
  5000 | 2 2 4 |   1    -345     -0.069
  6000 | 5 2 1 |  -1    -433     -0.072
  7000 | 2 2 3 |  -1    -463     -0.066
  8000 | 1 2 3 |  -1    -584     -0.073
  9000 | 1 2 2 |  -1    -618     -0.069
10000 | 4 2 3 |   1    -761     -0.076

I figured that if I was going to play this at any Perl Mongers meeting I was likely to run into unusual dice, so I wanted to see how much I'd get out of people using twenty sided dice.

use Games::Dice::Advanced;
 
my $total      = 0;
my $sides      = $ARGV[0] || 6;
my $iterations = $ARGV[1] || 100_00;
 
print "Roll  | Dice     | Win    Total    Win/Roll \n" .
      "------|----------|---------------------------\n";
 
foreach ( 1 .. $iterations )
    {
    my @n = map { Games::Dice::Advanced->roll( "d$sides" ) } 1 .. 3;
 
    my( $change ) = pay_up( \@n );
 
    $total += $change;
 
    printf "%5d | %2d %2d %2d |  %2d   %5d     % 5.3f\n",
        $_,
        @n, $change, $total, $total / $_
            if $_ % ( $iterations / 10 ) == 0;
    }
    }

Doing this, I discovered a bug in Games::Dice::Advanced. There's a closing paren in the wrong place such that die with more than nine sides don't work correctly:

--- Advanced.pm 2006-09-10 10:45:33.000000000 -0500
+++ Advanced.pm-new     2006-09-10 10:46:51.000000000 -0500
@@ -132,7 +132,7 @@
            if($recipe !~ /\D/) {                       # constant
                # $self = eval("sub { $recipe * $mul }");
                $self = sub { $recipe * $mul };
-           } elsif($recipe =~ /^d(\d)+$/) {            # dINT
+           } elsif($recipe =~ /^d(\d+)$/) {            # dINT
             # $self = eval("sub { (1 + int(rand($1))) * $mul }");
             my $faces = $1;
             $self = sub { (1 + int(rand($faces))) * $mul };

With the little change, I figure I'd win about 75 cents per throw. Of course, if I do this with the London Perl Mongers, I'd win even more because of the exchange rate (they'd have to play with pounds).

The Fine Print: The following comments are owned by whoever posted them. We are not responsible for them in any way.
 Full
 Abbreviated
 Hidden
More | Login | Reply
Loading... please wait.
  • Any old-time D&D gamer will have some 4-sided dice to use, if you're allowing non-standard dice. You'll be losing money to them.
  • Games::Dice::Advanced supports loaded dice too, so you're doomed if you play against a perl programmer.

    And thanks for the patch - version 1.1 is on its way to the CPAN as we speak.