In [1]:
import numpy as np
In [2]:
# We are going to implement five strategies.
# Each strategy takes as input the history of the turns played so far
# and returns 1 for cooperation and 0 for defection.
# 1) Always defect
def always_defect(previous_steps):
return 0
# 2) Always cooperate
def always_cooperate(previous_steps):
return 1
# 3) Purely random, with probability of defecting 0.5
def random(previous_steps):
if np.random.random(1) > 0.5:
return 1
return 0
# 4) Tit for tat
def tit_for_tat(previous_steps):
if len(previous_steps) == 0:
return 1
return previous_steps[-1]
# 5) Tit for two tat
def tit_for_two_tat(previous_steps):
if len(previous_steps) < 2:
return 1
# if the other player defected twice
if sum(previous_steps[-2:]) == 0:
# retaliate
return 0
return 1
You could implement a series of if elif
that plays each strategy against the other. Here, we present a more advanced approach that matches a string such as "strategy_1" with a name of a corresponding function. The call globals()[strategy_1]
does just that. Now pl1
is an "alias" that calls the function that corresponds to the chosen strategy.
In [3]:
def play_strategies(strategy_1, strategy_2, nsteps = 200):
pl1 = globals()[strategy_1]
pl2 = globals()[strategy_2]
# We create two vectors to store the moves of the players
steps_pl1 = []
steps_pl2 = []
# and two variables for keeping the scores.
# (because we said these are numbers of years in prison, we
# use negative payoffs, with less negative being better)
points_pl1 = 0
points_pl2 = 0
# Iterate over the number of steps
for i in range(nsteps):
# decide strategy:
# player 1 chooses using the history of the moves by player 2
last_pl1 = pl1(steps_pl2)
# and vice versa
last_pl2 = pl2(steps_pl1)
# calculate payoff
if last_pl1 == 1 and last_pl2 == 1:
# both cooperate -> -1 point each
points_pl1 = points_pl1 - 1
points_pl2 = points_pl2 - 1
elif last_pl1 == 0 and last_pl2 == 1:
# pl2 lose
points_pl1 = points_pl1 - 0
points_pl2 = points_pl2 - 3
elif last_pl1 == 1 and last_pl2 == 0:
# pl1 lose
points_pl1 = points_pl1 - 3
points_pl2 = points_pl2 - 0
else:
# both defect
points_pl1 = points_pl1 - 2
points_pl2 = points_pl2 - 2
# add the moves to the history
steps_pl1.append(last_pl1)
steps_pl2.append(last_pl2)
# return the final scores
return((points_pl1, points_pl2))
In [4]:
# Your numbers will differ given the involved randomness
play_strategies("random", "always_defect")
Out[4]:
In [5]:
def round_robin(strategies, nround, nstep):
nstrategies = len(strategies)
# initialize list for results
strategies_points = [0] * nstrategies
# for each pair
for i in range(nstrategies):
for j in range(i, nstrategies):
print("Playing", strategies[i], "vs.", strategies[j])
for k in range(nround):
res = play_strategies(strategies[i],
strategies[j],
nstep)
# print(res)
strategies_points[i] = strategies_points[i] + res[0]
strategies_points[j] = strategies_points[j] + res[1]
print("\nThe final results are:")
for i in range(nstrategies):
print(strategies[i] + ":", strategies_points[i])
print("\nand the winner is....")
print(strategies[strategies_points.index(max(strategies_points))])
In [6]:
my_strategies = ["always_defect",
"always_cooperate",
"random",
"tit_for_tat",
"tit_for_two_tat"]
In [7]:
# Your numbers will differ slightly given the involved randomness
round_robin(my_strategies, 10, 1000)