## Solution of 6.6.3, Axelrod 1980

``````

In [1]:

import numpy as np

``````

## Implement the five strategies

``````

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

``````

## Write a function that accepts the name of two strategies and competes them in a game of iterated prisoner's dilemma for a given number of turns.

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]:

(-506, -188)

``````

## Implement a round-robin tournament, in which each strategy is played against every other (including against itself) for 10 rounds of 1000 turns each.

``````

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)

``````
``````

Playing always_defect vs. always_defect
Playing always_defect vs. always_cooperate
Playing always_defect vs. random
Playing always_defect vs. tit_for_tat
Playing always_defect vs. tit_for_two_tat
Playing always_cooperate vs. always_cooperate
Playing always_cooperate vs. random
Playing always_cooperate vs. tit_for_tat
Playing always_cooperate vs. tit_for_two_tat
Playing random vs. random
Playing random vs. tit_for_tat
Playing random vs. tit_for_two_tat
Playing tit_for_tat vs. tit_for_tat
Playing tit_for_tat vs. tit_for_two_tat
Playing tit_for_two_tat vs. tit_for_two_tat

The final results are:
always_defect: -89916
always_cooperate: -90012
random: -85013
tit_for_tat: -74957
tit_for_two_tat: -77465

and the winner is....
tit_for_tat

``````