Skip to content
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

Implemented RichardHufford strat, K47R from Axelrod's Second. #1162

Merged
merged 6 commits into from
Jan 18, 2018
Merged
Show file tree
Hide file tree
Changes from all 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
3 changes: 2 additions & 1 deletion axelrod/strategies/_strategies.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
from .axelrod_second import (
Champion, Eatherley, Tester, Gladstein, Tranquilizer, MoreGrofman,
Kluepfel, Borufsen, Cave, WmAdams, GraaskampKatzen, Weiner, Harrington,
MoreTidemanAndChieruzzi, Getzler, Leyvraz, White, Black)
MoreTidemanAndChieruzzi, Getzler, Leyvraz, White, Black, RichardHufford)
from .backstabber import BackStabber, DoubleCrosser
from .better_and_better import BetterAndBetter
from .bush_mosteller import BushMosteller
Expand Down Expand Up @@ -243,6 +243,7 @@
Retaliate2,
Retaliate3,
RevisedDowning,
RichardHufford,
Ripoff,
RiskyQLearner,
SelfSteem,
Expand Down
114 changes: 113 additions & 1 deletion axelrod/strategies/axelrod_second.py
Original file line number Diff line number Diff line change
Expand Up @@ -1550,7 +1550,7 @@ def strategy(self, opponent: Player) -> Action:
class Black(Player):
"""
Strategy submitted to Axelrod's second tournament by Paul E Black (K83R)
and came in fourteenth in that tournament.
and came in fifteenth in that tournament.
Copy link
Member

Choose a reason for hiding this comment

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

As an FYI, this is in essence stepping on #1161. No problem at all (don't change it) but just a headsup.


The strategy Cooperates for the first five turns. Then it calculates the
number of opponent defects in the last five moves and Cooperates with
Expand Down Expand Up @@ -1597,3 +1597,115 @@ def strategy(self, opponent: Player) -> Action:
number_defects = np.sum(did_d(recent_history))

return random_choice(self.prob_coop[number_defects])


class RichardHufford(Player):
"""
Strategy submitted to Axelrod's second tournament by Richard Hufford (K47R)
and came in sixteenth in that tournament.

The strategy tracks opponent "agreements", that is whenever the opponent's
previous move is the some as this player's move two turns ago. If the
opponent's first move is a Defection, this is counted as a disagreement,
and otherwise an agreement. From the agreement counts, two measures are
calculated:

- `proportion_agree`: This is the number of agreements (through opponent's
last turn) + 2 divided by the current turn number.
- `last_four_num`: The number of agreements in the last four turns. If
there have been fewer than four previous turns, then this is number of
agreement + (4 - number of past turns).

We then use these measures to decide how to play, using these rules:

1. If `proportion_agree` > 0.9 and `last_four_num` >= 4, then Cooperate.
2. Otherwise if `proportion_agree` >= 0.625 and `last_four_num` >= 2, then
Tit-for-Tat.
3. Otherwise, Defect.

However, if the opponent has Cooperated the last `streak_needed` turns,
then the strategy deviates from the usual strategy, and instead Defects.
(We call such deviation an "aberration".) In the turn immediately after an
aberration, the strategy doesn't override, even if there's a streak of
Cooperations. Two turns after an aberration, the strategy: Restarts the
Cooperation streak (never looking before this turn); Cooperates; and
changes `streak_needed` to:

floor(20.0 * `num_abb_def` / `num_abb_coop`) + 1

Here `num_abb_def` is 2 + the number of times that the opponent Defected in
the turn after an aberration, and `num_abb_coop` is 2 + the number of times
that the opponent Cooperated in response to an aberration.

Names:

