user
Task

Create a dice simulator and scorer of Pig the dice game and add to it the ability to play the game to at least one strategy.

* State here the play strategies involved.
* Show play during a game here.

As a stretch goal:

* Simulate playing the game a number of times with two players of given strategies and report here summary statistics such as, but not restricted to, the influence of going first or which strategy seems stronger.

Game Rules

The game of Pig is a multiplayer game played with a single six-sided die. The
object of the game is to reach 100 points or more.
Play is taken in turns. On each person's turn that person has the option of either

1. **Rolling the dice**: where a roll of two to six is added to their score for that turn and the player's turn continues as the player is given the same choice again; or a roll of 1 loses the player's total points *for that turn* and their turn finishes with play passing to the next player.
2. **Holding**: The player's score for that round is added to their total and becomes safe from the effects of throwing a one. The player's turn finishes with play passing to the next player.

References

* Pig (dice)
* The Math of Being a Pig and Pigs (extra) - Numberphile videos featuring Ben Sparks.
assistant
(formerly Perl 6)

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:

```
 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**

```
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


```