RosettaCodeData/Task/Pig-the-dice-game-Player/Python/pig-the-dice-game-player.py
Ingy döt Net b83f433714 tasks a-s
2013-04-10 23:57:08 -07:00

127 lines
4.6 KiB
Python

#!/usr/bin/python3
'''
See: http://en.wikipedia.org/wiki/Pig_(dice)
This program scores, throws the dice, and plays for an N player game of Pig.
'''
from random import randint
from collections import namedtuple
import random
from pprint import pprint as pp
from collections import Counter
playercount = 2
maxscore = 100
maxgames = 100000
Game = namedtuple('Game', 'players, maxscore, rounds')
Round = namedtuple('Round', 'who, start, scores, safe')
class Player():
def __init__(self, player_index):
self.player_index = player_index
def __repr__(self):
return '%s(%i)' % (self.__class__.__name__, self.player_index)
def __call__(self, safescore, scores, game):
'Returns boolean True to roll again'
pass
class RandPlay(Player):
def __call__(self, safe, scores, game):
'Returns random boolean choice of whether to roll again'
return bool(random.randint(0, 1))
class RollTo20(Player):
def __call__(self, safe, scores, game):
'Roll again if this rounds score < 20'
return (((sum(scores) + safe[self.player_index]) < maxscore) # Haven't won yet
and(sum(scores) < 20)) # Not at 20 this round
class Desparat(Player):
def __call__(self, safe, scores, game):
'Roll again if this rounds score < 20 or someone is within 20 of winning'
return (((sum(scores) + safe[self.player_index]) < maxscore) # Haven't won yet
and( (sum(scores) < 20) # Not at 20 this round
or max(safe) >= (maxscore - 20))) # Someone's close
def game__str__(self):
'Pretty printer for Game class'
return ("Game(players=%r, maxscore=%i,\n rounds=[\n %s\n ])"
% (self.players, self.maxscore,
',\n '.join(repr(round) for round in self.rounds)))
Game.__str__ = game__str__
def winningorder(players, safescores):
'Return (players in winning order, their scores)'
return tuple(zip(*sorted(zip(players, safescores),
key=lambda x: x[1], reverse=True)))
def playpig(game):
'''
Plays the game of pig returning the players in winning order
and their scores whilst updating argument game with the details of play.
'''
players, maxscore, rounds = game
playercount = len(players)
safescore = [0] * playercount # Safe scores for each player
player = 0 # Who plays this round
scores=[] # Individual scores this round
while max(safescore) < maxscore:
startscore = safescore[player]
rolling = players[player](safescore, scores, game)
if rolling:
rolled = randint(1, 6)
scores.append(rolled)
if rolled == 1:
# Bust!
round = Round(who=players[player],
start=startscore,
scores=scores,
safe=safescore[player])
rounds.append(round)
scores, player = [], (player + 1) % playercount
else:
# Stick
safescore[player] += sum(scores)
round = Round(who=players[player],
start=startscore,
scores=scores,
safe=safescore[player])
rounds.append(round)
if safescore[player] >= maxscore:
break
scores, player = [], (player + 1) % playercount
# return players in winning order and all scores
return winningorder(players, safescore)
if __name__ == '__main__':
game = Game(players=tuple(RandPlay(i) for i in range(playercount)),
maxscore=20,
rounds=[])
print('ONE GAME')
print('Winning order: %r; Respective scores: %r\n' % playpig(game))
print(game)
game = Game(players=tuple(RandPlay(i) for i in range(playercount)),
maxscore=maxscore,
rounds=[])
algos = (RollTo20, RandPlay, Desparat)
print('\n\nMULTIPLE STATISTICS using %r\n for %i GAMES'
% (', '.join(p.__name__ for p in algos), maxgames,))
winners = Counter(repr(playpig(game._replace(players=tuple(random.choice(algos)(i)
for i in range(playercount)),
rounds=[]))[0])
for i in range(maxgames))
print(' Players(position) winning on left; occurrences on right:\n %s'
% ',\n '.join(str(w) for w in winners.most_common()))