Stories
Slash Boxes
Comments
NOTE: use Perl; is on undef hiatus. You can read content, but you can't post it. More info will be forthcoming forthcomingly.

All the Perl that's Practical to Extract and Report

use Perl Log In

Log In

[ Create a new account ]

Sunday September 10, 2006
11:21 AM

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.