Skip to content

Adaptive Zero Determinant Strategy #1282

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 14 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions axelrod/strategies/_strategies.py
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,7 @@
ZDGen2,
ZDMischief,
ZDSet2,
AdaptiveZeroDet,
)

# Note: Meta* strategies are handled in .__init__.py
Expand Down
79 changes: 79 additions & 0 deletions axelrod/strategies/zero_determinant.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import random
from axelrod.action import Action
from axelrod.player import Player

from .memoryone import MemoryOnePlayer

Expand Down Expand Up @@ -225,3 +227,80 @@ class ZDSet2(LRPlayer):

def __init__(self, phi: float = 1 / 4, s: float = 0.0, l: float = 2) -> None:
super().__init__(phi, s, l)


class AdaptiveZeroDet(LRPlayer):
name = 'AdaptiveZeroDet'
classifier = {
'memory_depth': float('inf'), # Long memory
'stochastic': True,
'makes_use_of': set(["game"]),
'long_run_time': False,
'inspects_source': False,
'manipulates_source': False,
'manipulates_state': False
}

def __init__(self, phi: float = 0.125, s: float = 0.5, l: float = 3,
initial: Action = C) -> None:
# This Keeps track of the parameter values (phi,s,l) as well as the
# four vector which makes final decisions.
super().__init__(phi=phi, s=s, l=l)
self._scores = {C: 0, D: 0}
self._initial = initial

def score_last_round(self, opponent: Player):
"""This gives the strategy the game attributes and allows the strategy
to score itself properly."""
game = self.match_attributes["game"]
if len(self.history):
last_round = (self.history[-1], opponent.history[-1])
scores = game.score(last_round)
self._scores[last_round[0]] += scores[0]

def _adjust_parameters(self):
d = random.randint(0, 9) / 1000 # Selects random value to adjust s and l

if self._scores[C] > self._scores[D]:
# This checks scores to determine how to adjust s and l either
# up or down by d
self.l = self.l + d
self.s = self.s - d
R, P, S, T = self.match_attributes["game"].RPST()
l = self.l
s = self.s
s_min = - min((T - l) / (l - S), (l - S) / (T - l)) # Sets minimum for s
if (l > R) or (s < s_min):
# This checks that neither s nor l is leaving its range
# If l would leave its range instead its distance from its max is halved
if l > R:
l = l - d
self.l = (l + R) / 2
# If s would leave its range instead its distance from its min is halved
if s < s_min:
s = s + d
self.s = (s + s_min) / 2
else:
# This adjusts s and l in the opposite direction
self.l = self.l - d
self.s = self.s + d
R, P, S, T = self.match_attributes["game"].RPST()
l = self.l
s = self.s
if (l < P) or (s > 1):
# This checks that neither s nor l is leaving its range
if l < P:
l = l + d
self.l = (l + P) / 2
# If l would leave its range instead its distance from its min is halved
if s > 1:
s = s - d
self.s = (s + 1) / 2
# Update the four vector for the new l and s values
self.receive_match_attributes()

def strategy(self, opponent: Player) -> Action:
if len(self.history) > 0:
self.score_last_round(opponent)
self._adjust_parameters()
return super().strategy(opponent)
24 changes: 24 additions & 0 deletions axelrod/tests/strategies/test_zero_determinant.py
Original file line number Diff line number Diff line change
Expand Up @@ -317,3 +317,27 @@ def test_strategy(self):

actions = [(C, D), (D, C), (D, D), (D, C), (D, D), (D, C)]
self.versus_test(opponent=axelrod.CyclerDC(), expected_actions=actions, seed=5)


class TestAdaptiveZeroDet(TestPlayer):
"""
Tests for the N Tit(s) For M Tat(s) strategy
"""

name = "AdaptiveZeroDet: 0.125, 0.5, 3, C"
player = axelrod.AdaptiveZeroDet
expected_classifier = {
"memory_depth": float('inf'),
"stochastic": True,
"makes_use_of": set(['game']),
"long_run_time": False,
"inspects_source": False,
"manipulates_source": False,
"manipulates_state": False,
}

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we add few tests for the two specific methods: _adjust_parameters and score_last_round (just running the methods and checking that the attributes have changed accordingly?

def test_strategy(self):
actions = [(C, C), (C, D), (C, C), (C, D), (C, C)]
self.versus_test(
axelrod.Alternator(), expected_actions=actions
)
2 changes: 2 additions & 0 deletions docs/reference/all_strategies.rst
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ Here are the docstrings of all the strategies in the library.

.. automodule:: axelrod.strategies.adaptive
:members:
.. automodule:: axelrod.strategies.adaptivezerodet
:members:
.. automodule:: axelrod.strategies.adaptor
:members:
.. automodule:: axelrod.strategies.alternator
Expand Down