"""Casino game simulator and analysis	The Simulator uses a set of player strategies, and a game which uses the player strategy.  		It loads results into an analyzer, which can be used to produce final reports."""from simlog import *;from casino import *;import math;import string;import sys;import time;def sum( aList ):	return reduce( lambda x,y:x+y, aList, 0.0 );def sq( aList ):	return map( lambda x:x*x, aList );def stddev( aList ):	n= len(aList);	return math.sqrt((n*sum(sq(aList))-sum(aList)**2)/(n*(n-1)));class Simulator:	"the simulation of a specific game with a variety of player strategies"	def __init__( self, players, game, analyzer ):		self.log= Simlog().instance();		self.analyzer= analyzer;		self.players= players;		self.game= game;		self.maxRounds= 0;		self.player= None;		self.duration= 0;		self.work= 0;	def oneRound( self ):		"run the game table for a single round of play"		self.game.play();		self.work += 1;	def runSession( self ):		"run the game table for a player's session - max rounds or out of money"		self.player.start( self.maxRounds );		round= 0;		while( self.player.canPlay() ):			round += 1;			self.log.msg( "sim.round", "round %d, stake %d" % (round,self.player.stake) );			self.oneRound();		self.log.msg( "sim.final", "final %d" % (self.player.stake) );	def sample( self, games, player ):		"collect statistics for a number of samples of a given player"		self.player= player;		self.game.seatPlayer( self.player );		final= [];		minStake= [];		maxStake= [];		for i in range(0,games):			self.runSession();			final.append( self.player.finalNet() );			minStake.append( self.player.minNet() );			maxStake.append( self.player.maxNet() );		self.analyzer.outcome( ( final, minStake, maxStake, self.player.name() ) );	def generate( self, games, rounds= 100 ):		"generate a database of stats for a number of players"		startTime= time.clock();		self.maxRounds= rounds;		for p in self.players:			self.sample( games, p );		self.duration= time.clock() - startTime;	def performance( self ):		"games per second"		return self.work / self.duration;		class Statistic:	"simple aggregate statistic"	def __init__( self ):		self.dataset= {};	def value( self, sample, value ):		self.dataset[sample]= value;	def report( self, samples ):		r= []		for s in samples:			r.append( "%0.2f" % (self.dataset.get(s,0)) );		return string.join( r, "\t" );class Distribution( Statistic ):	"distribution statstic"	def __init__( self ):		Statistic.__init__( self );		self.low= 0;		self.high= 0;	def value( self, sample, value ):		buckets= map( lambda(x):int(x/10), value );		freq = {};		for i in buckets: freq[i] = freq.get(i,0) + 1;		self.low= min( self.low, min(freq.keys()) );		self.high= max( self.high, max(freq.keys()) );		Statistic.value( self, sample, freq );	def report( self, samples ):		r= []		for s in samples:			v= [];			for i in range( min(self.dataset[s].keys()), max(self.dataset[s].keys())+1 ):				v.append( "%d-%d:%d" % (i*10, i*10+9, self.dataset[s].get(i,0)) );			r.append( string.join( v, ", " ) );		return string.join( r, "\t" );	def reportCell( self, index, samples ):		l= [ "%4d - %4d" % (index*10, index*10+9 ) ];		for s in samples:			l.append( "%d" % (self.dataset[s].get(index,0)) );		return string.join( l, "\t" );class Analyzer:	"analyze the results of a casino game simulation"	def __init__( self ):		self.rawdata= [];		self.data = {			"avg final":Statistic(),			"sdv final":Statistic(),			"min final":Statistic(),			"max final":Statistic(),			"avg minimum":Statistic(),			"min minimum":Statistic(),			"avg maximum":Statistic(),			"max maximum":Statistic(),			"dist final":Distribution(),			"dist minimum":Distribution()		};		self.outcomes= [];	def outcome( self, outMinMaxDoc ):		"log an outcome by a particular player"		self.rawdata.append( outMinMaxDoc );		(final, minStake, maxStake, doc)= outMinMaxDoc;		self.outcomes.append( doc );		n= len(final);		self.data["avg final"].value( doc, sum(final)/n );		if( n > 1 ): self.data["sdv final"].value( doc, stddev(final) );		self.data["min final"].value( doc, min(final) );		self.data["max final"].value( doc, max(final) );		self.data["avg minimum"].value( doc, sum(minStake)/len(minStake) );		self.data["min minimum"].value( doc, min(minStake) );		self.data["avg maximum"].value( doc, sum(maxStake)/len(maxStake) );		self.data["max maximum"].value( doc, max(maxStake) );		self.data["dist final"].value( doc, final );		self.data["dist minimum"].value( doc, minStake );	def report( self, file= sys.stdout ):		"create a report of all logged player outcomes"		file.writelines( "statistic\t" + string.join( self.outcomes, "\t" ), "\n" );		for d in ["avg final","sdv final","min final","max final","avg minimum",			"min minimum","avg maximum","max maximum"]:			file.writelines(  d + "\t" + self.data[d].report( self.outcomes ), "\n" );		for d in ["dist final","dist minimum"]:			file.writelines(  d, "\n" );			for b in range( self.data[d].low, self.data[d].high+1 ):				file.writelines(  self.data[d].reportCell( b, self.outcomes ), "\n" );def testSim():	Simlog().instance().detail();	n= 5;		a= Analyzer();	s= Simulator( PlayerFactory().playerSet( ["simple"] ), CasinoGame(), a );	s.generate( n, 100 );	a.report();if( __name__ == "__main__" ):	testSim();