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

Added strategy Borufsen/k42r from Axelrod's second tourn #1139

Merged
merged 7 commits into from
Nov 17, 2017
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
5 changes: 4 additions & 1 deletion axelrod/strategies/_strategies.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@
from .axelrod_first import (
Davis, RevisedDowning, Feld, Grofman, Nydegger, Joss, Shubik, Tullock,
UnnamedStrategy, SteinAndRapoport, TidemanAndChieruzzi)
from .axelrod_second import Champion, Eatherley, Tester, Gladstein, Tranquilizer, MoreGrofman, Kluepfel
from .axelrod_second import (
Champion, Eatherley, Tester, Gladstein, Tranquilizer, MoreGrofman,
Kluepfel, Borufsen)
from .backstabber import BackStabber, DoubleCrosser
from .better_and_better import BetterAndBetter
from .bush_mosteller import BushMosteller
Expand Down Expand Up @@ -105,6 +107,7 @@
AverageCopier,
BetterAndBetter,
BackStabber,
Borufsen,
Bully,
BushMosteller,
Calculator,
Expand Down
152 changes: 152 additions & 0 deletions axelrod/strategies/axelrod_second.py
Original file line number Diff line number Diff line change
Expand Up @@ -566,3 +566,155 @@ def strategy(self, opponent: Player) -> Action:
return one_move_ago
else:
return one_move_ago.flip()

class Borufsen(Player):
"""
Strategy submitted to Axelrod's second tournament by Otto Borufsen
(K32R), and came in third in that tournament.

This player keeps track of the the opponent's responses to own behavior:

- `cd_count` counts: Opponent cooperates as response to player defecting.
- `cc_count` counts: Opponent cooperates as response to player cooperating.

The player has a defect mode and a normal mode. In defect mode, the
player will always defect. In normal mode, the player obeys the following
ranked rules:

1. If in the last three turns, both the player/opponent defected, then
cooperate for a single turn.
2. If in the last three turns, the player/opponent acted differently from
each other and they're alternating, then change next defect to
cooperate. (Doesn't block third rule.)
3. Otherwise, do tit-for-tat.

Start in normal mode, but every 25 turns starting with the 27th turn,
re-evaluate the mode. Enter defect mode if any of the following
conditions hold:

- Detected random: Opponent cooperated 7-18 times since last mode
evaluation (or start) AND less than 70% of opponent cooperation was in
response to player's cooperation, i.e.
cc_count / (cc_count+cd_count) < 0.7
- Detect defective: Opponent cooperated fewer than 3 times since last mode
evaluation.

When switching to defect mode, defect immediately. The first two rules for
normal mode require that last three turns were in normal mode. When starting
normal mode from defect mode, defect on first move.

Names:

- Borufsen: [Axelrod1980b]_
"""

name = "Borufsen"
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):
super().__init__()
self.cd_counts, self.cc_counts = 0, 0
self.mutual_defect_streak = 0
self.echo_streak = 0
self.flip_next_defect = False
self.mode = "Normal"

def try_return(self, to_return):
"""
We put the logic here to check for the `flip_next_defect` bit here,
and proceed like normal otherwise.
"""

if to_return == C:
return C
# Otherwise look for flip bit.
if self.flip_next_defect:
self.flip_next_defect = False
return C
return D

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

if turn == 1:
return C

# Update the response history.
if turn >= 3:
if opponent.history[-1] == C:
if self.history[-2] == C:
self.cc_counts += 1
else:
self.cd_counts += 1

# Check if it's time for a mode change.
if turn > 2 and turn % 25 == 2:
coming_from_defect = False
if self.mode == "Defect":
coming_from_defect = True

self.mode = "Normal"
coops = self.cd_counts + self.cc_counts

# Check for a defective strategy
if coops < 3:
self.mode = "Defect"

# Check for a random strategy
if (coops >= 8 and coops <= 17) and self.cc_counts/coops < 0.7:
self.mode = "Defect"

self.cd_counts, self.cc_counts = 0, 0

# If defect mode, clear flags
if self.mode == "Defect":
self.mutual_defect_streak = 0
self.echo_streak = 0
self.flip_next_defect = False

# Check this special case
if self.mode == "Normal" and coming_from_defect:
return D

# Proceed
if self.mode == "Defect":
return D
else:
assert self.mode == "Normal"

# Look for mutual defects
if self.history[-1] == D and opponent.history[-1] == D:
self.mutual_defect_streak += 1
else:
self.mutual_defect_streak = 0
if self.mutual_defect_streak >= 3:
self.mutual_defect_streak = 0
self.echo_streak = 0 # Reset both streaks.
return self.try_return(C)

# Look for echoes
# Fortran code defaults two turns back to C if only second turn
my_two_back, opp_two_back = C, C
if turn >= 3:
my_two_back = self.history[-2]
opp_two_back = opponent.history[-2]
if self.history[-1] != opponent.history[-1] and \
self.history[-1] == opp_two_back and opponent.history[-1] == my_two_back:
self.echo_streak += 1
else:
self.echo_streak = 0
if self.echo_streak >= 3:
self.mutual_defect_streak = 0 # Reset both streaks.
self.echo_streak = 0
self.flip_next_defect = True

# Tit-for-tat
return self.try_return(opponent.history[-1])
40 changes: 39 additions & 1 deletion axelrod/tests/strategies/test_axelrod_second.py
Original file line number Diff line number Diff line change
Expand Up @@ -451,4 +451,42 @@ def test_strategy(self):
(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):
name = "Borufsen"
player = axelrod.Borufsen
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)] * 100 # Cooperate forever
self.versus_test(axelrod.Cooperator(), expected_actions=actions)

# Tries to cooperate every third time until detecting defective
actions = [(C, D), (D, D), (D, D), (D, D)] * 6 + \
[(C, D), (D, D)] + [(D, D)] * 100
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
# 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.
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.
actions = [(C, D), (D, C), (C, C)] * 8 + \
[(C, D), (D, C)] + [(D, C)] * 25 + \
[(D, C)] + [(C, C), (C, D), (D, C)] * 8 + \
[(D, C)] * 25
self.versus_test(axelrod.WinShiftLoseStay(D), expected_actions=actions)
2 changes: 1 addition & 1 deletion axelrod/tests/strategies/test_meta.py
Original file line number Diff line number Diff line change
Expand Up @@ -335,7 +335,7 @@ def test_strategy(self):
self.versus_test(opponent=axelrod.Alternator(),
expected_actions=actions, seed=0)

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

Expand Down
2 changes: 1 addition & 1 deletion docs/reference/overview_of_strategies.rst
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ repository.
"K39R_", "Tom Almy", "Not Implemented"
"K40R_", "Robert Adams", "Not Implemented"
"K41R_", "Herb Weiner", "Not Implemented"
"K42R_", "Otto Borufsen", "Not Implemented"
"K42R_", "Otto Borufsen", ":class:`Borufsen <axelrod.strategies.axelrod_second.Borufsen>`"
"K43R_", "R D Anderson", "Not Implemented"
"K44R_", "William Adams", "Not Implemented"
"K45R_", "Michael F McGurrin", "Not Implemented"
Expand Down