Pig the dice game/Player

This implements a pig player class where you can customize the strategy it uses. Pass a strategy code reference in that will evaluate to a Boolean value. The player will roll the die then decide whether to roll again or lock in its winnings based on its strategy. It will continue to roll until it gets a 1 (bust) or the strategy code reference evaluates to True (finished turn).

Set up as many players as you want, then run it. It will play 100 games (by default) then report the score for each game then the win totals for each player. If you want to play a different number of games, pass the number at the command line as a parameter.

Here we have 5 players:

Output:

 player 0 uses the default strategy, always roll if it can. 
 player 1 will roll up to 5 times then lock in whatever it earned.
 player 2 will try to get at least 20 points per turn.
 player 3 randomly picks whether to roll again or not biased so that there is a 90% chance that it will.
 player 4 randomly chooses to roll again but gets more consrvative as its score get closer to the goal.
my $games = @*ARGS ?? (shift @*ARGS) !! 100;

constant DIE = 1 .. 6;
constant GOAL = 100;

class player {
    has $.score    is rw = 0;
    has $.ante     is rw;
    has $.rolls    is rw;
    has &.strategy is rw = sub { False }; # default, always roll again

    method turn {
        my $done_turn = False;
        $.rolls = 0;
        $.ante  = 0;
        repeat {
            given DIE.roll {
                $.rolls++;
                when 1 {
                    $.ante = 0;
                    $done_turn = True;
                }
                when 2..* {
                    $.ante += $_;
                }
            }
            $done_turn = True if $.score + $.ante >= GOAL or (&.strategy)();
        } until $done_turn;
        $.score += $.ante;
    }
}

my @players;

# default, go-for-broke, always roll again
@players[0] = player.new;

# try to roll 5 times but no more per turn
@players[1] = player.new( strategy => sub { @players[1].rolls >= 5 } );

# try to accumulate at least 20 points per turn
@players[2] = player.new( strategy => sub { @players[2].ante > 20 } );

# random but 90% chance of rolling again
@players[3] = player.new( strategy => sub { 1.rand < .1 } );

# random but more conservative as approaches goal
@players[4] = player.new( strategy => sub { 1.rand < ( GOAL - @players[4].score ) * .6 / GOAL } );

my @wins = 0 xx @players;

for ^ $games {
    my $player = -1;
    repeat {
        $player++;
        @players[$player % @players].turn;
    } until @players[$player % @players].score >= GOAL;

    @wins[$player % @players]++;

    say join "\t", @players>>.score;
    @players[$_].score = 0 for ^@players; # reset scores for next game
}

say "\nSCORES: for $games games";
say join "\t", @wins;

Sample output for 10000 games

Output:

0       103     46      5       40
0       100     69      0       48
0       105     22      7       44
0       75      69      19      102
105     21      23      5       17
0       101     85      12      29
0       70      66      103     23
0       0       104     69      20
0       100     44      0       20
0       102     63      75      30
0       56      101     12      40
0       103     71      2       38
0       103     91      21      32
0       18      102     47      28
...
...
...
104     0       69      14      47
0       68      101     13      22
0       99      89      102     31

SCORES: for 10000 games
947     3534    3396    1714    409