Skip to content
Closed
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
1 change: 1 addition & 0 deletions axelrod/strategies/_strategies.py
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@
FSMPlayer,
)
from .forgiver import Forgiver, ForgivingTitForTat
from .four_duality_optimizer import FourDualityOptimizer1
from .gambler import (
PSOGambler1_1_1,
PSOGambler2_2_2,
Expand Down
64 changes: 64 additions & 0 deletions axelrod/strategies/four_duality_optimizer.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
from axelrod.action import Action
from axelrod.player import Player

C, D = Action.C, Action.D

class FourDualityOptimizer1(Player):
"""
A strategy that operates as follows:
cooperate by default;
ignore betrayals of length 1;
when the other agent performs a series of betrayals of length greater than 1,
respond with a series of betrayals whose number is equal to the number
of series of betrayals performed by the other agent since the beginning.
Based on the IPD analysis presented in the paper: https://philpapers.org/rec/FRACCP

Names:
4-Duality Optimizer 1 original by Paul Franceschi
"""
name = "4-Duality Optimizer 1"
classifier = {
'memory_depth': float('inf'),
'stochastic': False,
'long_run_time': False,
'inspects_source': False,
'manipulates_source': False,
'manipulates_state': False
}

def strategy(self, opponent: Player) -> Action:
# Calculate the number of opponent betrayal streaks of length > 1
waves_greater_than_one = 0
current_wave_length = 0
for action in opponent.history:
if action == axl.Action.D:
current_wave_length += 1
else:
if current_wave_length > 1:
waves_greater_than_one += 1
current_wave_length = 0

# Calculate the length of our current betrayal streak
consecutive_our_defections = 0
for i in range(len(self.history) - 1, -1, -1):
if self.history[i] == axl.Action.D:
consecutive_our_defections += 1
else:
break

# Calculate the length of the opponent's current betrayal streak
consecutive_opp_defections = 0
for i in range(len(opponent.history) - 1, -1, -1):
if opponent.history[i] == axl.Action.D:
consecutive_opp_defections += 1
else:
break

# Decision rules
if consecutive_opp_defections >= 2:
return D

if consecutive_our_defections > 0 and consecutive_our_defections < waves_greater_than_one:
return D

return C
34 changes: 34 additions & 0 deletions axelrod/tests/strategies/test_four_duality_optimizer.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
"""Tests for the FourDualityOptimizer strategy."""

import axelrod as axl

from .test_player import TestPlayer

C, D = axl.Action.C, axl.Action.D


class TestFourDualityOptimizer1(TestPlayer):

name = "4-Duality Optimizer 1"
player = axl.FourDualityOptimizer1
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), (C, C)] + [(C, C)] * 20
self.versus_test(axl.Cooperator(), expected_actions=actions)

actions = [(C, C), (C, C)] + [(C, C)] * 20
self.versus_test(axl.TitForTat(), expected_actions=actions)

actions = [(C, C), (C, C)] + [(C, C)] * 20
self.versus_test(axl.Retaliate(), expected_actions=actions)

2 changes: 2 additions & 0 deletions docs/reference/strategy_index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ Here are the docstrings of all the strategies in the library.
:members:
.. automodule:: axelrod.strategies.forgiver
:members:
.. automodule:: axelrod.strategies.four_duality_optimizer
:members:
.. automodule:: axelrod.strategies.frequency_analyzer
:members:
.. automodule:: axelrod.strategies.gambler
Expand Down
Loading