""" Craps simulator; see http://thewizardofodds.com/game/craps.html for rules and analysis """"""	TODO: 	Might want to try and generalize craps model to unify Come bet state and play state.		Might want to include "buy" and "lay" bets, and the "don't pass odds" bet."""from random import *;from simlog import *;from casino import *;from simulator import *;class CrapsTable( GameTable ):	"Craps Table: Keeps all bets; some bets persist after a winning round"	def __init__( self ):		GameTable.__init__( self );		# need the "buy" and "lay" bets, and the "don't pass odds" bet.		self.bets = {			"pass line":		Bet( "pass line", { 0:(1,1) } ),			"don't pass line":	Bet( "don't pass line", { 0:(1,1) } ),			"pass line odds":	Bet( "pass line odds", {6:(6,5),8:(6,5),5:(3,2),9:(3,2),4:(2,1),10:(2,1)} ),			"craps":			Bet( "craps",  { 2:(30,1), 3:(15,1), 12:(30,1)} ),			"11":				Bet( "11",   {11:(15,1)} ),			"7":				Bet( "7",    { 7:( 4,1)} ),			"any craps":		Bet( "any craps",{ 0:( 7,1)} ),			"horn":				Bet( "horn",    { 2:(27,4),12:(27,4),3:( 3,1),11:( 3,1)} ),			"field":			Bet( "field",   { 2:( 2,1),12:( 2,1),0:( 1,1)} ),			"place 4":			Bet( "place 4", {4:(9,5),10:(9,5),5:(7,5),9:(7,5),6:(7,6),8:(7,6)} ),			"place 5":			Bet( "place 5", {4:(9,5),10:(9,5),5:(7,5),9:(7,5),6:(7,6),8:(7,6)} ),			"place 6":			Bet( "place 6", {4:(9,5),10:(9,5),5:(7,5),9:(7,5),6:(7,6),8:(7,6)} ),			"place 8":			Bet( "place 8", {4:(9,5),10:(9,5),5:(7,5),9:(7,5),6:(7,6),8:(7,6)} ),			"place 9":			Bet( "place 9", {4:(9,5),10:(9,5),5:(7,5),9:(7,5),6:(7,6),8:(7,6)} ),			"place 10":			Bet( "place 10",{4:(9,5),10:(9,5),5:(7,5),9:(7,5),6:(7,6),8:(7,6)} ),			"big 6":			Bet( "big 6",   {6:(1,1)} ),			"big 8":			Bet( "big 8",	{8:(1,1)} ),			"hard 4":			Bet( "hard 4", 	{4:(7,1)} ),			"hard 6":			Bet( "hard 6",	{6:(9,1)} ),			"hard 8":			Bet( "hard 8",	{8:(9,1)} ),			"hard 10":			Bet( "hard 10", {10:(7,1)} ),			"come":				Bet( "come",    {0:(1,1)} ),			"come 4":			Bet( "come 4",  {0:(1,1)} ),			"come 5":			Bet( "come 5",  {0:(1,1)} ),			"come 6":			Bet( "come 6",  {0:(1,1)} ),			"come 8":			Bet( "come 8",  {0:(1,1)} ),			"come 9":			Bet( "come 9",  {0:(1,1)} ),			"come 10":			Bet( "come 10", {0:(1,1)} ),			"come odds 4":		Bet( "come odds 4",  {6:(6,5),8:(6,5),5:(3,2),9:(3,2),4:(2,1),10:(2,1)} ),			"come odds 5":		Bet( "come odds 5",  {6:(6,5),8:(6,5),5:(3,2),9:(3,2),4:(2,1),10:(2,1)} ),			"come odds 6":		Bet( "come odds 6",  {6:(6,5),8:(6,5),5:(3,2),9:(3,2),4:(2,1),10:(2,1)} ),			"come odds 8":		Bet( "come odds 8",  {6:(6,5),8:(6,5),5:(3,2),9:(3,2),4:(2,1),10:(2,1)} ),			"come odds 9":		Bet( "come odds 9",  {6:(6,5),8:(6,5),5:(3,2),9:(3,2),4:(2,1),10:(2,1)} ),			"come odds 10":		Bet( "come odds 10", {6:(6,5),8:(6,5),5:(3,2),9:(3,2),4:(2,1),10:(2,1)} )			};class CrapsState:	def __init__( self, point= 0 ):		self.point= point;		self.roundOver= 1;		self.nextState= self;	def evalDice( self, game, d1, d2 ):		return self.roundOver;	def name( self ):		return "error";class CrapsStateComeOutRoll( CrapsState ):	def name( self ):		return "Come Out Roll";	def evalDice( self, game, d1, d2 ):		self.nextState= None;		craps= 0;		r= d1+d2;		if( r in [ 2, 3, 12 ] ):			game.log.msg( "game.come out", "roll: %d, lose" % (r) );			game.comeOutLose( r );			craps= 1;			self.nextState= CrapsStateComeOutRoll();			self.roundOver= 1;		elif( r in [ 7, 11 ] ):			game.log.msg( "game.come out", "roll: %d, win" % (r) );			game.comeOutWin( r );			craps= 0;			self.nextState= CrapsStateComeOutRoll();			self.roundOver= 1;		else:			game.log.msg( "game.come out", "roll: %d, point established" % (r) );			craps= 0;			self.nextState= CrapsStatePointRoll( r );			self.roundOver= 0;		game.propositionPayout( r, craps );		game.placePayout( r, craps );		game.comeWhenComeOut( r );		return self.roundOver;class CrapsStatePointRoll( CrapsState ):	def name( self ):		return "Point (%d) roll" % ( self.point );	def evalDice( self, game, d1, d2 ):		next= None;		craps= 0;		r= d1+d2;		if( r == 7 ):			game.log.msg( "game.point", "roll %d: craps" % (r) );			game.craps( r );			craps= 1;			self.nextState= CrapsStateComeOutRoll();			self.roundOver= 1;		elif( r == self.point ):			game.log.msg( "game.point", "roll %d: point made" % (r) );			game.pointMade( r );			craps= 0;			self.nextState= CrapsStateComeOutRoll();			self.roundOver= 1;		else:			game.log.msg( "game.point", "roll %d" % (r) );			craps= 0;			self.nextState= self;			self.roundOver= 0;		game.propositionPayout( r, craps );		game.placePayout( r, craps );		game.comePayout( r );		return self.roundOver;			class CrapsGame ( CasinoGame ):	"The Craps Game - bets held by a CrapsTable"	def __init__( self ):		CasinoGame.__init__( self );		self.table= CrapsTable();		self.point= 0;		self.dice= ( 0, 0 );	def state( self ):		if( self.point == 0 ):			return ( "come out", 0, self.dice );		else:			return ( "point", self.point, self.dice );	def placePayout( self, number, craps ):		"""		Bets that ride until cleared by rolling a 7			place bets (4,5,6,8,9,10) 4 and 10 pay 9:5, 5 and 9 pay 7:5, 6 and 8 pay 7:6			buy(4,5,6,8,9,10) (deduct a 5% commission) 4 and 10 pay 2:1, 5 and 9 pay 3:2, 6 and 8 pay 6:5			lay(4,5,6,8,9,10) betting 7 will be rolled first, deduct a 5% commission, pay odds as a buy bet			big(6,8) pay 1:1			hardways(4,6,8,10) 4 and 10 pay 7:1, 6 and 8 pay 9:1		"""		if( number == 7 ):			# all of these are losers			for b in [ "place 4", "place 5", "place 6", "place 8", "place 9", "place 10",				"big 6", "big 8", "hard 4", "hard 6", "hard 8", "hard 10" ]:				self.table.lose(b);		else:			# check for possible winners			if( self.table.working("place 4") and number == 4 ): self.table.win("place 4", number );			if( self.table.working("place 5") and number == 5 ): self.table.win("place 5", number );			if( self.table.working("place 6") and number == 6 ): self.table.win("place 6", number );			if( self.table.working("place 8") and number == 8 ): self.table.win("place 8", number );			if( self.table.working("place 9") and number == 9 ): self.table.win("place 9", number );			if( self.table.working("place 10") and number == 10 ): self.table.win("place 10", number );			if( self.table.working("big 6") and number == 6 ): self.table.win("big 6", number );			if( self.table.working("big 8") and number == 8 ): self.table.win("big 8", number );			if( self.table.working("hard 4") and number == 4 ):				if( self.hard() ): self.table.win("hard 4", number );				else: self.table.lose("hard 4");			if( self.table.working("hard 6") and number == 6 ):				if( self.theGame.hard() ): self.table.win("hard 6", number );				else: self.table.lose("hard 6");			if( self.table.working("hard 8") and number == 8 ):				if( self.theGame.hard() ): self.table.win("hard 8", number );				else: self.table.lose("hard 8");			if( self.table.working("hard 10") and number == 10 ):				if( self.theGame.hard() ): self.table.win("hard 10", number );				else: self.table.lose("hard 10");	def propositionPayout( self, number, craps ):		"""		1-time bets on the next roll of the die:			craps2 (30:1)			craps3 (15:1)			crapsC(30:1)			7  (4:1)			11 (15:1)			any craps [2,3,12] (7:1)			horn(2,3,1112) 2 or 12 pays 27:4, 3 or 11 pays 3:1			field(2,3,4,9,10,11,12) 3,4,9,10 or 11 pay 1:1, 2 or 12 pay 2:1		"""		if( number in [2,3,12] and self.table.working("craps") ): self.table.win("craps", number );		if( number == 7 and self.table.working("7") ): self.table.win("7", number );		if( number == 11 and self.table.working("11") ): self.table.win("11", number );		if( number in [2,3,12] and self.table.working("any craps") ): self.table.win("any craps", number );		if( number in [2,3,11,12] and self.table.working("horn") ): self.table.win("horn", number );		if( number in [2,3,4,9,10,11,12] and self.table.working("field") ): self.table.win("field", number );		for b in [ "craps", "7", "11", "any craps", "horn", "field" ]:			self.table.lose( b );	def comePayout( self, number ):		# the basic rules for the Come bets		if( number in [ 2, 3, 12 ] ):			self.table.lose("come");		elif( number in [ 7 ] ):			self.table.win("come", number );			for b in [ 4, 5, 6, 8, 9, 10 ]:				bet= "come " + str(b);				self.table.lose(bet);		elif( number in [ 11 ] ):			self.table.win("come", number );		else:			for b in [ 4, 5, 6, 8, 9, 10 ]:				bet= "come " + str(b);				if( self.table.working(bet) and b == number ):					self.table.win(bet, number );			self.table.move( "come", "come " + str(number) );	def comeWhenComeOut( self, number ):		# special rules on from Come bets on the Come Out roll - odds bets are off!		if( number in [ 2, 3, 12 ] ):			self.table.lose("come");		elif( number in [ 7 ] ):			self.table.win("come", number );			for b in [ 4, 5, 6, 8, 9, 10 ]:				self.table.lose("come "+str(b));		elif( number in [ 11 ] ):			self.table.win("come", number );		else:			self.table.move( "come", "come " + str(number) );	def comeOutWin( self, number ):		"win the round on the come out roll - pay pass line bets; come bets stay if number not 7"		self.table.win("pass line", number );		self.table.lose("pass line odds");		self.table.lose("don't pass line");	def comeOutLose( self, number ):		"lose the round on the come out roll - don't pass wins; pass line bets lose; come bets stay if number not 7"		self.table.lose("pass line");		self.table.lose("pass line odds");		self.table.win("don't pass line", number );	def craps( self, number ):		"7 rolled before point - don't pass wins; pass line bets lose; come bets lose"		self.table.lose("pass line");		self.table.lose("pass line odds");		self.table.win("don't pass line", number );	def pointMade( self, number ):		"point rolled before 7 - pass line bets win; come bets stay"		self.table.win("pass line", number );		self.table.win("pass line odds", number );		self.table.lose("don't pass line");	def hard( self ):		return self.dice[0] == self.dice[1];	def play( self ):		"play 1 round of craps, offering betting opportunities to player"		self.point= 0;	# no point, means we are doing a come-out roll		state= CrapsStateComeOutRoll();		cmd= self.player.startRound( self );		Simlog().instance().msg( "game.start", str(cmd) );		cmd.do( self );		self.dice= ( randrange(6)+1, randrange(6)+1 );		done= state.evalDice( self, self.dice[0], self.dice[1] );		while( not done ):			state= state.nextState;						# advance game state			self.point= self.dice[0] + self.dice[1];	# set the point			cmd= self.player.inRound( self );			# allow bets			cmd.do( self );			Simlog().instance().msg( "game.inround", str(cmd) );			self.dice= ( randrange(6)+1, randrange(6)+1 );	# next roll			done= state.evalDice( self, self.dice[0], self.dice[1] );		self.player.endRound( self );class CrapsPlayer ( Player ):	"pass line with odds"	def __init__( self, limit ):		Player.__init__( self, limit );	def startRound( self, game ):		"place start-of-round bet, typically pass or don't pass"		Player.startRound( self, game );		return CommandBet( "pass line", 1 );	def inRound( self, game ):		"first roll? put odds behind pass line bet; otherwise make a come bet"		(state,point,dice)= game.state();		if( point != 0 and game.working( "pass line odds" ) == 0 ):			# usually double the passline amount, but for a point of 6 or 8, 2.5 times is permitted			if( point in [6,8] ):				return CommandBet( "pass line odds", 2.5 );			else:				return CommandBet( "pass line odds", 2 );		return Command( "wait" );class CrapsPlayerBigBet( CrapsPlayer ):	"pass line plus big6 plus hard8"	def __init__( self, limit ):		CrapsPlayer.__init__( self, limit );	def startRound( self, game ):		CrapsPlayer.startRound( self, game );		bets= CommandSequence();		bets.addCommand( CommandBet( "big 6", 1 ) );		bets.addCommand( CommandBet( "hard 8", 1 ) );		return bets;	def inRound( self, game ):		CrapsPlayer.inRound( self, game );		bets= CommandSequence();		if( game.working( "big 6" ) == 0 ): bets.addCommand( CommandBet( "big 6", 1 ) );		if( game.working( "hard 8" ) == 0 ): bets.addCommand( CommandBet( "hard 8", 1 ) );		return bets;class CrapsPlayerCome1( CrapsPlayer ):	"one working come bet"	def __init__( self, limit ):		CrapsPlayer.__init__( self, limit );	def startRound( self, game ):		return CrapsPlayer.startRound( self, game );	def inRound( self, game ):		CrapsPlayer.inRound( self, game );		(state,point,dice)= game.state();		if( point != 0 ):			w= [];			for p in [ 4, 5, 6, 8, 9, 10 ]:				if( game.working( "come " + str(p) ) ): w.append( p );			if( len(w) < 1 ):		# no come bet presently working!				return CommandBet( "come", 1 );			else:				# place double odds on come number (w)				return CommandBet( "come odds " + str(w[0]), 2 );		return Command( "wait" );class CrapsPlayerComeN( CrapsPlayer ):	"n working come bets"	def __init__( self, limit, comeBets ):		CrapsPlayer.__init__( self, limit );		self.comeBets= comeBets;	def startRound( self, game ):		return CrapsPlayer.startRound( self, game );	def inRound( self, game ):		CrapsPlayer.inRound( self, game );		(state,point,dice)= game.state();		if( point != 0 ):			w= [];			for p in [ 4, 5, 6, 8, 9, 10 ]:				if( game.working( "come " + str(p) ) ): w.append( p );			if( len(w) < self.comeBets ):		# too few bets presently working				return CommandBet( "come", 1 );			else:				# place double odds on come number lacking a working odds bet				bets= CommandSequence();				for n in w:					if( not game.working( "come odds " + str(n) ) ):						bets.addCommand( CommandBet( "come odds " + str(n), 2 ) );				return bets;	def name( self ):		return self.__doc__ + " (n=" + str(self.comeBets) + ", limit=" + str(self.limit) + ")";class CrapsPlayerFactory ( PlayerFactory ):	def __init__( self ):		PlayerFactory.__init__( self );	def newPlayer( self, name ):		if( name == "simple" ): return CrapsPlayer( 100 );		if( name == "bigbet" ): return CrapsPlayerBigBet( 100 );		if( name == "come1"  ): return CrapsPlayerComeN( 100, 1 );		if( name == "come1sl"  ): return CrapsPlayerComeN( 65, 1 );		if( name == "come2"  ): return CrapsPlayerComeN( 100, 2 );		if( name == "come3"  ): return CrapsPlayerComeN( 100, 3 );		else: print "unknown", name;def main():	#(log,n)= ( Simlog().instance().summary(), 100 );	(log,n)= ( Simlog().instance().detail(), 1 );	a= Analyzer();	s= Simulator( CrapsPlayerFactory().playerSet( ["come1","come2","come1sl"] ), CrapsGame(), a );	s.generate( n, 100 );	a.report();if( __name__ == "__main__" ):	main();