- RichardHufford: [Axelrod1980b]_
"""

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

def __init__(self) -> None:
super().__init__()
self.num_agreements = 2
self.last_four_agreements = [1] * 4
self.last_four_index = 0

self.streak_needed = 21
self.current_streak = 2
self.last_aberration = float("inf")
self.coop_after_ab_count = 2
self.def_after_ab_count = 2

def strategy(self, opponent: Player) -> Action:
turn = len(self.history) + 1
if turn == 1:
return C

# Check if opponent agreed with us.
self.last_four_index = (self.last_four_index + 1) % 4
me_two_moves_ago = C
if turn > 2:
me_two_moves_ago = self.history[-2]
if me_two_moves_ago == opponent.history[-1]:
self.num_agreements += 1
self.last_four_agreements[self.last_four_index] = 1
else:
self.last_four_agreements[self.last_four_index] = 0

# Check if last_aberration is infinite.
# i.e Not an aberration in last two turns.
if turn < self.last_aberration:
if opponent.history[-1] == C:
self.current_streak += 1
else:
self.current_streak = 0
if self.current_streak >= self.streak_needed:
self.last_aberration = turn
if self.current_streak == self.streak_needed:
return D
elif turn == self.last_aberration + 2:
self.last_aberration = float("inf")
if opponent.history[-1] == C:
self.coop_after_ab_count += 1
else:
self.def_after_ab_count += 1
self.streak_needed = np.floor(20.0 * self.def_after_ab_count / self.coop_after_ab_count) + 1
self.current_streak = 0
return C

proportion_agree = self.num_agreements / turn
last_four_num = np.sum(self.last_four_agreements)
if proportion_agree > 0.9 and last_four_num >= 4:
return C
elif proportion_agree >= 0.625 and last_four_num >= 2:
return opponent.history[-1]
return D
38 changes: 38 additions & 0 deletions axelrod/tests/strategies/test_axelrod_second.py
Original file line number Diff line number Diff line change
Expand Up @@ -1017,3 +1017,41 @@ def test_strategy(self):
actions += [(D, D), (C, D), (D, D), (D, D), (D, D), (C, D), (D, D), (D, D), (D, D), (D, D)]
self.versus_test(axelrod.Defector(), expected_actions=actions, seed=15)


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

def test_strategy(self):
actions = [(C, C)] * 19 + [(D, C), (C, C), (C, C)]
self.versus_test(axelrod.Cooperator(), expected_actions=actions, attrs={"streak_needed": 14})

actions = [(C, C)] * 19 + [(D, C), (C, C)]
actions += [(C, C)] # This is the first Cooperation that gets counted on the new streak
actions += [(C, C)] * 13 + [(D, C), (C, C), (C, C)]
self.versus_test(axelrod.Cooperator(), expected_actions=actions, attrs={"streak_needed": 11})

opponent_actions = [C] * 20 + [D]
BoredCooperator = axelrod.MockPlayer(actions=opponent_actions)
actions = [(C, C)] * 19 + [(D, C), (C, D), (C, C)]
self.versus_test(BoredCooperator, expected_actions=actions, attrs={"streak_needed": 31})

actions = [(C, D)] # "Disagreement"
actions += [(D, C)] # TFT. Disagreement
actions += [(C, C)] # TFT.
actions += [(C, D)] # TFT. Disagreement
actions += [(D, C)] # Three of last four are disagreements.
actions += [(C, C)] # TFT. Disagreement
actions += [(D, D)] # Three of last four are disagreements. Disagreement
actions += [(D, D)] # Three of last four are disagreements.
actions += [(D, D)] # Now there are 5/9 disagreements, so Defect.
self.versus_test(axelrod.WinShiftLoseStay(), expected_actions=actions, attrs={"num_agreements": 5})
2 changes: 1 addition & 1 deletion docs/reference/overview_of_strategies.rst
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ repository.
"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"
"K47R_", "Richard Hufford", ":class:`RichardHufford <axelrod.strategies.axelrod_second.RichardHufford>`"
"K48R_", "George Hufford", "Not Implemented"
"K49R_", "Rob Cave", ":class:`Cave <axelrod.strategies.axelrod_second.Cave>`"
"K50R_", "Rik Smoody", "Not Implemented"
Expand Down