Skip to content

Instantly share code, notes, and snippets.

@mjdominus
Created October 14, 2017 15:29
Show Gist options
  • Select an option

  • Save mjdominus/ac2c3c36c50d7ae97b0f06bf94346061 to your computer and use it in GitHub Desktop.

Select an option

Save mjdominus/ac2c3c36c50d7ae97b0f06bf94346061 to your computer and use it in GitHub Desktop.

Revisions

  1. mjdominus created this gist Oct 14, 2017.
    126 changes: 126 additions & 0 deletions dice
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,126 @@
    #!/usr/bin/perl
    #
    # 14 October 2017
    # Author: Mark Jason Dominus
    #
    # This program is in the public domain.
    # You may use, modify, copy, or distribute it
    # in any way for any purpose, without restriction.
    #

    use strict 'vars';

    my $G = [1,1,1,1,1,1]; # equidistributed 0-5
    my $R = [0,1,1,1,1,1,1]; # equidistributed 1-6
    my $S1 = [0,1,2,2,1]; # Sicherman A
    my $S2 = [0,1,0,1,1,1,1,0,1]; # Sicherman B

    my %dname = (R => $R, G => $G,
    S1 => $S1, S2 => $S2,
    '2R' => add2($R, $R),
    'RG' => add2($R, $G),
    '2G' => add2($G, $G),
    'S' => add2($S1, $S2), # not better or worse than 2R
    );

    my ($d1, $d2) = @ARGV;
    defined($d2) or die "Usage: dice D1 D2\n\t(or: dice test D1)\n";

    if ($d1 eq "test") {
    exists($dname{$d2}) or die "Unknown die '$d2'\n";
    test($dname{$d2});
    exit;
    }

    exists($dname{$_}) or die "Unknown die '$_'\n" for $d1, $d2;
    play(@dname{$d1, $d2});

    # dump out statistics for one die
    # including a random trial of 10,000 rolls
    sub test {
    my ($d) = @_;
    print "@$d\n";
    my %count;
    for (1 .. 10_000) {
    $count{roll($d)}++;
    }
    for my $k (sort { $a <=> $b } keys %count) {
    next unless $count{$k} > 0;
    printf "%3d %4d\n", $k, $count{$k};
    }
    }

    # Match one die against another,
    # print out who wins in the following format:
    # > dice G R
    # p1 10 27.8% 32.3%
    # p2 21 58.3 67.7
    # tie 5 13.9 16.1
    # 36
    #
    # player 1 (G) wins 10 times out of 36, which is 27.8%
    # player 2 (R) wins 21 times out of 36, which is 58.3%
    # the two players tie 5 times out of 36, which is 13.9%
    #
    # The right-hand column is the probabilities if ties are
    # do-overs: player 1 wins 32.3% of the time,
    # player 2 wins 67.7% of the time.
    #
    # The number in the lower right is not very meaningful.
    b# It is the fraction of do-overs as compared to decisive results.

    sub play {
    my ($d1, $d2) = @_;
    my %count;
    my $total = 0;
    my $decisive = 0;
    for my $i (0 .. $#$d1) {
    for my $j (0 .. $#$d2) {
    my ($r1, $r2) = ($d1->[$i], $d2->[$j]);
    my $outcome =
    $i > $j ? "p1"
    : $i < $j ? "p2" : "tie";
    $count{$outcome} += $r1 * $r2;
    $total += $r1 * $r2;
    $decisive += $r1 * $r2 unless $outcome eq "tie";
    }
    }
    my $pct = "%";
    for my $outcome (qw(p1 p2 tie)) {
    my $count = $count{$outcome};
    printf "%-4s %3d %4.1f%1s %4.1f%1s\n", $outcome, $count,
    100*$count / $total, $pct, 100 *$count/$decisive, $pct;
    $pct = " ";
    }
    printf "%-4s %3d\n", "", $total, $decisive;
    }

    sub roll {
    my ($die) = @_;
    my $total = sum(@$die);
    my $rand = int(rand($total));
    my $i = 0;
    while ($rand >= $die->[$i]) {
    $rand -= $die->[$i++];
    }
    return $i;
    }

    sub sum {
    my $total = 0;
    for (@_) { $total += $_ }
    return $total;
    }

    # Add two dice together
    sub add2 {
    my $s = [];
    my ($d1, $d2) = @_;
    for my $i (0 .. $#$d1) {
    for my $j (0 .. $#$d2) {
    my ($r1, $r2) = ($d1->[$i], $d2->[$j]);
    $s->[$i+$j] += $r1*$r2;
    }
    }
    return $s;
    }