from typing import List
from axelrod.action import Action
from axelrod.player import Player
Vector = List[float]
C, D = Action.C, Action.D
[docs]
class CollectiveStrategy(Player):
"""Defined in [Li2009]_. 'It always cooperates in the first move and defects
in the second move. If the opponent also cooperates in the first move and
defects in the second move, CS will cooperate until the opponent defects.
Otherwise, CS will always defect.'
Names:
- Collective Strategy: [Li2009]_
"""
name = "CollectiveStrategy"
classifier = {
"stochastic": False,
"memory_depth": float("inf"), # Long memory
"long_run_time": False,
"inspects_source": False,
"manipulates_source": False,
"manipulates_state": False,
}
[docs]
def strategy(self, opponent: Player) -> Action:
"""Actual strategy definition that determines player's action."""
turn = len(self.history)
if turn == 0:
return C
if turn == 1:
return D
if opponent.defections > 1:
return D
if opponent.history[0:2] == [C, D]:
return C
return D
[docs]
class Detective(Player):
"""
Starts with C, D, C, C, or with the given sequence of actions.
If the opponent defects at least once in the first fixed rounds,
play as TFT forever, else defect forever.
Names:
- Detective: [NC2019]_
"""
name = "Detective"
classifier = {
"memory_depth": float("inf"),
"stochastic": False,
"long_run_time": False,
"inspects_source": False,
"manipulates_source": False,
"manipulates_state": False,
}
def __init__(self, initial_actions: List[Action] = None) -> None:
super().__init__()
if initial_actions is None:
self.initial_actions = [C, D, C, C]
else:
self.initial_actions = initial_actions
[docs]
def strategy(self, opponent: Player) -> Action:
"""Actual strategy definition that determines player's action."""
hist_size = len(self.history)
init_size = len(self.initial_actions)
if hist_size < init_size:
return self.initial_actions[hist_size]
if D not in opponent.history[:init_size]:
return D
return opponent.history[-1] # TFT
[docs]
class Prober(Player):
"""
Plays D, C, C initially. Defects forever if opponent cooperated in moves 2
and 3. Otherwise plays TFT.
Names:
- Prober: [Li2011]_
"""
name = "Prober"
classifier = {
"stochastic": False,
"memory_depth": float("inf"), # Long memory
"long_run_time": False,
"inspects_source": False,
"manipulates_source": False,
"manipulates_state": False,
}
[docs]
def strategy(self, opponent: Player) -> Action:
"""Actual strategy definition that determines player's action."""
turn = len(self.history)
if turn == 0:
return D
if turn == 1:
return C
if turn == 2:
return C
if turn > 2:
if opponent.history[1:3] == [C, C]:
return D
else:
# TFT
return D if opponent.history[-1:] == [D] else C
[docs]
class Prober2(Player):
"""
Plays D, C, C initially. Cooperates forever if opponent played D then C
in moves 2 and 3. Otherwise plays TFT.
Names:
- Prober 2: [Prison1998]_
"""
name = "Prober 2"
classifier = {
"stochastic": False,
"memory_depth": float("inf"), # Long memory
"long_run_time": False,
"inspects_source": False,
"manipulates_source": False,
"manipulates_state": False,
}
[docs]
def strategy(self, opponent: Player) -> Action:
"""Actual strategy definition that determines player's action."""
turn = len(self.history)
if turn == 0:
return D
if turn == 1:
return C
if turn == 2:
return C
if turn > 2:
if opponent.history[1:3] == [D, C]:
return C
else:
# TFT
return D if opponent.history[-1:] == [D] else C
[docs]
class Prober3(Player):
"""
Plays D, C initially. Defects forever if opponent played C in moves 2.
Otherwise plays TFT.
Names:
- Prober 3: [Prison1998]_
"""
name = "Prober 3"
classifier = {
"stochastic": False,
"memory_depth": float("inf"), # Long memory
"long_run_time": False,
"inspects_source": False,
"manipulates_source": False,
"manipulates_state": False,
}
[docs]
def strategy(self, opponent: Player) -> Action:
"""Actual strategy definition that determines player's action."""
turn = len(self.history)
if turn == 0:
return D
if turn == 1:
return C
if turn > 1:
if opponent.history[1] == C:
return D
else:
# TFT
return D if opponent.history[-1:] == [D] else C
[docs]
class Prober4(Player):
"""
Plays C, C, D, C, D, D, D, C, C, D, C, D, C, C, D, C, D, D, C, D initially.
Counts retaliating and provocative defections of the opponent.
If the absolute difference between the counts is smaller or equal to 2,
defects forever.
Otherwise plays C for the next 5 turns and TFT for the rest of the game.
Names:
- Prober 4: [Prison1998]_
"""
name = "Prober 4"
classifier = {
"stochastic": False,
"memory_depth": float("inf"),
"long_run_time": False,
"inspects_source": False,
"manipulates_source": False,
"manipulates_state": False,
}
def __init__(self) -> None:
super().__init__()
self.init_sequence = [
C,
C,
D,
C,
D,
D,
D,
C,
C,
D,
C,
D,
C,
C,
D,
C,
D,
D,
C,
D,
]
self.just_Ds = 0
self.unjust_Ds = 0
self.turned_defector = False
[docs]
def strategy(self, opponent: Player) -> Action:
"""Actual strategy definition that determines player's action."""
if not self.history:
return self.init_sequence[0]
turn = len(self.history)
if turn < len(self.init_sequence):
if opponent.history[-1] == D:
if self.history[-1] == D:
self.just_Ds += 1
if self.history[-1] == C:
self.unjust_Ds += 1
return self.init_sequence[turn]
if turn == len(self.init_sequence):
diff_in_Ds = abs(self.just_Ds - self.unjust_Ds)
self.turned_defector = diff_in_Ds <= 2
if self.turned_defector:
return D
if not self.turned_defector:
if turn < len(self.init_sequence) + 5:
return C
return D if opponent.history[-1] == D else C
[docs]
class HardProber(Player):
"""
Plays D, D, C, C initially. Defects forever if opponent cooperated in moves
2 and 3. Otherwise plays TFT.
Names:
- Hard Prober: [Prison1998]_
"""
name = "Hard Prober"
classifier = {
"stochastic": False,
"memory_depth": float("inf"), # Long memory
"long_run_time": False,
"inspects_source": False,
"manipulates_source": False,
"manipulates_state": False,
}
[docs]
def strategy(self, opponent: Player) -> Action:
"""Actual strategy definition that determines player's action."""
turn = len(self.history)
if turn == 0:
return D
if turn == 1:
return D
if turn == 2:
return C
if turn == 3:
return C
if turn > 3:
if opponent.history[1:3] == [C, C]:
return D
else:
# TFT
return D if opponent.history[-1:] == [D] else C
[docs]
class NaiveProber(Player):
"""
Like tit-for-tat, but it occasionally defects with a small probability.
Names:
- Naive Prober: [Li2011]_
"""
name = "Naive Prober"
classifier = {
"memory_depth": 1,
"stochastic": True,
"long_run_time": False,
"inspects_source": False,
"manipulates_source": False,
"manipulates_state": False,
}
def __init__(self, p: float = 0.1) -> None:
"""
Parameters
----------
p, float
The probability to defect randomly
"""
super().__init__()
self.p = p
if (self.p == 0) or (self.p == 1):
self.classifier["stochastic"] = False
[docs]
def strategy(self, opponent: Player) -> Action:
"""Actual strategy definition that determines player's action."""
# First move
if len(self.history) == 0:
return C
# React to the opponent's last move
if opponent.history[-1] == D:
return D
# Otherwise cooperate, defect with probability 1 - self.p
if self.p == 0:
return C
if self.p == 1:
return D
choice = self._random.random_choice(1 - self.p)
return choice
[docs]
class RemorsefulProber(NaiveProber):
"""
Like Naive Prober, but it remembers if the opponent responds to a random
defection with a defection by being remorseful and cooperating.
For reference see: [Li2011]_. A more complete description is given in "The
Selfish Gene" (https://books.google.co.uk/books?id=ekonDAAAQBAJ):
"Remorseful Prober remembers whether it has just spontaneously defected, and
whether the result was prompt retaliation. If so, it 'remorsefully' allows
its opponent 'one free hit' without retaliating."
Names:
- Remorseful Prober: [Li2011]_
"""
name = "Remorseful Prober"
classifier = {
"memory_depth": 2, # It remembers if its previous move was random
"stochastic": True,
"long_run_time": False,
"inspects_source": False,
"manipulates_source": False,
"manipulates_state": False,
}
def __init__(self, p: float = 0.1) -> None:
super().__init__(p)
self.probing = False
[docs]
def strategy(self, opponent: Player) -> Action:
"""Actual strategy definition that determines player's action."""
# First move
if len(self.history) == 0:
return C
# React to the opponent's last move
if opponent.history[-1] == D:
if self.probing:
self.probing = False
return C
return D
# Otherwise cooperate with probability 1 - self.p
if self.p == 1:
self.probing = True
return D
elif self.p == 0 or self._random.random() < 1 - self.p:
self.probing = False
return C
self.probing = True
return D