Skip to content

Commit

Permalink
Implemented WmAdams strategy (k44r from Axelrod's second) (#1142)
Browse files Browse the repository at this point in the history
* Implemented WmAdams strategy (k44r from Axelrod's second)

* Fixed formatting issues mentioned in PR

* Minor formatting fixes.

* Subtracted first defect.
  • Loading branch information
gaffney2010 authored and drvinceknight committed Nov 27, 2017
1 parent 36ac9a4 commit 8b434a9
Show file tree
Hide file tree
Showing 5 changed files with 109 additions and 24 deletions.
3 changes: 2 additions & 1 deletion axelrod/strategies/_strategies.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
UnnamedStrategy, SteinAndRapoport, TidemanAndChieruzzi)
from .axelrod_second import (
Champion, Eatherley, Tester, Gladstein, Tranquilizer, MoreGrofman,
Kluepfel, Borufsen, Cave)
Kluepfel, Borufsen, Cave, WmAdams)
from .backstabber import BackStabber, DoubleCrosser
from .better_and_better import BetterAndBetter
from .bush_mosteller import BushMosteller
Expand Down Expand Up @@ -274,6 +274,7 @@
Winner21,
WinShiftLoseStay,
WinStayLoseShift,
WmAdams,
WorseAndWorse,
WorseAndWorse2,
WorseAndWorse3,
Expand Down
44 changes: 41 additions & 3 deletions axelrod/strategies/axelrod_second.py
Original file line number Diff line number Diff line change
Expand Up @@ -755,9 +755,9 @@ def strategy(self, opponent: Player) -> Action:
turn = len(self.history) + 1
if turn == 1: return C

did_d = np.vectorize(lambda action: float(action == D))
number_defects = np.sum(did_d(opponent.history))
perc_defects = number_defects / turn # Size of numerator is smaller than denomator -- How it was in the Fortran.
number_defects = opponent.defections
# Size of numerator is smaller than denomator -- How it was in the Fortran.
perc_defects = number_defects / turn

# If overly defect or appears random
if turn > 39 and perc_defects > 0.39: return D
Expand All @@ -771,3 +771,41 @@ def strategy(self, opponent: Player) -> Action:
return random_choice(0.5)
else:
return C

class WmAdams(Player):
"""
Strategy submitted to Axelrod's second tournament by William Adams (K44R),
and came in fifth in that tournament.
Count the number of opponent defections after their first move, call
`c_defect`. Defect if c_defect equals 4, 7, or 9. If c_defect > 9,
then defect immediately after opponent defects with probability =
(0.5)^(c_defect-1). Otherwise cooperate.
Names:
- WmAdams: [Axelrod1980b]_
"""

name = "WmAdams"
classifier = {
'memory_depth': float('inf'),
'stochastic': True,
'makes_use_of': set(),
'long_run_time': False,
'inspects_source': False,
'manipulates_source': False,
'manipulates_state': False
}

def strategy(self, opponent: Player) -> Action:
if len(self.history) <= 1:
return C
number_defects = opponent.defections
if opponent.history[0] == D:
number_defects -= 1

if number_defects in [4, 7, 9]: return D
if number_defects > 9 and opponent.history[-1] == D:
return random_choice((0.5) ** (number_defects - 9))
return C
82 changes: 64 additions & 18 deletions axelrod/tests/strategies/test_axelrod_second.py
Original file line number Diff line number Diff line change
Expand Up @@ -442,14 +442,15 @@ def test_strategy(self):

# Now we have to test the detect-random logic, which doesn't pick up
# until after 26 turns. So we need a big sample.
actions = [(C, D), (D, D), (D, D), (D, D), (D, D), (D, C), (C, C), (C, D),
(C, C), (D, D), (D, C), (C, C), (C, D), (D, D), (C, D), (D, D),
(D, C), (C, C), (D, C), (C, C), (C, D), (D, D), (D, C), (C, D),
(D, C), (C, C), (C, D),
actions = [(C, D), (D, D), (D, D), (D, D), (D, D), (D, C), (C, C),
(C, D), (C, C), (D, D), (D, C), (C, C), (C, D), (D, D),
(C, D), (D, D), (D, C), (C, C), (D, C), (C, C), (C, D),
(D, D), (D, C), (C, D), (D, C), (C, C), (C, D),
# Success detect random opponent for remaining turns.
(D, D),(D, D),(D, D),(D, C),(D, D),(D, C),(D, D),(D, C),(D, D),
(D, C),(D, C),(D, D),(D, D),(D, C),(D, C),(D, C),(D, C),(D, D),
(D, C),(D, C),(D, C),(D, C),(D, D)]
(D, D), (D, D), (D, D), (D, C), (D, D), (D, C), (D, D),
(D, C), (D, D), (D, C), (D, C), (D, D), (D, D), (D, C),
(D, C), (D, C), (D, C), (D, D), (D, C), (D, C), (D, C),
(D, C), (D, D)]
self.versus_test(axelrod.Random(0.5), expected_actions=actions, seed=10)

class TestBorufsen(TestPlayer):
Expand All @@ -475,16 +476,21 @@ def test_strategy(self):
self.versus_test(axelrod.Defector(), expected_actions=actions)

# Alternates with additional coop, every sixth turn
# Won't be labeled as random, since 2/3 of opponent's C follow player's C
# `flip_next_defect` will get set on the sixth turn, which changes the seventh action
# Won't be labeled as random, since 2/3 of opponent's C follow
# player's C
# `flip_next_defect` will get set on the sixth turn, which changes the
# seventh action
# Note that the first two turns of each period of six aren't
# marked as echoes, and the third isn't marked that way until the fourth turn.
# marked as echoes, and the third isn't marked that way until the
# fourth turn.
actions = [(C, C), (C, D), (D, C), (C, D), (D, C), (C, D)] * 20
self.versus_test(axelrod.Alternator(), expected_actions=actions)

