Pig the dice game
You are encouraged to solve this task according to the task description, using any language you may know.
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
- 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.
- 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.
- Task goal
The goal of this task is to create a program to score for and simulate dice throws for a two-person game.
- Reference
- Cf
D
<lang d>import std.stdio, std.string, std.algorithm, std.random;
void main() {
enum maxScore = 100; enum playerCount = 2; immutable confirmations = ["yes", "y", ""];
int[playerCount] safeScore; int player, score;
while (true) { writef(" Player %d: (%d, %d). Rolling? (y/n) ", player, safeScore[player], score); if (safeScore[player] + score < maxScore && confirmations.canFind(readln().strip().toLower())) { immutable int rolled = uniform(1, 7); writefln(" Rolled %d", rolled); if (rolled == 1) { writefln(" Bust! You lose %d but keep %d\n", score, safeScore[player]); } else { score += rolled; continue; } } else { safeScore[player] += score; if (safeScore[player] >= maxScore) break; writefln(" Sticking with %d\n", safeScore[player]); }
score = 0; player = (player + 1) % playerCount; }
writefln("\n\nPlayer %d wins with a score of %d", player, safeScore[player]);
}</lang>
- Output:
Player 0: (0, 0). Rolling? (y/n) Rolled 6 Player 0: (0, 6). Rolling? (y/n) Rolled 5 Player 0: (0, 11). Rolling? (y/n) Rolled 1 Bust! you lose 11 but still keep your previous 0 Player 1: (0, 0). Rolling? (y/n) Rolled 3 Player 1: (0, 3). Rolling? (y/n) Rolled 4 Player 1: (0, 7). Rolling? (y/n) Rolled 6 Player 1: (0, 13). Rolling? (y/n) n Sticking with 13 ... Player 0: (78, 10). Rolling? (y/n) n Sticking with 88 Player 1: (63, 0). Rolling? (y/n) Rolled 6 Player 1: (63, 6). Rolling? (y/n) Rolled 1 Bust! you lose 6 but still keep your previous 63 Player 0: (88, 0). Rolling? (y/n) n Sticking with 88 Player 1: (63, 0). Rolling? (y/n) n Sticking with 63 Player 0: (88, 0). Rolling? (y/n) Rolled 6 Player 0: (88, 6). Rolling? (y/n) Rolled 4 Player 0: (88, 10). Rolling? (y/n) Rolled 3 Player 0: (88, 13). Rolling? (y/n) n Player 0 wins with a score of 101
Go
This version includes a couple of different strategies and can pit one against the other to see which one comes out ahead more often.
<lang go> package main
import (
"fmt" "math/rand" "time"
)
// Set up random number generator. func init() {
rand.Seed(time.Now().Unix()) time.Sleep(time.Duration(rand.Intn(3)+1) * time.Second)
}
type PigGameData struct {
Player int TurnCount int TurnRollCount int TurnScore int Scores [2]int Printing bool
}
// Run the simulation. func main() {
pg := new(PigGameData) pg.Printing = true strategies := [2](func(*PigGameData) bool){scoreChaseStrat, rollCountStrat} for !pg.IsGameOver() { pg.Play(strategies[pg.Player]) } fmt.Printf("game over after %d turns\n player 1 %d\n player 2 %d\n", pg.TurnCount, pg.GetPlayerScore(0), pg.GetPlayerScore(1))
}
func (pg *PigGameData) Play(hs (func(*PigGameData) bool)) (keepPlaying bool) {
if pg.IsGameOver() { pg.Print(fmt.Sprintf("game is over after %d turns", pg.TurnCount)) return false }
if pg.TurnCount == 0 { pg.Player = 1 pg.NextPlayer() }
roll := rand.Intn(6) + 1 pg.Print(fmt.Sprintf(" rolls %d", roll)) pg.TurnRollCount++ if roll == 1 { pg.Print(fmt.Sprintf(" pigged out after %d roll%s", pg.TurnRollCount, plural(pg.TurnRollCount))) pg.NextPlayer() } else { pg.TurnScore += roll pg.Print(fmt.Sprintf(" %d point%s pending", pg.TurnScore, plural(pg.TurnScore))) if hs(pg) { pg.Hold() pg.NextPlayer() } } return true
}
func (pg *PigGameData) Init() {
pg.Player = 0 pg.TurnCount = 0 pg.TurnRollCount = 0 pg.TurnScore = 0 pg.Scores = [2]int{0, 0} pg.Printing = false
}
func (pg *PigGameData) Print(msg string) {
if pg.Printing { fmt.Println(msg) }
}
func (pg *PigGameData) GetPlayerScore(player int) int {
if player == -1 { player = pg.Player } return pg.Scores[player]
}
func (pg *PigGameData) IsGameOver() bool {
return pg.Scores[0] >= 100 || pg.Scores[1] >= 100
}
func (pg *PigGameData) Winner() int {
for i, s := range pg.Scores { if s >= 100 { return i } } return -1
}
func (pg *PigGameData) Hold() {
pg.Scores[pg.Player] += pg.TurnScore pg.Print(fmt.Sprintf(" holds after %d turns, adding %d points for a total of %d", pg.TurnRollCount, pg.TurnScore, pg.GetPlayerScore(-1))) pg.TurnRollCount = 0 pg.TurnScore = 0
}
func (pg *PigGameData) NextPlayer() {
pg.TurnCount++ pg.TurnRollCount = 0 pg.Player = (pg.Player + 1) % 2 pg.Print(fmt.Sprintf("player %d's turn:", pg.Player+1))
}
func rollCountStrat(pg *PigGameData) bool {
//fmt.Printf(" roll %d of 3\n", pg.TurnRollCount) return pg.TurnRollCount >= 3
}
func scoreChaseStrat(pg *PigGameData) bool {
myNumber, hisNumber := pg.Player, (pg.Player+1)%2 myScore, hisScore := pg.GetPlayerScore(myNumber), pg.GetPlayerScore(hisNumber) myPendingScore := pg.TurnScore + myScore //fmt.Printf(" %d vs %d\n", myPendingScore, hisScore) return myPendingScore >= 100 || myPendingScore > hisScore || pg.TurnRollCount >= 5
}
func plural(n int) string {
if n != 1 { return "s" } return ""
} </lang>
J
<lang j>require'misc'
status=:3 :0
'pid cur tot'=. y player=. 'player ',":pid potential=. ' potential: ',":cur total=. ' total: ',":tot smoutput player,potential,total
)
getmove=:3 :0
whilst.1~:+/choice do. choice=.'HRQ' e. prompt ' Roll the dice or Hold or Quit? [R or H or Q]: ' end. choice#'HRQ'
)
NB. simulate an y player game of pig pigsim=:3 :0
smoutput (":y),' player game of pig' scores=.y#0 while.100>>./scores do. for_player.=i.y do. pid=.1+I.player smoutput 'begining of turn for player ',":pid current=. 0 whilst. (1 ~: roll) *. 'R' = move do. status pid, current, player+/ .*scores move=. getmove roll=. 1+?6 if.'R'=move do. smoutput 'rolled a ',":roll current=. (1~:roll)*current+roll end. end. scores=. scores+(current*player)+100*('Q'e.move)*-.player smoutput 'player scores now: ',":scores end. end. smoutput 'player ',(":1+I.scores>:100),' wins'
)</lang>
Example game:
<lang> pigsim 2 2 player game of pig begining of turn for player 1 player 1 potential: 0 total: 0
Roll the dice or Hold or Quit? [R or H or Q]: R
rolled a 3 player 1 potential: 3 total: 0
Roll the dice or Hold or Quit? [R or H or Q]: R
rolled a 6 player 1 potential: 9 total: 0
Roll the dice or Hold or Quit? [R or H or Q]: R
rolled a 4 player 1 potential: 13 total: 0
Roll the dice or Hold or Quit? [R or H or Q]: R
rolled a 6 player 1 potential: 19 total: 0
Roll the dice or Hold or Quit? [R or H or Q]: R
rolled a 2 player 1 potential: 21 total: 0
Roll the dice or Hold or Quit? [R or H or Q]: H
player scores now: 21 0 begining of turn for player 2 player 2 potential: 0 total: 0
Roll the dice or Hold or Quit? [R or H or Q]: R
rolled a 3 player 2 potential: 3 total: 0
Roll the dice or Hold or Quit? [R or H or Q]: R
rolled a 6 player 2 potential: 9 total: 0
Roll the dice or Hold or Quit? [R or H or Q]: R
rolled a 4 player 2 potential: 13 total: 0
Roll the dice or Hold or Quit? [R or H or Q]: R
rolled a 6 player 2 potential: 19 total: 0
Roll the dice or Hold or Quit? [R or H or Q]: R
rolled a 3 player 2 potential: 22 total: 0
Roll the dice or Hold or Quit? [R or H or Q]: H
player scores now: 21 22 begining of turn for player 1 player 1 potential: 0 total: 21
Roll the dice or Hold or Quit? [R or H or Q]: R
...
Roll the dice or Hold or Quit? [R or H or Q]: R
rolled a 6 player 1 potential: 22 total: 62
Roll the dice or Hold or Quit? [R or H or Q]: H
player scores now: 84 90 begining of turn for player 2 player 2 potential: 0 total: 90
Roll the dice or Hold or Quit? [R or H or Q]: R
rolled a 6 player 2 potential: 6 total: 90
Roll the dice or Hold or Quit? [R or H or Q]: R
rolled a 6 player 2 potential: 12 total: 90
Roll the dice or Hold or Quit? [R or H or Q]: H
player scores now: 84 102 player 2 wins</lang>
Java
<lang java>import java.util.*;
public class PigDice {
public static void main(String[] args) { final int maxScore = 100; final int playerCount = 2; int[] safeScore = new int[2]; int player = 0, score = 0;
Scanner sc = new Scanner(System.in); String[] yesses = {"yes", "y", ""}; Random rnd = new Random();
while (true) { System.out.printf(" Player %d: (%d, %d) Rolling? (Yn) ", player, safeScore[player], score); String ln = sc.nextLine(); if (Arrays.asList(yesses).contains(ln.trim().toLowerCase())) { int rolled = rnd.nextInt(6) + 1; System.out.printf(" Rolled %d\n", rolled); if (rolled == 1) { System.out.printf(" Bust! You lose %d but keep %d\n\n", score, safeScore[player]); } else { score += rolled; continue; } } else { safeScore[player] += score; if (safeScore[player] >= maxScore) break; System.out.printf(" Sticking with %d\n\n", safeScore[player]); } score = 0; player = (player + 1) % playerCount; } System.out.printf("\nPlayer %d wins with a score of %d", player, safeScore[player]); }
}</lang>
Player 0: (0, 0) Rolling? (Yn) Rolled 3 Player 0: (0, 3) Rolling? (Yn) Rolled 5 Player 0: (0, 8) Rolling? (Yn) Rolled 2 Player 0: (0, 10) Rolling? (Yn) n Sticking with 10 Player 1: (0, 0) Rolling? (Yn) Rolled 1 Bust! You lose 0 but keep 0 Player 0: (10, 0) Rolling? (Yn) Rolled 1 Bust! You lose 0 but keep 10 Player 1: (0, 0) Rolling? (Yn) Rolled 4 Player 1: (0, 4) Rolling? (Yn) Rolled 5 Player 1: (0, 9) Rolling? (Yn) Rolled 1 Bust! You lose 9 but keep 0 (...) Player 1: (96, 0) Rolling? (Yn) Rolled 4 Player 1: (96, 4) Rolling? (Yn) y Rolled 2 Player 1: (96, 6) Rolling? (Yn) n Player 1 wins with a score of 102
Perl 6
<lang perl6>constant DIE = 1..6;
sub MAIN (Int :$players = 2, Int :$goal = 100) {
my @safe = 0 xx $players; for ^$players xx * -> $player {
say "\nOK, player #$player is up now."; my $safe = @safe[$player]; my $ante = 0; until $safe + $ante >= $goal or prompt("#$player, you have $safe + $ante = {$safe+$ante}. Roll? [Yn] ") ~~ /:i ^n/ { given DIE.roll { say " You rolled a $_."; when 1 { say " Bust! You lose $ante but keep your previous $safe."; $ante = 0; last; } when 2..* { $ante += $_; } } } $safe += $ante; if $safe >= $goal { say "\nPlayer #$player wins with a score of $safe!"; last; } @safe[$player] = $safe; say " Sticking with $safe." if $ante;
}
}</lang> The game defaults to the specified task, but we'll play a shorter game with three players for our example:
- Output:
> pig help Usage: pig [--players=<Int>] [--goal=<Int>] > pig --players=3 --goal=20 OK, player #0 is up now. #0, you have 0 + 0 = 0. Roll? [Yn] You rolled a 6. #0, you have 0 + 6 = 6. Roll? [Yn] You rolled a 6. #0, you have 0 + 12 = 12. Roll? [Yn] n Sticking with 12. OK, player #1 is up now. #1, you have 0 + 0 = 0. Roll? [Yn] You rolled a 4. #1, you have 0 + 4 = 4. Roll? [Yn] You rolled a 6. #1, you have 0 + 10 = 10. Roll? [Yn] You rolled a 6. #1, you have 0 + 16 = 16. Roll? [Yn] n Sticking with 16. OK, player #2 is up now. #2, you have 0 + 0 = 0. Roll? [Yn] You rolled a 5. #2, you have 0 + 5 = 5. Roll? [Yn] You rolled a 1. Bust! You lose 5 but keep your previous 0. OK, player #0 is up now. #0, you have 12 + 0 = 12. Roll? [Yn] You rolled a 1. Bust! You lose 0 but keep your previous 12. OK, player #1 is up now. #1, you have 16 + 0 = 16. Roll? [Yn] n OK, player #2 is up now. #2, you have 0 + 0 = 0. Roll? [Yn] You rolled a 6. #2, you have 0 + 6 = 6. Roll? [Yn] You rolled a 6. #2, you have 0 + 12 = 12. Roll? [Yn] You rolled a 4. #2, you have 0 + 16 = 16. Roll? [Yn] You rolled a 6. Player #2 wins with a score of 22!
PHP
<lang php>error_reporting(E_ALL & ~ ( E_NOTICE | E_WARNING ));
define('MAXSCORE', 100); define('PLAYERCOUNT', 2);
$confirm = array('yes', 'y', );
while (true) {
printf(' Player %d: (%d, %d) Rolling? (Yn) ', $player, $safeScore[$player], $score); if ($safeScore[$player] + $score < MAXSCORE && in_array(strtolower(trim(fgets(STDIN))), $confirm)) { $rolled = rand(1, 6); echo " Rolled $rolled \n"; if ($rolled == 1) { printf(' Bust! You lose %d but keep %d \n\n', $score, $safeScore[$player]); } else { $score += $rolled; continue; } } else { $safeScore[$player] += $score; if ($safeScore[$player] >= MAXSCORE) break; echo ' Sticking with ', $safeScore[$player], '\n\n'; } $score = 0; $player = ($player + 1) % PLAYERCOUNT;
} printf('\n\nPlayer %d wins with a score of %d ',
$player, $safeScore[$player]);
</lang>
C:\UniServer\usr\local\php\php pig.php Player 0: (0, 0) Rolling? (Yn) Rolled 2 Player 0: (0, 2) Rolling? (Yn) Rolled 1 Bust! You lose 2 but keep 0 Player 1: (0, 0) Rolling? (Yn) Rolled 2 Player 1: (0, 2) Rolling? (Yn) Rolled 1 Bust! You lose 2 but keep 0 Player 0: (0, 0) Rolling? (Yn) Rolled 3 Player 0: (0, 3) Rolling? (Yn) Rolled 6 Player 0: (0, 9) Rolling? (Yn) n sticking with 9 Player 1: (0, 0) Rolling? (Yn) Rolled 5 Player 1: (0, 5) Rolling? (Yn) Rolled 3 Player 1: (0, 8) Rolling? (Yn) n sticking with 8 (...) Player 1: (93, 0) Rolling? (Yn) Rolled 5 Player 1: (93, 5) Rolling? (Yn) Rolled 3 Player 1: (93, 8) Rolling? (Yn) Player 1 wins with a score of 101
Python
<lang python>#!/usr/bin/python3
See: http://en.wikipedia.org/wiki/Pig_(dice)
This program scores and throws the dice for a two player game of Pig
from random import randint
playercount = 2 maxscore = 100 safescore = [0] * playercount player = 0 score=0
while max(safescore) < maxscore:
rolling = input("Player %i: (%i, %i) Rolling? (Y) " % (player, safescore[player], score)).strip().lower() in {'yes', 'y', } if rolling: rolled = randint(1, 6) print(' Rolled %i' % rolled) if rolled == 1: print(' Bust! you lose %i but still keep your previous %i' % (score, safescore[player])) score, player = 0, (player + 1) % playercount else: score += rolled else: safescore[player] += score if safescore[player] >= maxscore: break print(' Sticking with %i' % safescore[player]) score, player = 0, (player + 1) % playercount
print('\nPlayer %i wins with a score of %i' %(player, safescore[player]))</lang>
- Samples from a game
Player 0: (0, 0) Rolling? (Y) Rolled 6 Player 0: (0, 6) Rolling? (Y) Rolled 5 Player 0: (0, 11) Rolling? (Y) Rolled 1 Bust! you lose 11 but still keep your previous 0 Player 1: (0, 0) Rolling? (Y) Rolled 3 Player 1: (0, 3) Rolling? (Y) Rolled 4 Player 1: (0, 7) Rolling? (Y) Rolled 6 Player 1: (0, 13) Rolling? (Y) n Sticking with 13 ... Player 0: (78, 10) Rolling? (Y) n Sticking with 88 Player 1: (63, 0) Rolling? (Y) Rolled 6 Player 1: (63, 6) Rolling? (Y) Rolled 1 Bust! you lose 6 but still keep your previous 63 Player 0: (88, 0) Rolling? (Y) n Sticking with 88 Player 1: (63, 0) Rolling? (Y) n Sticking with 63 Player 0: (88, 0) Rolling? (Y) Rolled 6 Player 0: (88, 6) Rolling? (Y) Rolled 4 Player 0: (88, 10) Rolling? (Y) Rolled 3 Player 0: (88, 13) Rolling? (Y) n Player 0 wins with a score of 101
XPL0
<lang XPL0>include c:\cxpl\codes; \intrinsic 'code' declarations integer Player, Die, Points, Score(2); [Score(0):= 0; Score(1):= 0; \starting scores for each player Player:= 1; \second player repeat Player:= if Player = 1 then 0 else 1; \next player
Points:= 0; \points for current turn loop [Text(0, "Player "); IntOut(0, Player+1); Text(0, " is up. Roll or hold (r/h)? "); OpenI(0); \discard any chars in keyboard buffer (like CR) if ChIn(0) = ^h then quit \default is 'r' to roll else [Die:= Ran(6)+1; \roll the die Text(0, "You get "); IntOut(0, Die); CrLf(0); if Die = 1 then [Points:= 0; quit]; Points:= Points + Die; \add up points for turn Text(0, "Total points are "); IntOut(0, Points); Text(0, " for a tentative score of "); IntOut(0, Score(Player)+Points); CrLf(0); ]; ]; Score(Player):= Score(Player) + Points; \show scores Text(0, "Player 1 has "); IntOut(0, Score(0)); Text(0, " and player 2 has "); IntOut(0, Score(1)); CrLf(0);
until Score(Player) >= 100; Text(0, "Player "); IntOut(0, Player+1); Text(0, " WINS!!!"); ]</lang>
Output:
Player 1 is up. Roll or hold (r/h)? r You get 5 Total points are 5 for a tentative score of 5 Player 1 is up. Roll or hold (r/h)? r You get 6 Total points are 11 for a tentative score of 11 Player 1 is up. Roll or hold (r/h)? r You get 6 Total points are 17 for a tentative score of 17 Player 1 is up. Roll or hold (r/h)? r You get 6 Total points are 23 for a tentative score of 23 Player 1 is up. Roll or hold (r/h)? h Player 1 has 23 and player 2 has 0 Player 2 is up. Roll or hold (r/h)? r You get 2 Total points are 2 for a tentative score of 2 Player 2 is up. Roll or hold (r/h)? r You get 6 Total points are 8 for a tentative score of 8 Player 2 is up. Roll or hold (r/h)? r You get 1 Player 1 has 23 and player 2 has 0 ... Player 1 has 94 and player 2 has 57 Player 1 is up. Roll or hold (r/h)? r You get 6 Total points are 6 for a tentative score of 100 Player 1 is up. Roll or hold (r/h)? h Player 1 has 100 and player 2 has 57 Player 1 WINS!!!