diff --git a/axelrod/strategies/_strategies.py b/axelrod/strategies/_strategies.py index bc80eeccc..85112f585 100644 --- a/axelrod/strategies/_strategies.py +++ b/axelrod/strategies/_strategies.py @@ -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, diff --git a/axelrod/strategies/four_duality_optimizer.py b/axelrod/strategies/four_duality_optimizer.py new file mode 100644 index 000000000..ec4271547 --- /dev/null +++ b/axelrod/strategies/four_duality_optimizer.py @@ -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 diff --git a/axelrod/tests/strategies/test_four_duality_optimizer.py b/axelrod/tests/strategies/test_four_duality_optimizer.py new file mode 100644 index 000000000..daf8d9444 --- /dev/null +++ b/axelrod/tests/strategies/test_four_duality_optimizer.py @@ -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) + diff --git a/docs/reference/strategy_index.rst b/docs/reference/strategy_index.rst index 9764d3082..02c3670d0 100644 --- a/docs/reference/strategy_index.rst +++ b/docs/reference/strategy_index.rst @@ -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