# Basically does tit-for-tat against Win-Shift, Lose-Stay D
# After 26 turns, will detect random since half of opponent's C follow Cs
# Coming out of it, there will be new pattern. Then random is detected again.
# After 26 turns, will detect random since half of opponent's C follow
# Cs
# Coming out of it, there will be new pattern. Then random is detected
# again.
actions = [(C, D), (D, C), (C, C)] * 8 + \
[(C, D), (D, C)] + [(D, C)] * 25 + \
[(D, C)] + [(C, C), (C, D), (D, C)] * 8 + \
Expand All @@ -505,7 +511,7 @@ class TestCave(TestPlayer):
}

def test_strategy(self):
actions = [(C, C)] * 100
actions = [(C, C)] * 100
self.versus_test(axelrod.Cooperator(), expected_actions=actions)

# It will take until turn 18 to respond decide to repond D->D
Expand All @@ -531,11 +537,51 @@ def test_strategy(self):

#Here it will take until turn 40 to detect random and defect
actions = [(C, C)]
actions += [(C, D), (D, C), (C, D), (D, C), (C, D), (C, C), (C, D),
(C, C), (C, D), (D, C), (C, D), (D, C), (C, D), (D, C),
(C, D), (C, C), (C, D), (D, C), (C, D), (D, C), (C, D),
(D, C), (C, D), (C, C), (C, D), (C, C), (C, D), (C, C),
(C, D), (D, C), (C, D), (D, C), (C, D), (D, C), (C, D)] #Randomly choose
actions += [(C, D), (D, C), (C, D), (D, C), (C, D), (C, C), (C, D),
(C, C), (C, D), (D, C), (C, D), (D, C), (C, D), (D, C),
(C, D), (C, C), (C, D), (D, C), (C, D), (D, C), (C, D),
(D, C), (C, D), (C, C), (C, D), (C, C), (C, D), (C, C),
(C, D), (D, C), (C, D), (D, C), (C, D), (D, C), (C, D)] #Randomly choose
actions += [(D, C), (C, D), (D, C)] # 17 D have come, so tit for tat for a while
actions += [(D, D), (D, C)] * 100 # Random finally detected
self.versus_test(axelrod.Alternator(), expected_actions=actions, seed=2)

class TestWmAdams(TestPlayer):
name = "WmAdams"
player = axelrod.WmAdams
expected_classifier = {
'memory_depth': float('inf'),
'stochastic': True,
'makes_use_of': set(),
'long_run_time': False,
'inspects_source': False,
'manipulates_source': False,
'manipulates_state': False
}

def test_strategy(self):
actions = [(C, C)] * 100 # Cooperate forever
self.versus_test(axelrod.Cooperator(), expected_actions=actions)

# Will ignore the first four defects
opponent_actions = [D] * 4 + [C] * 100
defect_four = axelrod.MockPlayer(actions=opponent_actions)
actions = [(C, D)] * 4 + [(C, C)] * 100
self.versus_test(defect_four, expected_actions=actions)

actions = [(C, D), (C, D), (C, D), (C, D), (C, D), (D, D), (C, D),
(C, D), (D, D), (C, D), (D, D), (C, D), (D, D), (D, D),
(D, D), (D, D)]
self.versus_test(axelrod.Defector(), expected_actions=actions, seed=1)
actions = [(C, D), (C, D), (C, D), (C, D), (C, D), (D, D), (C, D),
(C, D), (D, D), (C, D), (D, D), (D, D), (D, D), (C, D),
(D, D), (D, D)]
self.versus_test(axelrod.Defector(), expected_actions=actions, seed=2)

# After responding to the 11th D (counted as 10 D), just start cooperating
opponent_actions = [D] * 11 + [C] * 100
changed_man = axelrod.MockPlayer(actions=opponent_actions)
actions = [(C, D), (C, D), (C, D), (C, D), (C, D), (D, D), (C, D),
(C, D), (D, D), (C, D), (D, D), (C, C)]
actions += [(C, C)] * 99
self.versus_test(changed_man, expected_actions=actions, seed=1)
2 changes: 1 addition & 1 deletion docs/reference/overview_of_strategies.rst
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ repository.
"K41R_", "Herb Weiner", "Not Implemented"
"K42R_", "Otto Borufsen", ":class:`Borufsen <axelrod.strategies.axelrod_second.Borufsen>`"
"K43R_", "R D Anderson", "Not Implemented"
"K44R_", "William Adams", "Not Implemented"
"K44R_", "William Adams", ":class:`WmAdams <axelrod.strategies.axelrod_second.WmAdams>`"
"K45R_", "Michael F McGurrin", "Not Implemented"
"K46R_", "Graham J Eatherley", ":class:`Eatherley <axelrod.strategies.axelrod_second.Eatherley>`"
"K47R_", "Richard Hufford", "Not Implemented"
Expand Down
2 changes: 1 addition & 1 deletion docs/tutorials/advanced/classification_of_strategies.rst
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ strategies::
... }
>>> strategies = axl.filtered_strategies(filterset)
>>> len(strategies)
77
78

Or, to find out how many strategies only use 1 turn worth of memory to
make a decision::
Expand Down

0 comments on commit 8b434a9

Please sign in to comment.