In the source, you can create different strategy functions that take the same arguments

and return either a colour or the global name ipass.

Enjoy!

'''

The hat problem

From: http://www.msri.org/people/members/sara/articles/hat.html

The hat problem goes like this:

Three players enter a room and a red or blue hat is placed on each

person's head. The color of each hat is determined by a coin toss,

with the outcome of one coin toss having no effect on the others. Each

person can see the other players' hats but not his own.

No communication of any sort is allowed, except for an initial

strategy session before the game begins. Once they have had a chance

to look at the other hats, the players must simultaneously guess the

color of their own hats or pass. The group shares a hypothetical $3

million prize if at least one player guesses correctly and no players

guess incorrectly.

'''

import random

verbose = True

numplayers = 3

hatcolours = 'red blue'.split()

ipass = 'pass'defotherhatcolour(hat):

''' not(hat) when hat can have two or more colours'''

returnhatcolours[(hatcolours.index(hat)+1) % len(hatcolours)]defplayerhats(n = numplayers):

''' generate all hat combinations for the players, but scrambled.'''

ifn:

hats = hatcolours[:]

random.shuffle(hats)

forh1inhats:

forh2inplayerhats(n-1):

yield[h1] + h2

else:

yield[]defstrategy0(otherhats, hatcolours):

'''

If there is a clear max total of hat colours:

Yours is a random choice from the hat colours occuring the least

else:

pass

'''

# Count the total hats in each colour

colourcount = [otherhats.count(c)forcinhatcolours]

# What hat colours are most/least prevalent

mn = min(colourcount)

mx = max(colourcount)

#

ifcolourcount.count(mx) == 1:

# only one colour occurs as the maximum

returnhatcolours[random.choice([ index

forindex, countinenumerate(colourcount)

ifcount == mn]) ]

else:

returnipassdefstrategy1(otherhats, hatcolours):

'''

If there is a clear max and min total of hat colours,

Yours is the min; otherwise pass.

'''

# Count the total hats in each colour

colourcount = [otherhats.count(c)forcinhatcolours]

# What hat colours are most/least prevalent

mn = min(colourcount)

mx = max(colourcount)

#

ifmn != mxand(mn == 0orcolourcount.count(mx) == colourcount.count(mn) == 1):

# only one colour occurs as the maximum, another as minimum

# So guess the minimum

returnhatcolours[colourcount.index(mn)]

else:

returnipassdefscoreplayers(ph, strategy, _verbose = verbose):

''' Compute score and return 1 if players win otherwise zero'''

n = len(ph)

strat = []

playerguessed = []

forplayernum,hatinenumerate(ph):

strat = strategy([hfori,hinenumerate(ph)ifi != playernum], hatcolours)

if_verbose:

" "*(playernum+1), playernum, " "*(n-playernum-1), hat, strat

),

ifstrat == hat:

if_verbose:

playerguessed.append(True)

elifstrat == ipass:

if_verbose:

playerguessed.append(ipass)

else:

if_verbose:

playerguessed.append(False)

if(Trueinplayerguessed)andnot( Falseinplayerguessed):

if_verbose:

return1

else:

if_verbose:

return0defrun_stratagem(strategy, _verbose= verbose, _numplayers = numplayers,

_hatcolours = hatcolours):

'''Applies a strategy function to all possible games of a hat problem.

Prints either a verbose output of every trial, or a summary of

all trials in csv format

'''

globalverbose, numplayers, hatcolours

verbose, numplayers, hatcolours = _verbose, _numplayers, _hatcolours

totaltries = 0

totalwins = 0

ifverbose:

forphinplayerhats():

totaltries +=1

totalwins += scoreplayers(ph, strategy, verbose)

ifverbose:

totalwins, totaltries, float(totalwins)/totaltries*100.0,

strategy.__name__)

else:

strategy.__name__, len(hatcolours), numplayers,

totaltries, totalwins, float(totalwins)/totaltries)

colours = 'red blue orange yellow green indigo violet'.split()

run_stratagem(strategy0, verbose)

run_stratagem(strategy1, verbose)