From b940b395a724a3f761d5fe5b813821649b34d986 Mon Sep 17 00:00:00 2001 From: Vince Knight Date: Mon, 6 Apr 2020 14:01:20 +0100 Subject: [PATCH 01/20] Add github actions and remove travis Note that I've removed hypothesis from the requirements. As is, to pip install axelrod also installs hypothesis which is silly. --- .github/workflows/config.yml | 52 ++++++++++++++++++++++++++++++++++++ .travis.yml | 38 -------------------------- appveyor.yml | 1 + requirements.txt | 1 - 4 files changed, 53 insertions(+), 39 deletions(-) create mode 100644 .github/workflows/config.yml delete mode 100644 .travis.yml diff --git a/.github/workflows/config.yml b/.github/workflows/config.yml new file mode 100644 index 000000000..a3376fd14 --- /dev/null +++ b/.github/workflows/config.yml @@ -0,0 +1,52 @@ +name: CI + +on: [push, pull_request] + +jobs: + build: + + runs-on: ${{ matrix.os }} + strategy: + max-parallel: 4 + matrix: + os: [ubuntu-latest, windows-latest] + python-version: [3.6, 3.7] + + steps: + - uses: actions/checkout@v1 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v1 + with: + python-version: ${{ matrix.python-version }} + - name: Install dependencies + run: | + python -m pip install --upgrade pip + python -m pip install -r requirements.txt + - name: Check that documentation builds + run: | + python -m pip install sphinx + python -m pip install sphinx_rtd_theme + python -m pip install docutils==0.12 + python -m pip install mock + cd docs; make clean; make html; cd ..; + - name: Install testing dependencies + run: | + python -m pip install coverage + python -m pip install hypothesis==3.2 + python -m pip install mypy + - name: Run tests and coverage + run: | + coverage run --source=axelrod -m unittest discover + coverage report -m --fail-under=100 + - name: Run doctest + run: | + python doctests.py + - name: Run static type checker + run: | + python run_mypy.py + - name: Check that all strategies are indexed + run: | + python run_strategy_indexer.py + - name: Check that installs + run: | + python setup.py install diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 4374c83e1..000000000 --- a/.travis.yml +++ /dev/null @@ -1,38 +0,0 @@ -dist: xenial -services: - - xvfb -language: python -python: - - 3.7 - - 3.6 -cache: - directories: - - $TRAVIS_BUILD_DIR/.hypothesis -install: - - pip install -r requirements.txt - - pip install sphinx - - pip install sphinx_rtd_theme - - pip install docutils==0.12 - - pip install coverage - - pip install coveralls - - pip install mypy -script: - # Build the documentation - - cd docs; make clean; make html - # Run the test suit with coverage - - cd .. - - travis_wait 60 coverage run --source=axelrod -m unittest discover - - coverage report -m - # Run the doctests - - python doctests.py - # Run the type checker - - python run_mypy.py - # Check that all strategies are in the index - - python run_strategy_indexer.py -after_success: - - coveralls -notifications: - webhooks: - urls: - - https://webhooks.gitter.im/e/3cc093037c0df458209d - diff --git a/appveyor.yml b/appveyor.yml index 30632d49d..c182913ae 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -5,6 +5,7 @@ environment: install: - "%PYTHON%\\python.exe --version" - "%PYTHON%\\python.exe -m pip install -r requirements.txt" + - "%PYTHON%\\python.exe -m pip install hypothesis==3.2" build: off test_script: - "%PYTHON%\\python.exe -m unittest discover" diff --git a/requirements.txt b/requirements.txt index 5c3b872b2..c78a85a18 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,7 +1,6 @@ cloudpickle>=0.2.1 fsspec>=0.4.3 dask>=2.3.0 -hypothesis==3.2 matplotlib>=2.0.0 numpy>=1.9.2 pandas>=0.18.1 From 9c59b207671819fb01ea61eab39d3cc060807aeb Mon Sep 17 00:00:00 2001 From: Vince Knight Date: Mon, 6 Apr 2020 16:23:57 +0100 Subject: [PATCH 02/20] Add an error so docs do not build. --- docs/reference/play_contexts.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/reference/play_contexts.rst b/docs/reference/play_contexts.rst index 67888e747..d6782920e 100644 --- a/docs/reference/play_contexts.rst +++ b/docs/reference/play_contexts.rst @@ -6,7 +6,7 @@ Play Contexts and Generic Prisoner's Dilemma There are four possible round outcomes: - Mutual cooperation: :math:`(C, C)` -- Defection: :math:`(C, D)` or :math:`(D, C)` +- Defection: :math`(C, D)` or :math:`(D, C)` - Mutual defection: :math:`(D, D)` Each of these corresponds to one particular set of payoffs in the following @@ -15,7 +15,7 @@ generic Prisoner's dilemma: +----------+---------------+---------------+ | | Cooperate | Defect | -+==========+===============+===============+ ++========+===============+===============+ |Cooperate | (R,R) | (S,T) | +----------+---------------+---------------+ |Defect | (T,S) | (P,P) | From 46bf99076ce0f115930f8e03bf74de1f982755ff Mon Sep 17 00:00:00 2001 From: Vince Knight Date: Mon, 6 Apr 2020 16:35:51 +0100 Subject: [PATCH 03/20] Revert "Add an error so docs do not build." This reverts commit 9c59b207671819fb01ea61eab39d3cc060807aeb. --- docs/reference/play_contexts.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/reference/play_contexts.rst b/docs/reference/play_contexts.rst index d6782920e..67888e747 100644 --- a/docs/reference/play_contexts.rst +++ b/docs/reference/play_contexts.rst @@ -6,7 +6,7 @@ Play Contexts and Generic Prisoner's Dilemma There are four possible round outcomes: - Mutual cooperation: :math:`(C, C)` -- Defection: :math`(C, D)` or :math:`(D, C)` +- Defection: :math:`(C, D)` or :math:`(D, C)` - Mutual defection: :math:`(D, D)` Each of these corresponds to one particular set of payoffs in the following @@ -15,7 +15,7 @@ generic Prisoner's dilemma: +----------+---------------+---------------+ | | Cooperate | Defect | -+========+===============+===============+ ++==========+===============+===============+ |Cooperate | (R,R) | (S,T) | +----------+---------------+---------------+ |Defect | (T,S) | (P,P) | From 20aa7b0671b9b7c889db559c93c3b07970cb1ae1 Mon Sep 17 00:00:00 2001 From: Vince Knight Date: Mon, 6 Apr 2020 16:36:20 +0100 Subject: [PATCH 04/20] Add an error so unit tests fail. --- axelrod/tests/unit/test_match.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/axelrod/tests/unit/test_match.py b/axelrod/tests/unit/test_match.py index 71913d103..e6fcc8f6d 100644 --- a/axelrod/tests/unit/test_match.py +++ b/axelrod/tests/unit/test_match.py @@ -21,7 +21,7 @@ def test_init(self, turns, game): self.assertEqual(match.result, []) self.assertEqual(match.players, [p1, p2]) self.assertEqual(match.turns, turns) - self.assertEqual(match.prob_end, 0) + self.assertEqual(match.prob_end, "foo") self.assertEqual(match.noise, 0) self.assertEqual(match.game.RPST(), game.RPST()) From fd3456eb431552fd881ace97251343d53815a481 Mon Sep 17 00:00:00 2001 From: Vince Knight Date: Mon, 6 Apr 2020 18:09:09 +0100 Subject: [PATCH 05/20] Revert "Add an error so unit tests fail." This reverts commit 20aa7b0671b9b7c889db559c93c3b07970cb1ae1. --- axelrod/tests/unit/test_match.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/axelrod/tests/unit/test_match.py b/axelrod/tests/unit/test_match.py index e6fcc8f6d..71913d103 100644 --- a/axelrod/tests/unit/test_match.py +++ b/axelrod/tests/unit/test_match.py @@ -21,7 +21,7 @@ def test_init(self, turns, game): self.assertEqual(match.result, []) self.assertEqual(match.players, [p1, p2]) self.assertEqual(match.turns, turns) - self.assertEqual(match.prob_end, "foo") + self.assertEqual(match.prob_end, 0) self.assertEqual(match.noise, 0) self.assertEqual(match.game.RPST(), game.RPST()) From 386f4cd28c292e7e2d7aa5ea9e1f3d4f56b800de Mon Sep 17 00:00:00 2001 From: Vince Knight Date: Mon, 6 Apr 2020 18:09:54 +0100 Subject: [PATCH 06/20] Remove unit tests so coverage fails. --- axelrod/tests/strategies/test_titfortat.py | 1169 -------------------- 1 file changed, 1169 deletions(-) diff --git a/axelrod/tests/strategies/test_titfortat.py b/axelrod/tests/strategies/test_titfortat.py index b04c7f049..38a3daa89 100644 --- a/axelrod/tests/strategies/test_titfortat.py +++ b/axelrod/tests/strategies/test_titfortat.py @@ -68,1172 +68,3 @@ def test_strategy(self): opponent = axl.MockPlayer(actions=[C, C, D, D, C, D]) actions = [(C, C), (C, C), (C, D), (D, D), (D, C), (C, D)] self.versus_test(opponent, expected_actions=actions) - - -class TestTitFor2Tats(TestPlayer): - - name = "Tit For 2 Tats" - player = axl.TitFor2Tats - expected_classifier = { - "memory_depth": 2, - "stochastic": False, - "makes_use_of": set(), - "inspects_source": False, - "manipulates_source": False, - "manipulates_state": False, - } - - def test_strategy(self): - # Will punish sequence of 2 defections but will forgive one - opponent = axl.MockPlayer(actions=[D, D, D, C, C]) - actions = [(C, D), (C, D), (D, D), (D, C), (C, C), (C, D)] - self.versus_test(opponent, expected_actions=actions) - opponent = axl.MockPlayer(actions=[C, C, D, D, C, D, D, C, C, D, D]) - actions = [ - (C, C), - (C, C), - (C, D), - (C, D), - (D, C), - (C, D), - (C, D), - (D, C), - (C, C), - (C, D), - (C, D), - ] - self.versus_test(opponent, expected_actions=actions) - - -class TestTwoTitsForTat(TestPlayer): - - name = "Two Tits For Tat" - player = axl.TwoTitsForTat - expected_classifier = { - "memory_depth": 2, - "stochastic": False, - "makes_use_of": set(), - "inspects_source": False, - "manipulates_source": False, - "manipulates_state": False, - } - - def test_strategy(self): - # Will defect twice when last turn of opponent was defection. - opponent = axl.MockPlayer(actions=[D, C, C, D, C]) - actions = [(C, D), (D, C), (D, C), (C, D), (D, C)] - self.versus_test(opponent, expected_actions=actions) - - actions = [(C, C), (C, C)] - self.versus_test(opponent=axl.Cooperator(), expected_actions=actions) - - actions = [(C, D), (D, D), (D, D)] - self.versus_test(opponent=axl.Defector(), expected_actions=actions) - - -class TestDynamicTwoTitsForTat(TestPlayer): - - name = "Dynamic Two Tits For Tat" - player = axl.DynamicTwoTitsForTat - expected_classifier = { - "memory_depth": float("inf"), - "stochastic": True, - "makes_use_of": set(), - "inspects_source": False, - "manipulates_source": False, - "manipulates_state": False, - } - - def test_strategy(self): - # Test that it is stochastic - opponent = axl.MockPlayer(actions=[D, C, D, D, C]) - actions = [(C, D), (D, C), (C, D), (D, D), (D, C)] - self.versus_test(opponent, expected_actions=actions, seed=1) - # Should respond differently with a different seed - actions = [(C, D), (D, C), (D, D), (D, D), (C, C)] - self.versus_test(opponent, expected_actions=actions, seed=2) - - # Will cooperate if opponent cooperates. - actions = [(C, C), (C, C), (C, C), (C, C), (C, C)] - self.versus_test(axl.Cooperator(), expected_actions=actions) - # Test against defector - actions = [(C, D), (D, D), (D, D), (D, D), (D, D)] - self.versus_test(axl.Defector(), expected_actions=actions) - - -class TestBully(TestPlayer): - - name = "Bully" - player = axl.Bully - expected_classifier = { - "memory_depth": 1, - "stochastic": False, - "makes_use_of": set(), - "inspects_source": False, - "manipulates_source": False, - "manipulates_state": False, - } - - def test_strategy(self): - # Will do opposite of what opponent does. - actions = [(D, C), (D, D), (C, C), (D, D), (C, C)] - self.versus_test(axl.Alternator(), expected_actions=actions) - - actions = [(D, C), (D, C), (D, C), (D, C), (D, C)] - self.versus_test(axl.Cooperator(), expected_actions=actions) - - actions = [(D, D), (C, D), (C, D), (C, D), (C, D)] - self.versus_test(axl.Defector(), expected_actions=actions) - - -class TestSneakyTitForTat(TestPlayer): - - name = "Sneaky Tit For Tat" - player = axl.SneakyTitForTat - expected_classifier = { - "memory_depth": float("inf"), # Long memory - "stochastic": False, - "makes_use_of": set(), - "inspects_source": False, - "manipulates_source": False, - "manipulates_state": False, - } - - def test_strategy(self): - opponent = axl.MockPlayer(actions=[C, C, C, D, C, C]) - actions = [(C, C), (C, C), (D, C), (D, D), (C, C), (C, C)] - self.versus_test(opponent, expected_actions=actions) - - # Repents if punished for a defection - actions = [(C, C), (C, D), (D, C), (C, D), (C, C)] - self.versus_test(axl.Alternator(), expected_actions=actions) - - -class TestSuspiciousTitForTat(TestPlayer): - - name = "Suspicious Tit For Tat" - player = axl.SuspiciousTitForTat - expected_classifier = { - "memory_depth": 1, # Four-Vector = (1.,0.,1.,0.) - "stochastic": False, - "makes_use_of": set(), - "inspects_source": False, - "manipulates_source": False, - "manipulates_state": False, - } - - def test_strategy(self): - # Plays like TFT after the first move, repeating the opponents last - # move. - actions = [(D, C), (C, D)] * 8 - self.versus_test(axl.TitForTat(), expected_actions=actions) - - actions = [(D, C), (C, C), (C, C)] - self.versus_test(axl.Cooperator(), expected_actions=actions) - - actions = [(D, D), (D, D), (D, D)] - self.versus_test(axl.Defector(), expected_actions=actions) - - -class TestAntiTitForTat(TestPlayer): - - name = "Anti Tit For Tat" - player = axl.AntiTitForTat - expected_classifier = { - "memory_depth": 1, # Four-Vector = (1.,0.,1.,0.) - "stochastic": False, - "makes_use_of": set(), - "inspects_source": False, - "manipulates_source": False, - "manipulates_state": False, - } - - def test_strategy(self): - actions = [(C, C), (D, C), (D, D), (C, D)] * 4 - self.versus_test(axl.TitForTat(), expected_actions=actions) - - -class TestHardTitForTat(TestPlayer): - - name = "Hard Tit For Tat" - player = axl.HardTitForTat - expected_classifier = { - "memory_depth": 3, - "stochastic": False, - "makes_use_of": set(), - "inspects_source": False, - "manipulates_source": False, - "manipulates_state": False, - } - - def test_strategy(self): - opponent = axl.MockPlayer(actions=[D, C, C, C, D, C]) - actions = [(C, D), (D, C), (D, C), (D, C), (C, D), (D, C)] - self.versus_test(opponent, expected_actions=actions) - - actions = [(C, C), (C, C), (C, C)] - self.versus_test(axl.Cooperator(), expected_actions=actions) - - actions = [(C, D), (D, D), (D, D)] - self.versus_test(axl.Defector(), expected_actions=actions) - - -class TestHardTitFor2Tats(TestPlayer): - - name = "Hard Tit For 2 Tats" - player = axl.HardTitFor2Tats - expected_classifier = { - "memory_depth": 3, - "stochastic": False, - "makes_use_of": set(), - "inspects_source": False, - "manipulates_source": False, - "manipulates_state": False, - } - - def test_strategy(self): - # Uses memory 3 to punish 2 consecutive defections - opponent = axl.MockPlayer(actions=[D, C, C, D, D, D, C]) - actions = [(C, D), (C, C), (C, C), (C, D), (C, D), (D, D), (D, C)] - self.versus_test(opponent, expected_actions=actions) - - -class TestOmegaTFT(TestPlayer): - - name = "Omega TFT: 3, 8" - player = axl.OmegaTFT - - expected_classifier = { - "memory_depth": float("inf"), - "stochastic": False, - "makes_use_of": set(), - "inspects_source": False, - "manipulates_source": False, - "manipulates_state": False, - } - - def test_strategy(self): - player_history = [C, D, C, D, C, C, C, C, C] - opp_history = [D, C, D, C, D, C, C, C, C] - actions = list(zip(player_history, opp_history)) - self.versus_test(axl.SuspiciousTitForTat(), expected_actions=actions) - - player_history = [C, C, D, C, D, C, C, C, D, D, D, D, D, D] - opp_history = [C, D] * 7 - actions = list(zip(player_history, opp_history)) - self.versus_test(axl.Alternator(), expected_actions=actions) - - -class TestGradual(TestPlayer): - - name = "Gradual" - player = axl.Gradual - expected_classifier = { - "memory_depth": float("inf"), - "stochastic": False, - "makes_use_of": set(), - "inspects_source": False, - "manipulates_source": False, - "manipulates_state": False, - } - - def test_strategy(self): - # Punishes defection with a growing number of defections and calms - # the opponent with two cooperations in a row. - opponent = axl.MockPlayer(actions=[C]) - actions = [(C, C)] - self.versus_test( - opponent, - expected_actions=actions, - attrs={ - "calm_count": 0, - "punish_count": 0, - }, - ) - - opponent = axl.MockPlayer(actions=[D]) - actions = [(C, D)] - self.versus_test( - opponent, - expected_actions=actions, - attrs={ - "calm_count": 0, - "punish_count": 0, - }, - ) - - opponent = axl.MockPlayer(actions=[D, C]) - actions = [(C, D), (D, C)] - self.versus_test( - opponent, - expected_actions=actions, - attrs={ - "calm_count": 2, - "punish_count": 0, - }, - ) - - opponent = axl.MockPlayer(actions=[D, C, C]) - actions = [(C, D), (D, C), (C, C)] - self.versus_test( - opponent, - expected_actions=actions, - attrs={ - "calm_count": 1, - "punish_count": 0, - }, - ) - - opponent = axl.MockPlayer(actions=[D, C, D, C]) - actions = [(C, D), (D, C), (C, D), (C, C)] - self.versus_test( - opponent, - expected_actions=actions, - attrs={ - "calm_count": 0, - "punish_count": 0, - }, - ) - - opponent = axl.MockPlayer(actions=[D, C, D, C, C]) - actions = [(C, D), (D, C), (C, D), (C, C), (C, C)] - self.versus_test( - opponent, - expected_actions=actions, - attrs={ - "calm_count": 0, - "punish_count": 0, - }, - ) - - opponent = axl.MockPlayer(actions=[D, C, D, C, C, C]) - actions = [(C, D), (D, C), (C, D), (C, C), (C, C), (C, C)] - self.versus_test( - opponent, - expected_actions=actions, - attrs={ - "calm_count": 0, - "punish_count": 0, - }, - ) - - opponent = axl.MockPlayer(actions=[D, C, D, C, C, C, D, C]) - actions = [(C, D), (D, C), (C, D), (C, C), (C, C), (C, C), (C, D), (D, C)] - self.versus_test( - opponent, - expected_actions=actions, - attrs={ - "calm_count": 2, - "punish_count": 2, - }, - ) - - opponent = axl.MockPlayer(actions=[D, C, D, C, C, D, D, D]) - actions = [(C, D), (D, C), (C, D), (C, C), (C, C), (C, D), (D, D), (D, D)] - self.versus_test( - opponent, - expected_actions=actions, - attrs={ - "calm_count": 2, - "punish_count": 1, - }, - ) - - opponent = axl.Defector() - actions = [ - (C, D), - (D, D), # 1 defection as a response to the 1 defection by opponent - (C, D), - (C, D), - (D, D), # starts defecting after a total of 4 defections by the opponent - (D, D), - (D, D), - (D, D), # 4 defections - (C, D), - (C, D), - (D, D), # Start defecting after a total of 10 defections by the opponent - (D, D), - (D, D), - (D, D), - (D, D), - (D, D), - (D, D), - (D, D), - (D, D), - (D, D), # 10 defections - (C, D), - (C, D), - (D, D), # starts defecting after 22 defections by the opponent - (D, D), - (D, D), - (D, D), - (D, D), - (D, D), - (D, D), - (D, D), - (D, D), - (D, D), - (D, D), - (D, D), - (D, D), - (D, D), - (D, D), - (D, D), - (D, D), - (D, D), - (D, D), - (D, D), - (D, D), - (D, D), # 22 defections - (C, D), - (C, D), - (D, D), - (D, D), - (D, D), - (D, D), - ] - self.versus_test( - opponent, - expected_actions=actions, - attrs={ - "calm_count": 2, - "punish_count": 42, - }, - ) - - def test_specific_set_of_results(self): - """ - This tests specific reported results as discussed in - https://github.com/Axelrod-Python/Axelrod/issues/1294 - - The results there used a version of mistrust with a bug that corresponds - to a memory one player that start by defecting and only cooperates if - both players cooperated in the previous round. - """ - mistrust_with_bug = axl.MemoryOnePlayer( - initial=D, - four_vector=(1, 0, 0, 0), - ) - players = [ - self.player(), - axl.TitForTat(), - axl.GoByMajority(), - axl.Grudger(), - axl.WinStayLoseShift(), - axl.Prober(), - axl.Defector(), - mistrust_with_bug, - axl.Cooperator(), - axl.CyclerCCD(), - axl.CyclerDDC(), - ] - axl.seed(1) - tournament = axl.Tournament(players, turns=1000, repetitions=1) - results = tournament.play(progress_bar=False) - scores = [round(average_score_per_turn * 1000, 1) - for average_score_per_turn in results.payoff_matrix[0]] - expected_scores = [ - 3000.0, - 3000.0, - 3000.0, - 3000.0, - 3000.0, - 2999.0, - 983.0, - 983.0, - 3000.0, - 3596.0, - 2302.0, - ] - self.assertEqual(scores, expected_scores) - -class TestOriginalGradual(TestPlayer): - - name = "Original Gradual" - player = axl.OriginalGradual - expected_classifier = { - "memory_depth": float("inf"), - "stochastic": False, - "makes_use_of": set(), - "inspects_source": False, - "manipulates_source": False, - "manipulates_state": False, - } - - def test_strategy(self): - # Punishes defection with a growing number of defections and calms - # the opponent with two cooperations in a row. - opponent = axl.MockPlayer(actions=[C]) - actions = [(C, C)] - self.versus_test( - opponent, - expected_actions=actions, - attrs={ - "calming": False, - "punishing": False, - "punishment_count": 0, - "punishment_limit": 0, - }, - ) - - opponent = axl.MockPlayer(actions=[D]) - actions = [(C, D)] - self.versus_test( - opponent, - expected_actions=actions, - attrs={ - "calming": False, - "punishing": False, - "punishment_count": 0, - "punishment_limit": 0, - }, - ) - - opponent = axl.MockPlayer(actions=[D, C]) - actions = [(C, D), (D, C)] - self.versus_test( - opponent, - expected_actions=actions, - attrs={ - "calming": False, - "punishing": True, - "punishment_count": 1, - "punishment_limit": 1, - }, - ) - - opponent = axl.MockPlayer(actions=[D, C, C]) - actions = [(C, D), (D, C), (C, C)] - self.versus_test( - opponent, - expected_actions=actions, - attrs={ - "calming": True, - "punishing": False, - "punishment_count": 0, - "punishment_limit": 1, - }, - ) - - opponent = axl.MockPlayer(actions=[D, C, D, C]) - actions = [(C, D), (D, C), (C, D), (C, C)] - self.versus_test( - opponent, - expected_actions=actions, - attrs={ - "calming": False, - "punishing": False, - "punishment_count": 0, - "punishment_limit": 1, - }, - ) - - opponent = axl.MockPlayer(actions=[D, C, D, C, C]) - actions = [(C, D), (D, C), (C, D), (C, C), (C, C)] - self.versus_test( - opponent, - expected_actions=actions, - attrs={ - "calming": False, - "punishing": False, - "punishment_count": 0, - "punishment_limit": 1, - }, - ) - - opponent = axl.MockPlayer(actions=[D, C, D, C, C, C]) - actions = [(C, D), (D, C), (C, D), (C, C), (C, C), (C, C)] - self.versus_test( - opponent, - expected_actions=actions, - attrs={ - "calming": False, - "punishing": False, - "punishment_count": 0, - "punishment_limit": 1, - }, - ) - - opponent = axl.MockPlayer(actions=[D, C, D, C, C, C, D, C]) - actions = [(C, D), (D, C), (C, D), (C, C), (C, C), (C, C), (C, D), (D, C)] - self.versus_test( - opponent, - expected_actions=actions, - attrs={ - "calming": False, - "punishing": True, - "punishment_count": 1, - "punishment_limit": 2, - }, - ) - - opponent = axl.MockPlayer(actions=[D, C, D, C, C, D, D, D]) - actions = [(C, D), (D, C), (C, D), (C, C), (C, C), (C, D), (D, D), (D, D)] - self.versus_test( - opponent, - expected_actions=actions, - attrs={ - "calming": False, - "punishing": True, - "punishment_count": 2, - "punishment_limit": 2, - }, - ) - - def test_output_from_literature(self): - """ - This strategy is not fully described in the literature, however the - scores for the strategy against a set of opponents is reported - - Bruno Beaufils, Jean-Paul Delahaye, Philippe Mathie - "Our Meeting With Gradual: A Good Strategy For The Iterated Prisoner's - Dilemma" Proc. Artif. Life 1996 - - This test just ensures that the strategy is as was originally defined. - - See https://github.com/Axelrod-Python/Axelrod/issues/1294 for another - discussion of this. - """ - players = [axl.Cooperator(), - axl.Defector(), - axl.Random(), - axl.TitForTat(), - axl.Grudger(), - axl.CyclerDDC(), - axl.CyclerCCD(), - axl.GoByMajority(), - axl.SuspiciousTitForTat(), - axl.Prober(), - self.player(), - axl.WinStayLoseShift(), - ] - - axl.seed(1) - turns = 1000 - tournament = axl.Tournament(players, turns=turns, repetitions=1) - results = tournament.play(progress_bar=False) - scores = [round(average_score_per_turn * 1000, 1) - for average_score_per_turn in results.payoff_matrix[-2]] - expected_scores = [ - 3000.0, - 915.0, - 2763.0, - 3000.0, - 3000.0, - 2219.0, - 3472.0, - 3000.0, - 2996.0, - 2999.0, - 3000.0, - 3000.0, - ] - self.assertEqual(scores, expected_scores) - - -class TestContriteTitForTat(TestPlayer): - - name = "Contrite Tit For Tat" - player = axl.ContriteTitForTat - expected_classifier = { - "memory_depth": 3, - "stochastic": False, - "makes_use_of": set(), - "inspects_source": False, - "manipulates_source": False, - "manipulates_state": False, - } - - deterministic_strategies = [ - s for s in axl.strategies if not s().classifier["stochastic"] - ] - - def test_init(self): - ctft = self.player() - self.assertFalse(ctft.contrite, False) - self.assertEqual(ctft._recorded_history, []) - - @given( - strategies=strategy_lists(strategies=deterministic_strategies, max_size=1), - turns=integers(min_value=1, max_value=20), - ) - def test_is_tit_for_tat_with_no_noise(self, strategies, turns): - tft = axl.TitForTat() - ctft = self.player() - opponent = strategies[0]() - m1 = axl.Match((tft, opponent), turns) - m2 = axl.Match((ctft, opponent), turns) - self.assertEqual(m1.play(), m2.play()) - - def test_strategy_with_noise(self): - ctft = self.player() - opponent = axl.Defector() - self.assertEqual(ctft.strategy(opponent), C) - self.assertEqual(ctft._recorded_history, [C]) - ctft.reset() # Clear the recorded history - self.assertEqual(ctft._recorded_history, []) - - random.seed(0) - ctft.play(opponent, noise=0.9) - self.assertEqual(ctft.history, [D]) - self.assertEqual(ctft._recorded_history, [C]) - self.assertEqual(opponent.history, [C]) - - # After noise: is contrite - ctft.play(opponent) - self.assertEqual(ctft.history, [D, C]) - self.assertEqual(ctft._recorded_history, [C, C]) - self.assertEqual(opponent.history, [C, D]) - self.assertTrue(ctft.contrite) - - # Cooperates and no longer contrite - ctft.play(opponent) - self.assertEqual(ctft.history, [D, C, C]) - self.assertEqual(ctft._recorded_history, [C, C, C]) - self.assertEqual(opponent.history, [C, D, D]) - self.assertFalse(ctft.contrite) - - # Goes back to playing tft - ctft.play(opponent) - self.assertEqual(ctft.history, [D, C, C, D]) - self.assertEqual(ctft._recorded_history, [C, C, C, D]) - self.assertEqual(opponent.history, [C, D, D, D]) - self.assertFalse(ctft.contrite) - - -class TestAdaptiveTitForTat(TestPlayer): - - name = "Adaptive Tit For Tat: 0.5" - player = axl.AdaptiveTitForTat - expected_classifier = { - "memory_depth": float("inf"), - "stochastic": False, - "makes_use_of": set(), - "inspects_source": False, - "manipulates_source": False, - "manipulates_state": False, - } - - def test_strategy(self): - actions = [(C, C), (C, D), (D, C), (C, D), (D, C)] - self.versus_test( - axl.Alternator(), - expected_actions=actions, - attrs={"world": 0.34375, "rate": 0.5}, - ) - - -class TestSpitefulTitForTat(TestPlayer): - name = "Spiteful Tit For Tat" - player = axl.SpitefulTitForTat - expected_classifier = { - "memory_depth": float("inf"), - "stochastic": False, - "makes_use_of": set(), - "inspects_source": False, - "manipulates_source": False, - "manipulates_state": False, - } - - def test_strategy(self): - # Repeats last action of opponent history until 2 consecutive - # defections, then always defects - opponent = axl.MockPlayer(actions=[C, C, C, C]) - actions = [(C, C)] * 5 - self.versus_test( - opponent, expected_actions=actions, attrs={"retaliating": False} - ) - - opponent = axl.MockPlayer(actions=[C, C, C, C, D, C]) - actions = [(C, C)] * 4 + [(C, D), (D, C), (C, C)] - self.versus_test( - opponent, expected_actions=actions, attrs={"retaliating": False} - ) - - opponent = axl.MockPlayer(actions=[C, C, D, D, C]) - actions = [(C, C), (C, C), (C, D), (D, D), (D, C)] - self.versus_test( - opponent, expected_actions=actions, attrs={"retaliating": True} - ) - - -class TestSlowTitForTwoTats2(TestPlayer): - - name = "Slow Tit For Two Tats 2" - player = axl.SlowTitForTwoTats2 - expected_classifier = { - "memory_depth": 2, - "stochastic": False, - "makes_use_of": set(), - "inspects_source": False, - "manipulates_source": False, - "manipulates_state": False, - } - - def test_strategy(self): - # If opponent plays the same move twice, repeats last action of - # opponent history, otherwise repeats previous move. - opponent = axl.MockPlayer(actions=[C, C, D, D, C, D, D, C, C, D, D]) - actions = [ - (C, C), - (C, C), - (C, D), - (C, D), - (D, C), - (D, D), - (D, D), - (D, C), - (D, C), - (C, D), - (C, D), - ] - self.versus_test(opponent, expected_actions=actions) - - -class TestAlexei(TestPlayer): - """ - Tests for the Alexei strategy - """ - - name = "Alexei: (D,)" - player = axl.Alexei - expected_classifier = { - "memory_depth": float("inf"), - "stochastic": False, - "makes_use_of": {"length"}, - "inspects_source": False, - "manipulates_source": False, - "manipulates_state": False, - } - - def test_strategy(self): - actions = [(C, C), (C, C), (C, C), (C, C), (D, C)] - self.versus_test(axl.Cooperator(), expected_actions=actions) - - actions = [(C, D), (D, D), (D, D), (D, D), (D, D)] - self.versus_test(axl.Defector(), expected_actions=actions) - - actions = [(C, C), (C, D), (D, C), (C, D), (D, C), (C, D)] - self.versus_test( - axl.Alternator(), - expected_actions=actions, - match_attributes={"length": float("inf")}, - ) - - actions = [(C, C), (C, D), (D, C), (C, D), (D, C), (D, D)] - self.versus_test(axl.Alternator(), expected_actions=actions) - - opponent = axl.MockPlayer(actions=[C, C, D, D, C, D]) - actions = [(C, C), (C, C), (C, D), (D, D), (D, C), (D, D)] - self.versus_test(opponent, expected_actions=actions) - - -class TestEugineNier(TestPlayer): - """ - Tests for the Eugine Nier strategy - """ - - name = "EugineNier: (D,)" - player = axl.EugineNier - expected_classifier = { - "memory_depth": float("inf"), - "stochastic": False, - "makes_use_of": {"length"}, - "inspects_source": False, - "manipulates_source": False, - "manipulates_state": False, - } - - def test_strategy(self): - actions = [(C, C), (C, C), (C, C), (D, C)] - self.versus_test( - axl.Cooperator(), expected_actions=actions, attrs={"is_defector": False} - ) - - actions = [(C, C), (C, C), (C, C), (C, C)] - self.versus_test( - axl.Cooperator(), - expected_actions=actions, - attrs={"is_defector": False}, - match_attributes={"length": float("inf")}, - ) - - # Plays TfT and defects in last round - actions = [(C, C), (C, D), (D, C), (C, D), (D, C), (D, D)] - self.versus_test( - axl.Alternator(), expected_actions=actions, attrs={"is_defector": False} - ) - - actions = [(C, C), (C, D), (D, C), (C, D), (D, C), (C, D)] - self.versus_test( - axl.Alternator(), - expected_actions=actions, - attrs={"is_defector": False}, - match_attributes={"length": float("inf")}, - ) - - # Becomes defector after 5 defections - opponent = axl.MockPlayer(actions=[D, C, D, D, D, D, C, C]) - actions = [(C, D), (D, C), (C, D), (D, D), (D, D), (D, D), (D, C), (D, C)] - self.versus_test(opponent, expected_actions=actions) - - -class TestNTitsForMTats(TestPlayer): - """ - Tests for the N Tit(s) For M Tat(s) strategy - """ - - name = "N Tit(s) For M Tat(s): 3, 2" - player = axl.NTitsForMTats - expected_classifier = { - "memory_depth": 3, - "stochastic": False, - "makes_use_of": set(), - "long_run_time": False, - "inspects_source": False, - "manipulates_source": False, - "manipulates_state": False, - } - - expected_class_classifier = copy.copy(expected_classifier) - expected_class_classifier["memory_depth"] = float("inf") - - def test_strategy(self): - # TitForTat test_strategy - init_kwargs = {"N": 1, "M": 1} - actions = [(C, C), (C, D), (D, C), (C, D), (D, C)] - self.versus_test( - axl.Alternator(), expected_actions=actions, init_kwargs=init_kwargs - ) - actions = [(C, C), (C, C), (C, C), (C, C), (C, C)] - self.versus_test( - axl.Cooperator(), expected_actions=actions, init_kwargs=init_kwargs - ) - actions = [(C, D), (D, D), (D, D), (D, D), (D, D)] - self.versus_test( - axl.Defector(), expected_actions=actions, init_kwargs=init_kwargs - ) - actions = [(C, C), (C, D), (D, C), (C, D), (D, C)] - self.versus_test( - axl.Alternator(), - expected_actions=actions, - match_attributes={"length": float("inf")}, - init_kwargs=init_kwargs, - ) - actions = [(C, D), (D, D), (D, C), (C, C), (C, D)] - self.versus_test( - axl.Random(), expected_actions=actions, seed=0, init_kwargs=init_kwargs - ) - actions = [(C, C), (C, D), (D, D), (D, C)] - self.versus_test( - axl.Random(), expected_actions=actions, seed=1, init_kwargs=init_kwargs - ) - opponent = axl.MockPlayer(actions=[C, D]) - actions = [(C, C), (C, D), (D, C), (C, D)] - self.versus_test(opponent, expected_actions=actions, init_kwargs=init_kwargs) - opponent = axl.MockPlayer(actions=[C, C, D, D, C, D]) - actions = [(C, C), (C, C), (C, D), (D, D), (D, C), (C, D)] - self.versus_test(opponent, expected_actions=actions, init_kwargs=init_kwargs) - - # TitFor2Tats test_strategy - init_kwargs = {"N": 1, "M": 2} - opponent = axl.MockPlayer(actions=[D, D, D, C, C]) - actions = [(C, D), (C, D), (D, D), (D, C), (C, C), (C, D)] - self.versus_test(opponent, expected_actions=actions, init_kwargs=init_kwargs) - - # TwoTitsForTat test_strategy - init_kwargs = {"N": 2, "M": 1} - opponent = axl.MockPlayer(actions=[D, C, C, D, C]) - actions = [(C, D), (D, C), (D, C), (C, D), (D, C)] - self.versus_test(opponent, expected_actions=actions, init_kwargs=init_kwargs) - actions = [(C, C), (C, C)] - self.versus_test( - opponent=axl.Cooperator(), - expected_actions=actions, - init_kwargs=init_kwargs, - ) - actions = [(C, D), (D, D), (D, D)] - self.versus_test( - opponent=axl.Defector(), - expected_actions=actions, - init_kwargs=init_kwargs, - ) - - # Cooperator test_strategy - actions = [(C, C)] + [(C, D), (C, C)] * 9 - self.versus_test( - opponent=axl.Alternator(), - expected_actions=actions, - init_kwargs={"N": 0, "M": 1}, - ) - self.versus_test( - opponent=axl.Alternator(), - expected_actions=actions, - init_kwargs={"N": 0, "M": 5}, - ) - self.versus_test( - opponent=axl.Alternator(), - expected_actions=actions, - init_kwargs={"N": 0, "M": 0}, - ) - - # Defector test_strategy - actions = [(D, C)] + [(D, D), (D, C)] * 9 - self.versus_test( - opponent=axl.Alternator(), - expected_actions=actions, - init_kwargs={"N": 1, "M": 0}, - ) - self.versus_test( - opponent=axl.Alternator(), - expected_actions=actions, - init_kwargs={"N": 5, "M": 0}, - ) - - # Default init args - actions = [(C, C), (C, D), (C, D), (D, C), (D, C), (D, D), (C, C)] - opponent = axl.MockPlayer(actions=[acts[1] for acts in actions]) - self.versus_test(opponent=opponent, expected_actions=actions) - - def test_varying_memory_depth(self): - self.assertEqual(self.player(1, 1).classifier["memory_depth"], 1) - self.assertEqual(self.player(0, 3).classifier["memory_depth"], 3) - self.assertEqual(self.player(5, 3).classifier["memory_depth"], 5) - - -class TestMichaelos(TestPlayer): - """ - Tests for the Michaelos strategy - """ - - name = "Michaelos: (D,)" - player = axl.Michaelos - expected_classifier = { - "memory_depth": float("inf"), - "stochastic": True, - "makes_use_of": {"length"}, - "inspects_source": False, - "manipulates_source": False, - "manipulates_state": False, - } - - def test_strategy(self): - - actions = [(C, C), (C, C), (C, C), (D, C)] - self.versus_test( - axl.Cooperator(), - expected_actions=actions, - attrs={"is_defector": False}, - seed=2, - ) - - actions = [(C, C), (C, C), (C, C), (C, C)] - self.versus_test( - axl.Cooperator(), - expected_actions=actions, - attrs={"is_defector": False}, - match_attributes={"length": float("inf")}, - seed=2, - ) - - actions = [(C, D), (D, D), (D, D), (D, D)] - self.versus_test( - axl.Defector(), - expected_actions=actions, - attrs={"is_defector": False}, - seed=2, - ) - - actions = [(C, D), (D, D), (D, D), (D, D)] - self.versus_test( - axl.Defector(), - expected_actions=actions, - attrs={"is_defector": False}, - match_attributes={"length": float("inf")}, - seed=2, - ) - - # Chance of becoming a defector is 50% after (D, C) occurs. - actions = [(C, C), (C, D), (D, C), (C, D), (D, C)] - self.versus_test( - axl.Alternator(), - expected_actions=actions, - attrs={"is_defector": False}, - seed=3, - ) - - actions = [(C, C), (C, D), (D, C), (D, D), (D, C), (D, D), (D, C)] - self.versus_test( - axl.Alternator(), - expected_actions=actions, - attrs={"is_defector": True}, - seed=2, - ) - - actions = [(C, C), (C, D), (D, C), (C, D), (D, C), (D, D), (D, C)] - self.versus_test( - axl.Alternator(), - expected_actions=actions, - attrs={"is_defector": True}, - match_attributes={"length": float("inf")}, - seed=1, - ) - - -class TestRandomTitForTat(TestPlayer): - """Tests for random tit for tat strategy.""" - - name = "Random Tit for Tat: 0.5" - player = axl.RandomTitForTat - expected_classifier = { - "memory_depth": 1, - "stochastic": True, - "makes_use_of": set(), - "long_run_time": False, - "inspects_source": False, - "manipulates_source": False, - "manipulates_state": False, - } - - def test_strategy(self): - """ - Test that strategy reacts to opponent, and controlled by - probability every other iteration. Also reacts randomly if no - probability input. - """ - actions = [(C, C), (C, C), (C, C)] - self.versus_test( - axl.Cooperator(), expected_actions=actions, init_kwargs={"p": 1} - ) - - actions = [(C, D), (D, D), (D, D)] - self.versus_test( - axl.Defector(), expected_actions=actions, init_kwargs={"p": 0} - ) - - actions = [(C, C), (C, C), (D, C), (C, C)] - self.versus_test( - axl.Cooperator(), expected_actions=actions, init_kwargs={"p": 0} - ) - - actions = [(C, D), (D, D), (C, D), (D, D)] - self.versus_test( - axl.Defector(), expected_actions=actions, init_kwargs={"p": 1} - ) - - actions = [(C, C), (C, C), (D, C), (C, C), (D, C), (C, C)] - self.versus_test(axl.Cooperator(), expected_actions=actions, seed=2) - - actions = [(C, D), (D, D), (C, D), (D, D), (D, D), (D, D)] - self.versus_test(axl.Defector(), expected_actions=actions, seed=1) - - def test_deterministic_classification(self): - """ - Test classification when probability input is 0 or 1. - Should change stochastic to false, because actions are no - longer random. - - """ - for p in [0, 1]: - player = axl.RandomTitForTat(p=p) - self.assertFalse(player.classifier["stochastic"]) From 5365f98d74a449b3b1af06acc32127ef2e65ecdf Mon Sep 17 00:00:00 2001 From: Vince Knight Date: Mon, 6 Apr 2020 18:54:56 +0100 Subject: [PATCH 07/20] Revert "Remove unit tests so coverage fails." This reverts commit 386f4cd28c292e7e2d7aa5ea9e1f3d4f56b800de. --- axelrod/tests/strategies/test_titfortat.py | 1169 ++++++++++++++++++++ 1 file changed, 1169 insertions(+) diff --git a/axelrod/tests/strategies/test_titfortat.py b/axelrod/tests/strategies/test_titfortat.py index 38a3daa89..b04c7f049 100644 --- a/axelrod/tests/strategies/test_titfortat.py +++ b/axelrod/tests/strategies/test_titfortat.py @@ -68,3 +68,1172 @@ def test_strategy(self): opponent = axl.MockPlayer(actions=[C, C, D, D, C, D]) actions = [(C, C), (C, C), (C, D), (D, D), (D, C), (C, D)] self.versus_test(opponent, expected_actions=actions) + + +class TestTitFor2Tats(TestPlayer): + + name = "Tit For 2 Tats" + player = axl.TitFor2Tats + expected_classifier = { + "memory_depth": 2, + "stochastic": False, + "makes_use_of": set(), + "inspects_source": False, + "manipulates_source": False, + "manipulates_state": False, + } + + def test_strategy(self): + # Will punish sequence of 2 defections but will forgive one + opponent = axl.MockPlayer(actions=[D, D, D, C, C]) + actions = [(C, D), (C, D), (D, D), (D, C), (C, C), (C, D)] + self.versus_test(opponent, expected_actions=actions) + opponent = axl.MockPlayer(actions=[C, C, D, D, C, D, D, C, C, D, D]) + actions = [ + (C, C), + (C, C), + (C, D), + (C, D), + (D, C), + (C, D), + (C, D), + (D, C), + (C, C), + (C, D), + (C, D), + ] + self.versus_test(opponent, expected_actions=actions) + + +class TestTwoTitsForTat(TestPlayer): + + name = "Two Tits For Tat" + player = axl.TwoTitsForTat + expected_classifier = { + "memory_depth": 2, + "stochastic": False, + "makes_use_of": set(), + "inspects_source": False, + "manipulates_source": False, + "manipulates_state": False, + } + + def test_strategy(self): + # Will defect twice when last turn of opponent was defection. + opponent = axl.MockPlayer(actions=[D, C, C, D, C]) + actions = [(C, D), (D, C), (D, C), (C, D), (D, C)] + self.versus_test(opponent, expected_actions=actions) + + actions = [(C, C), (C, C)] + self.versus_test(opponent=axl.Cooperator(), expected_actions=actions) + + actions = [(C, D), (D, D), (D, D)] + self.versus_test(opponent=axl.Defector(), expected_actions=actions) + + +class TestDynamicTwoTitsForTat(TestPlayer): + + name = "Dynamic Two Tits For Tat" + player = axl.DynamicTwoTitsForTat + expected_classifier = { + "memory_depth": float("inf"), + "stochastic": True, + "makes_use_of": set(), + "inspects_source": False, + "manipulates_source": False, + "manipulates_state": False, + } + + def test_strategy(self): + # Test that it is stochastic + opponent = axl.MockPlayer(actions=[D, C, D, D, C]) + actions = [(C, D), (D, C), (C, D), (D, D), (D, C)] + self.versus_test(opponent, expected_actions=actions, seed=1) + # Should respond differently with a different seed + actions = [(C, D), (D, C), (D, D), (D, D), (C, C)] + self.versus_test(opponent, expected_actions=actions, seed=2) + + # Will cooperate if opponent cooperates. + actions = [(C, C), (C, C), (C, C), (C, C), (C, C)] + self.versus_test(axl.Cooperator(), expected_actions=actions) + # Test against defector + actions = [(C, D), (D, D), (D, D), (D, D), (D, D)] + self.versus_test(axl.Defector(), expected_actions=actions) + + +class TestBully(TestPlayer): + + name = "Bully" + player = axl.Bully + expected_classifier = { + "memory_depth": 1, + "stochastic": False, + "makes_use_of": set(), + "inspects_source": False, + "manipulates_source": False, + "manipulates_state": False, + } + + def test_strategy(self): + # Will do opposite of what opponent does. + actions = [(D, C), (D, D), (C, C), (D, D), (C, C)] + self.versus_test(axl.Alternator(), expected_actions=actions) + + actions = [(D, C), (D, C), (D, C), (D, C), (D, C)] + self.versus_test(axl.Cooperator(), expected_actions=actions) + + actions = [(D, D), (C, D), (C, D), (C, D), (C, D)] + self.versus_test(axl.Defector(), expected_actions=actions) + + +class TestSneakyTitForTat(TestPlayer): + + name = "Sneaky Tit For Tat" + player = axl.SneakyTitForTat + expected_classifier = { + "memory_depth": float("inf"), # Long memory + "stochastic": False, + "makes_use_of": set(), + "inspects_source": False, + "manipulates_source": False, + "manipulates_state": False, + } + + def test_strategy(self): + opponent = axl.MockPlayer(actions=[C, C, C, D, C, C]) + actions = [(C, C), (C, C), (D, C), (D, D), (C, C), (C, C)] + self.versus_test(opponent, expected_actions=actions) + + # Repents if punished for a defection + actions = [(C, C), (C, D), (D, C), (C, D), (C, C)] + self.versus_test(axl.Alternator(), expected_actions=actions) + + +class TestSuspiciousTitForTat(TestPlayer): + + name = "Suspicious Tit For Tat" + player = axl.SuspiciousTitForTat + expected_classifier = { + "memory_depth": 1, # Four-Vector = (1.,0.,1.,0.) + "stochastic": False, + "makes_use_of": set(), + "inspects_source": False, + "manipulates_source": False, + "manipulates_state": False, + } + + def test_strategy(self): + # Plays like TFT after the first move, repeating the opponents last + # move. + actions = [(D, C), (C, D)] * 8 + self.versus_test(axl.TitForTat(), expected_actions=actions) + + actions = [(D, C), (C, C), (C, C)] + self.versus_test(axl.Cooperator(), expected_actions=actions) + + actions = [(D, D), (D, D), (D, D)] + self.versus_test(axl.Defector(), expected_actions=actions) + + +class TestAntiTitForTat(TestPlayer): + + name = "Anti Tit For Tat" + player = axl.AntiTitForTat + expected_classifier = { + "memory_depth": 1, # Four-Vector = (1.,0.,1.,0.) + "stochastic": False, + "makes_use_of": set(), + "inspects_source": False, + "manipulates_source": False, + "manipulates_state": False, + } + + def test_strategy(self): + actions = [(C, C), (D, C), (D, D), (C, D)] * 4 + self.versus_test(axl.TitForTat(), expected_actions=actions) + + +class TestHardTitForTat(TestPlayer): + + name = "Hard Tit For Tat" + player = axl.HardTitForTat + expected_classifier = { + "memory_depth": 3, + "stochastic": False, + "makes_use_of": set(), + "inspects_source": False, + "manipulates_source": False, + "manipulates_state": False, + } + + def test_strategy(self): + opponent = axl.MockPlayer(actions=[D, C, C, C, D, C]) + actions = [(C, D), (D, C), (D, C), (D, C), (C, D), (D, C)] + self.versus_test(opponent, expected_actions=actions) + + actions = [(C, C), (C, C), (C, C)] + self.versus_test(axl.Cooperator(), expected_actions=actions) + + actions = [(C, D), (D, D), (D, D)] + self.versus_test(axl.Defector(), expected_actions=actions) + + +class TestHardTitFor2Tats(TestPlayer): + + name = "Hard Tit For 2 Tats" + player = axl.HardTitFor2Tats + expected_classifier = { + "memory_depth": 3, + "stochastic": False, + "makes_use_of": set(), + "inspects_source": False, + "manipulates_source": False, + "manipulates_state": False, + } + + def test_strategy(self): + # Uses memory 3 to punish 2 consecutive defections + opponent = axl.MockPlayer(actions=[D, C, C, D, D, D, C]) + actions = [(C, D), (C, C), (C, C), (C, D), (C, D), (D, D), (D, C)] + self.versus_test(opponent, expected_actions=actions) + + +class TestOmegaTFT(TestPlayer): + + name = "Omega TFT: 3, 8" + player = axl.OmegaTFT + + expected_classifier = { + "memory_depth": float("inf"), + "stochastic": False, + "makes_use_of": set(), + "inspects_source": False, + "manipulates_source": False, + "manipulates_state": False, + } + + def test_strategy(self): + player_history = [C, D, C, D, C, C, C, C, C] + opp_history = [D, C, D, C, D, C, C, C, C] + actions = list(zip(player_history, opp_history)) + self.versus_test(axl.SuspiciousTitForTat(), expected_actions=actions) + + player_history = [C, C, D, C, D, C, C, C, D, D, D, D, D, D] + opp_history = [C, D] * 7 + actions = list(zip(player_history, opp_history)) + self.versus_test(axl.Alternator(), expected_actions=actions) + + +class TestGradual(TestPlayer): + + name = "Gradual" + player = axl.Gradual + expected_classifier = { + "memory_depth": float("inf"), + "stochastic": False, + "makes_use_of": set(), + "inspects_source": False, + "manipulates_source": False, + "manipulates_state": False, + } + + def test_strategy(self): + # Punishes defection with a growing number of defections and calms + # the opponent with two cooperations in a row. + opponent = axl.MockPlayer(actions=[C]) + actions = [(C, C)] + self.versus_test( + opponent, + expected_actions=actions, + attrs={ + "calm_count": 0, + "punish_count": 0, + }, + ) + + opponent = axl.MockPlayer(actions=[D]) + actions = [(C, D)] + self.versus_test( + opponent, + expected_actions=actions, + attrs={ + "calm_count": 0, + "punish_count": 0, + }, + ) + + opponent = axl.MockPlayer(actions=[D, C]) + actions = [(C, D), (D, C)] + self.versus_test( + opponent, + expected_actions=actions, + attrs={ + "calm_count": 2, + "punish_count": 0, + }, + ) + + opponent = axl.MockPlayer(actions=[D, C, C]) + actions = [(C, D), (D, C), (C, C)] + self.versus_test( + opponent, + expected_actions=actions, + attrs={ + "calm_count": 1, + "punish_count": 0, + }, + ) + + opponent = axl.MockPlayer(actions=[D, C, D, C]) + actions = [(C, D), (D, C), (C, D), (C, C)] + self.versus_test( + opponent, + expected_actions=actions, + attrs={ + "calm_count": 0, + "punish_count": 0, + }, + ) + + opponent = axl.MockPlayer(actions=[D, C, D, C, C]) + actions = [(C, D), (D, C), (C, D), (C, C), (C, C)] + self.versus_test( + opponent, + expected_actions=actions, + attrs={ + "calm_count": 0, + "punish_count": 0, + }, + ) + + opponent = axl.MockPlayer(actions=[D, C, D, C, C, C]) + actions = [(C, D), (D, C), (C, D), (C, C), (C, C), (C, C)] + self.versus_test( + opponent, + expected_actions=actions, + attrs={ + "calm_count": 0, + "punish_count": 0, + }, + ) + + opponent = axl.MockPlayer(actions=[D, C, D, C, C, C, D, C]) + actions = [(C, D), (D, C), (C, D), (C, C), (C, C), (C, C), (C, D), (D, C)] + self.versus_test( + opponent, + expected_actions=actions, + attrs={ + "calm_count": 2, + "punish_count": 2, + }, + ) + + opponent = axl.MockPlayer(actions=[D, C, D, C, C, D, D, D]) + actions = [(C, D), (D, C), (C, D), (C, C), (C, C), (C, D), (D, D), (D, D)] + self.versus_test( + opponent, + expected_actions=actions, + attrs={ + "calm_count": 2, + "punish_count": 1, + }, + ) + + opponent = axl.Defector() + actions = [ + (C, D), + (D, D), # 1 defection as a response to the 1 defection by opponent + (C, D), + (C, D), + (D, D), # starts defecting after a total of 4 defections by the opponent + (D, D), + (D, D), + (D, D), # 4 defections + (C, D), + (C, D), + (D, D), # Start defecting after a total of 10 defections by the opponent + (D, D), + (D, D), + (D, D), + (D, D), + (D, D), + (D, D), + (D, D), + (D, D), + (D, D), # 10 defections + (C, D), + (C, D), + (D, D), # starts defecting after 22 defections by the opponent + (D, D), + (D, D), + (D, D), + (D, D), + (D, D), + (D, D), + (D, D), + (D, D), + (D, D), + (D, D), + (D, D), + (D, D), + (D, D), + (D, D), + (D, D), + (D, D), + (D, D), + (D, D), + (D, D), + (D, D), + (D, D), # 22 defections + (C, D), + (C, D), + (D, D), + (D, D), + (D, D), + (D, D), + ] + self.versus_test( + opponent, + expected_actions=actions, + attrs={ + "calm_count": 2, + "punish_count": 42, + }, + ) + + def test_specific_set_of_results(self): + """ + This tests specific reported results as discussed in + https://github.com/Axelrod-Python/Axelrod/issues/1294 + + The results there used a version of mistrust with a bug that corresponds + to a memory one player that start by defecting and only cooperates if + both players cooperated in the previous round. + """ + mistrust_with_bug = axl.MemoryOnePlayer( + initial=D, + four_vector=(1, 0, 0, 0), + ) + players = [ + self.player(), + axl.TitForTat(), + axl.GoByMajority(), + axl.Grudger(), + axl.WinStayLoseShift(), + axl.Prober(), + axl.Defector(), + mistrust_with_bug, + axl.Cooperator(), + axl.CyclerCCD(), + axl.CyclerDDC(), + ] + axl.seed(1) + tournament = axl.Tournament(players, turns=1000, repetitions=1) + results = tournament.play(progress_bar=False) + scores = [round(average_score_per_turn * 1000, 1) + for average_score_per_turn in results.payoff_matrix[0]] + expected_scores = [ + 3000.0, + 3000.0, + 3000.0, + 3000.0, + 3000.0, + 2999.0, + 983.0, + 983.0, + 3000.0, + 3596.0, + 2302.0, + ] + self.assertEqual(scores, expected_scores) + +class TestOriginalGradual(TestPlayer): + + name = "Original Gradual" + player = axl.OriginalGradual + expected_classifier = { + "memory_depth": float("inf"), + "stochastic": False, + "makes_use_of": set(), + "inspects_source": False, + "manipulates_source": False, + "manipulates_state": False, + } + + def test_strategy(self): + # Punishes defection with a growing number of defections and calms + # the opponent with two cooperations in a row. + opponent = axl.MockPlayer(actions=[C]) + actions = [(C, C)] + self.versus_test( + opponent, + expected_actions=actions, + attrs={ + "calming": False, + "punishing": False, + "punishment_count": 0, + "punishment_limit": 0, + }, + ) + + opponent = axl.MockPlayer(actions=[D]) + actions = [(C, D)] + self.versus_test( + opponent, + expected_actions=actions, + attrs={ + "calming": False, + "punishing": False, + "punishment_count": 0, + "punishment_limit": 0, + }, + ) + + opponent = axl.MockPlayer(actions=[D, C]) + actions = [(C, D), (D, C)] + self.versus_test( + opponent, + expected_actions=actions, + attrs={ + "calming": False, + "punishing": True, + "punishment_count": 1, + "punishment_limit": 1, + }, + ) + + opponent = axl.MockPlayer(actions=[D, C, C]) + actions = [(C, D), (D, C), (C, C)] + self.versus_test( + opponent, + expected_actions=actions, + attrs={ + "calming": True, + "punishing": False, + "punishment_count": 0, + "punishment_limit": 1, + }, + ) + + opponent = axl.MockPlayer(actions=[D, C, D, C]) + actions = [(C, D), (D, C), (C, D), (C, C)] + self.versus_test( + opponent, + expected_actions=actions, + attrs={ + "calming": False, + "punishing": False, + "punishment_count": 0, + "punishment_limit": 1, + }, + ) + + opponent = axl.MockPlayer(actions=[D, C, D, C, C]) + actions = [(C, D), (D, C), (C, D), (C, C), (C, C)] + self.versus_test( + opponent, + expected_actions=actions, + attrs={ + "calming": False, + "punishing": False, + "punishment_count": 0, + "punishment_limit": 1, + }, + ) + + opponent = axl.MockPlayer(actions=[D, C, D, C, C, C]) + actions = [(C, D), (D, C), (C, D), (C, C), (C, C), (C, C)] + self.versus_test( + opponent, + expected_actions=actions, + attrs={ + "calming": False, + "punishing": False, + "punishment_count": 0, + "punishment_limit": 1, + }, + ) + + opponent = axl.MockPlayer(actions=[D, C, D, C, C, C, D, C]) + actions = [(C, D), (D, C), (C, D), (C, C), (C, C), (C, C), (C, D), (D, C)] + self.versus_test( + opponent, + expected_actions=actions, + attrs={ + "calming": False, + "punishing": True, + "punishment_count": 1, + "punishment_limit": 2, + }, + ) + + opponent = axl.MockPlayer(actions=[D, C, D, C, C, D, D, D]) + actions = [(C, D), (D, C), (C, D), (C, C), (C, C), (C, D), (D, D), (D, D)] + self.versus_test( + opponent, + expected_actions=actions, + attrs={ + "calming": False, + "punishing": True, + "punishment_count": 2, + "punishment_limit": 2, + }, + ) + + def test_output_from_literature(self): + """ + This strategy is not fully described in the literature, however the + scores for the strategy against a set of opponents is reported + + Bruno Beaufils, Jean-Paul Delahaye, Philippe Mathie + "Our Meeting With Gradual: A Good Strategy For The Iterated Prisoner's + Dilemma" Proc. Artif. Life 1996 + + This test just ensures that the strategy is as was originally defined. + + See https://github.com/Axelrod-Python/Axelrod/issues/1294 for another + discussion of this. + """ + players = [axl.Cooperator(), + axl.Defector(), + axl.Random(), + axl.TitForTat(), + axl.Grudger(), + axl.CyclerDDC(), + axl.CyclerCCD(), + axl.GoByMajority(), + axl.SuspiciousTitForTat(), + axl.Prober(), + self.player(), + axl.WinStayLoseShift(), + ] + + axl.seed(1) + turns = 1000 + tournament = axl.Tournament(players, turns=turns, repetitions=1) + results = tournament.play(progress_bar=False) + scores = [round(average_score_per_turn * 1000, 1) + for average_score_per_turn in results.payoff_matrix[-2]] + expected_scores = [ + 3000.0, + 915.0, + 2763.0, + 3000.0, + 3000.0, + 2219.0, + 3472.0, + 3000.0, + 2996.0, + 2999.0, + 3000.0, + 3000.0, + ] + self.assertEqual(scores, expected_scores) + + +class TestContriteTitForTat(TestPlayer): + + name = "Contrite Tit For Tat" + player = axl.ContriteTitForTat + expected_classifier = { + "memory_depth": 3, + "stochastic": False, + "makes_use_of": set(), + "inspects_source": False, + "manipulates_source": False, + "manipulates_state": False, + } + + deterministic_strategies = [ + s for s in axl.strategies if not s().classifier["stochastic"] + ] + + def test_init(self): + ctft = self.player() + self.assertFalse(ctft.contrite, False) + self.assertEqual(ctft._recorded_history, []) + + @given( + strategies=strategy_lists(strategies=deterministic_strategies, max_size=1), + turns=integers(min_value=1, max_value=20), + ) + def test_is_tit_for_tat_with_no_noise(self, strategies, turns): + tft = axl.TitForTat() + ctft = self.player() + opponent = strategies[0]() + m1 = axl.Match((tft, opponent), turns) + m2 = axl.Match((ctft, opponent), turns) + self.assertEqual(m1.play(), m2.play()) + + def test_strategy_with_noise(self): + ctft = self.player() + opponent = axl.Defector() + self.assertEqual(ctft.strategy(opponent), C) + self.assertEqual(ctft._recorded_history, [C]) + ctft.reset() # Clear the recorded history + self.assertEqual(ctft._recorded_history, []) + + random.seed(0) + ctft.play(opponent, noise=0.9) + self.assertEqual(ctft.history, [D]) + self.assertEqual(ctft._recorded_history, [C]) + self.assertEqual(opponent.history, [C]) + + # After noise: is contrite + ctft.play(opponent) + self.assertEqual(ctft.history, [D, C]) + self.assertEqual(ctft._recorded_history, [C, C]) + self.assertEqual(opponent.history, [C, D]) + self.assertTrue(ctft.contrite) + + # Cooperates and no longer contrite + ctft.play(opponent) + self.assertEqual(ctft.history, [D, C, C]) + self.assertEqual(ctft._recorded_history, [C, C, C]) + self.assertEqual(opponent.history, [C, D, D]) + self.assertFalse(ctft.contrite) + + # Goes back to playing tft + ctft.play(opponent) + self.assertEqual(ctft.history, [D, C, C, D]) + self.assertEqual(ctft._recorded_history, [C, C, C, D]) + self.assertEqual(opponent.history, [C, D, D, D]) + self.assertFalse(ctft.contrite) + + +class TestAdaptiveTitForTat(TestPlayer): + + name = "Adaptive Tit For Tat: 0.5" + player = axl.AdaptiveTitForTat + expected_classifier = { + "memory_depth": float("inf"), + "stochastic": False, + "makes_use_of": set(), + "inspects_source": False, + "manipulates_source": False, + "manipulates_state": False, + } + + def test_strategy(self): + actions = [(C, C), (C, D), (D, C), (C, D), (D, C)] + self.versus_test( + axl.Alternator(), + expected_actions=actions, + attrs={"world": 0.34375, "rate": 0.5}, + ) + + +class TestSpitefulTitForTat(TestPlayer): + name = "Spiteful Tit For Tat" + player = axl.SpitefulTitForTat + expected_classifier = { + "memory_depth": float("inf"), + "stochastic": False, + "makes_use_of": set(), + "inspects_source": False, + "manipulates_source": False, + "manipulates_state": False, + } + + def test_strategy(self): + # Repeats last action of opponent history until 2 consecutive + # defections, then always defects + opponent = axl.MockPlayer(actions=[C, C, C, C]) + actions = [(C, C)] * 5 + self.versus_test( + opponent, expected_actions=actions, attrs={"retaliating": False} + ) + + opponent = axl.MockPlayer(actions=[C, C, C, C, D, C]) + actions = [(C, C)] * 4 + [(C, D), (D, C), (C, C)] + self.versus_test( + opponent, expected_actions=actions, attrs={"retaliating": False} + ) + + opponent = axl.MockPlayer(actions=[C, C, D, D, C]) + actions = [(C, C), (C, C), (C, D), (D, D), (D, C)] + self.versus_test( + opponent, expected_actions=actions, attrs={"retaliating": True} + ) + + +class TestSlowTitForTwoTats2(TestPlayer): + + name = "Slow Tit For Two Tats 2" + player = axl.SlowTitForTwoTats2 + expected_classifier = { + "memory_depth": 2, + "stochastic": False, + "makes_use_of": set(), + "inspects_source": False, + "manipulates_source": False, + "manipulates_state": False, + } + + def test_strategy(self): + # If opponent plays the same move twice, repeats last action of + # opponent history, otherwise repeats previous move. + opponent = axl.MockPlayer(actions=[C, C, D, D, C, D, D, C, C, D, D]) + actions = [ + (C, C), + (C, C), + (C, D), + (C, D), + (D, C), + (D, D), + (D, D), + (D, C), + (D, C), + (C, D), + (C, D), + ] + self.versus_test(opponent, expected_actions=actions) + + +class TestAlexei(TestPlayer): + """ + Tests for the Alexei strategy + """ + + name = "Alexei: (D,)" + player = axl.Alexei + expected_classifier = { + "memory_depth": float("inf"), + "stochastic": False, + "makes_use_of": {"length"}, + "inspects_source": False, + "manipulates_source": False, + "manipulates_state": False, + } + + def test_strategy(self): + actions = [(C, C), (C, C), (C, C), (C, C), (D, C)] + self.versus_test(axl.Cooperator(), expected_actions=actions) + + actions = [(C, D), (D, D), (D, D), (D, D), (D, D)] + self.versus_test(axl.Defector(), expected_actions=actions) + + actions = [(C, C), (C, D), (D, C), (C, D), (D, C), (C, D)] + self.versus_test( + axl.Alternator(), + expected_actions=actions, + match_attributes={"length": float("inf")}, + ) + + actions = [(C, C), (C, D), (D, C), (C, D), (D, C), (D, D)] + self.versus_test(axl.Alternator(), expected_actions=actions) + + opponent = axl.MockPlayer(actions=[C, C, D, D, C, D]) + actions = [(C, C), (C, C), (C, D), (D, D), (D, C), (D, D)] + self.versus_test(opponent, expected_actions=actions) + + +class TestEugineNier(TestPlayer): + """ + Tests for the Eugine Nier strategy + """ + + name = "EugineNier: (D,)" + player = axl.EugineNier + expected_classifier = { + "memory_depth": float("inf"), + "stochastic": False, + "makes_use_of": {"length"}, + "inspects_source": False, + "manipulates_source": False, + "manipulates_state": False, + } + + def test_strategy(self): + actions = [(C, C), (C, C), (C, C), (D, C)] + self.versus_test( + axl.Cooperator(), expected_actions=actions, attrs={"is_defector": False} + ) + + actions = [(C, C), (C, C), (C, C), (C, C)] + self.versus_test( + axl.Cooperator(), + expected_actions=actions, + attrs={"is_defector": False}, + match_attributes={"length": float("inf")}, + ) + + # Plays TfT and defects in last round + actions = [(C, C), (C, D), (D, C), (C, D), (D, C), (D, D)] + self.versus_test( + axl.Alternator(), expected_actions=actions, attrs={"is_defector": False} + ) + + actions = [(C, C), (C, D), (D, C), (C, D), (D, C), (C, D)] + self.versus_test( + axl.Alternator(), + expected_actions=actions, + attrs={"is_defector": False}, + match_attributes={"length": float("inf")}, + ) + + # Becomes defector after 5 defections + opponent = axl.MockPlayer(actions=[D, C, D, D, D, D, C, C]) + actions = [(C, D), (D, C), (C, D), (D, D), (D, D), (D, D), (D, C), (D, C)] + self.versus_test(opponent, expected_actions=actions) + + +class TestNTitsForMTats(TestPlayer): + """ + Tests for the N Tit(s) For M Tat(s) strategy + """ + + name = "N Tit(s) For M Tat(s): 3, 2" + player = axl.NTitsForMTats + expected_classifier = { + "memory_depth": 3, + "stochastic": False, + "makes_use_of": set(), + "long_run_time": False, + "inspects_source": False, + "manipulates_source": False, + "manipulates_state": False, + } + + expected_class_classifier = copy.copy(expected_classifier) + expected_class_classifier["memory_depth"] = float("inf") + + def test_strategy(self): + # TitForTat test_strategy + init_kwargs = {"N": 1, "M": 1} + actions = [(C, C), (C, D), (D, C), (C, D), (D, C)] + self.versus_test( + axl.Alternator(), expected_actions=actions, init_kwargs=init_kwargs + ) + actions = [(C, C), (C, C), (C, C), (C, C), (C, C)] + self.versus_test( + axl.Cooperator(), expected_actions=actions, init_kwargs=init_kwargs + ) + actions = [(C, D), (D, D), (D, D), (D, D), (D, D)] + self.versus_test( + axl.Defector(), expected_actions=actions, init_kwargs=init_kwargs + ) + actions = [(C, C), (C, D), (D, C), (C, D), (D, C)] + self.versus_test( + axl.Alternator(), + expected_actions=actions, + match_attributes={"length": float("inf")}, + init_kwargs=init_kwargs, + ) + actions = [(C, D), (D, D), (D, C), (C, C), (C, D)] + self.versus_test( + axl.Random(), expected_actions=actions, seed=0, init_kwargs=init_kwargs + ) + actions = [(C, C), (C, D), (D, D), (D, C)] + self.versus_test( + axl.Random(), expected_actions=actions, seed=1, init_kwargs=init_kwargs + ) + opponent = axl.MockPlayer(actions=[C, D]) + actions = [(C, C), (C, D), (D, C), (C, D)] + self.versus_test(opponent, expected_actions=actions, init_kwargs=init_kwargs) + opponent = axl.MockPlayer(actions=[C, C, D, D, C, D]) + actions = [(C, C), (C, C), (C, D), (D, D), (D, C), (C, D)] + self.versus_test(opponent, expected_actions=actions, init_kwargs=init_kwargs) + + # TitFor2Tats test_strategy + init_kwargs = {"N": 1, "M": 2} + opponent = axl.MockPlayer(actions=[D, D, D, C, C]) + actions = [(C, D), (C, D), (D, D), (D, C), (C, C), (C, D)] + self.versus_test(opponent, expected_actions=actions, init_kwargs=init_kwargs) + + # TwoTitsForTat test_strategy + init_kwargs = {"N": 2, "M": 1} + opponent = axl.MockPlayer(actions=[D, C, C, D, C]) + actions = [(C, D), (D, C), (D, C), (C, D), (D, C)] + self.versus_test(opponent, expected_actions=actions, init_kwargs=init_kwargs) + actions = [(C, C), (C, C)] + self.versus_test( + opponent=axl.Cooperator(), + expected_actions=actions, + init_kwargs=init_kwargs, + ) + actions = [(C, D), (D, D), (D, D)] + self.versus_test( + opponent=axl.Defector(), + expected_actions=actions, + init_kwargs=init_kwargs, + ) + + # Cooperator test_strategy + actions = [(C, C)] + [(C, D), (C, C)] * 9 + self.versus_test( + opponent=axl.Alternator(), + expected_actions=actions, + init_kwargs={"N": 0, "M": 1}, + ) + self.versus_test( + opponent=axl.Alternator(), + expected_actions=actions, + init_kwargs={"N": 0, "M": 5}, + ) + self.versus_test( + opponent=axl.Alternator(), + expected_actions=actions, + init_kwargs={"N": 0, "M": 0}, + ) + + # Defector test_strategy + actions = [(D, C)] + [(D, D), (D, C)] * 9 + self.versus_test( + opponent=axl.Alternator(), + expected_actions=actions, + init_kwargs={"N": 1, "M": 0}, + ) + self.versus_test( + opponent=axl.Alternator(), + expected_actions=actions, + init_kwargs={"N": 5, "M": 0}, + ) + + # Default init args + actions = [(C, C), (C, D), (C, D), (D, C), (D, C), (D, D), (C, C)] + opponent = axl.MockPlayer(actions=[acts[1] for acts in actions]) + self.versus_test(opponent=opponent, expected_actions=actions) + + def test_varying_memory_depth(self): + self.assertEqual(self.player(1, 1).classifier["memory_depth"], 1) + self.assertEqual(self.player(0, 3).classifier["memory_depth"], 3) + self.assertEqual(self.player(5, 3).classifier["memory_depth"], 5) + + +class TestMichaelos(TestPlayer): + """ + Tests for the Michaelos strategy + """ + + name = "Michaelos: (D,)" + player = axl.Michaelos + expected_classifier = { + "memory_depth": float("inf"), + "stochastic": True, + "makes_use_of": {"length"}, + "inspects_source": False, + "manipulates_source": False, + "manipulates_state": False, + } + + def test_strategy(self): + + actions = [(C, C), (C, C), (C, C), (D, C)] + self.versus_test( + axl.Cooperator(), + expected_actions=actions, + attrs={"is_defector": False}, + seed=2, + ) + + actions = [(C, C), (C, C), (C, C), (C, C)] + self.versus_test( + axl.Cooperator(), + expected_actions=actions, + attrs={"is_defector": False}, + match_attributes={"length": float("inf")}, + seed=2, + ) + + actions = [(C, D), (D, D), (D, D), (D, D)] + self.versus_test( + axl.Defector(), + expected_actions=actions, + attrs={"is_defector": False}, + seed=2, + ) + + actions = [(C, D), (D, D), (D, D), (D, D)] + self.versus_test( + axl.Defector(), + expected_actions=actions, + attrs={"is_defector": False}, + match_attributes={"length": float("inf")}, + seed=2, + ) + + # Chance of becoming a defector is 50% after (D, C) occurs. + actions = [(C, C), (C, D), (D, C), (C, D), (D, C)] + self.versus_test( + axl.Alternator(), + expected_actions=actions, + attrs={"is_defector": False}, + seed=3, + ) + + actions = [(C, C), (C, D), (D, C), (D, D), (D, C), (D, D), (D, C)] + self.versus_test( + axl.Alternator(), + expected_actions=actions, + attrs={"is_defector": True}, + seed=2, + ) + + actions = [(C, C), (C, D), (D, C), (C, D), (D, C), (D, D), (D, C)] + self.versus_test( + axl.Alternator(), + expected_actions=actions, + attrs={"is_defector": True}, + match_attributes={"length": float("inf")}, + seed=1, + ) + + +class TestRandomTitForTat(TestPlayer): + """Tests for random tit for tat strategy.""" + + name = "Random Tit for Tat: 0.5" + player = axl.RandomTitForTat + expected_classifier = { + "memory_depth": 1, + "stochastic": True, + "makes_use_of": set(), + "long_run_time": False, + "inspects_source": False, + "manipulates_source": False, + "manipulates_state": False, + } + + def test_strategy(self): + """ + Test that strategy reacts to opponent, and controlled by + probability every other iteration. Also reacts randomly if no + probability input. + """ + actions = [(C, C), (C, C), (C, C)] + self.versus_test( + axl.Cooperator(), expected_actions=actions, init_kwargs={"p": 1} + ) + + actions = [(C, D), (D, D), (D, D)] + self.versus_test( + axl.Defector(), expected_actions=actions, init_kwargs={"p": 0} + ) + + actions = [(C, C), (C, C), (D, C), (C, C)] + self.versus_test( + axl.Cooperator(), expected_actions=actions, init_kwargs={"p": 0} + ) + + actions = [(C, D), (D, D), (C, D), (D, D)] + self.versus_test( + axl.Defector(), expected_actions=actions, init_kwargs={"p": 1} + ) + + actions = [(C, C), (C, C), (D, C), (C, C), (D, C), (C, C)] + self.versus_test(axl.Cooperator(), expected_actions=actions, seed=2) + + actions = [(C, D), (D, D), (C, D), (D, D), (D, D), (D, D)] + self.versus_test(axl.Defector(), expected_actions=actions, seed=1) + + def test_deterministic_classification(self): + """ + Test classification when probability input is 0 or 1. + Should change stochastic to false, because actions are no + longer random. + + """ + for p in [0, 1]: + player = axl.RandomTitForTat(p=p) + self.assertFalse(player.classifier["stochastic"]) From dbe8a12a677b7383840a9447c54fe0c863f87c6a Mon Sep 17 00:00:00 2001 From: Vince Knight Date: Mon, 6 Apr 2020 19:14:31 +0100 Subject: [PATCH 08/20] Report coverage separately. This just makes reading the output from github Actions slightly more modular. --- .github/workflows/config.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/config.yml b/.github/workflows/config.yml index a3376fd14..d098b2c7d 100644 --- a/.github/workflows/config.yml +++ b/.github/workflows/config.yml @@ -34,9 +34,11 @@ jobs: python -m pip install coverage python -m pip install hypothesis==3.2 python -m pip install mypy - - name: Run tests and coverage + - name: Run tests run: | coverage run --source=axelrod -m unittest discover + - name: Report coverage + run: | coverage report -m --fail-under=100 - name: Run doctest run: | From 16ae21f2f3ee99c47f130be5a0ba34b3053adb9f Mon Sep 17 00:00:00 2001 From: Vince Knight Date: Mon, 6 Apr 2020 19:22:51 +0100 Subject: [PATCH 09/20] Add an error in type hinting. --- axelrod/tournament.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/axelrod/tournament.py b/axelrod/tournament.py index 26144757c..3b378d260 100644 --- a/axelrod/tournament.py +++ b/axelrod/tournament.py @@ -33,7 +33,7 @@ def __init__( noise: float = 0, edges: List[Tuple] = None, match_attributes: dict = None, - ) -> None: + ) -> float: """ Parameters ---------- From f3fad7db4ed323d80db62fca149a3699f20b15c6 Mon Sep 17 00:00:00 2001 From: Vince Knight Date: Mon, 6 Apr 2020 19:26:52 +0100 Subject: [PATCH 10/20] Revert "Add an error in type hinting." This reverts commit 16ae21f2f3ee99c47f130be5a0ba34b3053adb9f. --- axelrod/tournament.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/axelrod/tournament.py b/axelrod/tournament.py index 3b378d260..26144757c 100644 --- a/axelrod/tournament.py +++ b/axelrod/tournament.py @@ -33,7 +33,7 @@ def __init__( noise: float = 0, edges: List[Tuple] = None, match_attributes: dict = None, - ) -> float: + ) -> None: """ Parameters ---------- From d6d7de9d29f63fde7b5d4ce333fa078336c551bc Mon Sep 17 00:00:00 2001 From: Vince Knight Date: Mon, 6 Apr 2020 19:50:23 +0100 Subject: [PATCH 11/20] Add error to doctests. --- docs/tutorials/getting_started/match.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/tutorials/getting_started/match.rst b/docs/tutorials/getting_started/match.rst index b7ef10e6b..1acd11801 100644 --- a/docs/tutorials/getting_started/match.rst +++ b/docs/tutorials/getting_started/match.rst @@ -14,7 +14,7 @@ For example, to create a 5 turn match between :code:`Cooperator` and >>> players = (axl.Cooperator(), axl.Alternator()) >>> match = axl.Match(players, 5) >>> match.play() - [(C, C), (C, D), (C, C), (C, D), (C, C)] + [(C, D), (C, D), (C, C), (C, D), (C, C)] By default, a match will not be noisy, but you can introduce noise if you wish. Noise is the probability with which any action dictated by a strategy will be From dd54a8826e20f6e9fa25d923bbd242b4cb7203f4 Mon Sep 17 00:00:00 2001 From: Vince Knight Date: Mon, 6 Apr 2020 19:51:15 +0100 Subject: [PATCH 12/20] Revert "Add error to doctests." This reverts commit d6d7de9d29f63fde7b5d4ce333fa078336c551bc. --- docs/tutorials/getting_started/match.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/tutorials/getting_started/match.rst b/docs/tutorials/getting_started/match.rst index 1acd11801..b7ef10e6b 100644 --- a/docs/tutorials/getting_started/match.rst +++ b/docs/tutorials/getting_started/match.rst @@ -14,7 +14,7 @@ For example, to create a 5 turn match between :code:`Cooperator` and >>> players = (axl.Cooperator(), axl.Alternator()) >>> match = axl.Match(players, 5) >>> match.play() - [(C, D), (C, D), (C, C), (C, D), (C, C)] + [(C, C), (C, D), (C, C), (C, D), (C, C)] By default, a match will not be noisy, but you can introduce noise if you wish. Noise is the probability with which any action dictated by a strategy will be From 2bf4699884e5b9eaabaf8b5db2c4eefb72ee8741 Mon Sep 17 00:00:00 2001 From: Vince Knight Date: Mon, 6 Apr 2020 20:36:00 +0100 Subject: [PATCH 13/20] Add error to strategy index. --- docs/reference/all_strategies.rst | 2 -- 1 file changed, 2 deletions(-) diff --git a/docs/reference/all_strategies.rst b/docs/reference/all_strategies.rst index f933dd43e..94e30e6e0 100644 --- a/docs/reference/all_strategies.rst +++ b/docs/reference/all_strategies.rst @@ -80,8 +80,6 @@ Here are the docstrings of all the strategies in the library. :members: .. automodule:: axelrod.strategies.mindcontrol :members: -.. automodule:: axelrod.strategies.mindreader - :members: .. automodule:: axelrod.strategies.mutual :members: .. automodule:: axelrod.strategies.negation From 9bafd4cf6ccf34db02026f0400e2a86736de9618 Mon Sep 17 00:00:00 2001 From: Vince Knight Date: Mon, 6 Apr 2020 21:27:20 +0100 Subject: [PATCH 14/20] Revert "Add error to strategy index." This reverts commit 2bf4699884e5b9eaabaf8b5db2c4eefb72ee8741. --- docs/reference/all_strategies.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/reference/all_strategies.rst b/docs/reference/all_strategies.rst index 94e30e6e0..f933dd43e 100644 --- a/docs/reference/all_strategies.rst +++ b/docs/reference/all_strategies.rst @@ -80,6 +80,8 @@ Here are the docstrings of all the strategies in the library. :members: .. automodule:: axelrod.strategies.mindcontrol :members: +.. automodule:: axelrod.strategies.mindreader + :members: .. automodule:: axelrod.strategies.mutual :members: .. automodule:: axelrod.strategies.negation From 3acab965ba5d7a35555cf665380a7ef141d22579 Mon Sep 17 00:00:00 2001 From: Vince Knight Date: Mon, 6 Apr 2020 21:32:57 +0100 Subject: [PATCH 15/20] Add error to setup.py --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index c49ed695c..508479b9f 100644 --- a/setup.py +++ b/setup.py @@ -12,7 +12,7 @@ long_description = f.read() # Read in the version number -exec(open("axelrod/version.py", "r").read()) +exec(open("axelrod/version.py", "r").read() setup( name="Axelrod", From e7a23e20f5cf10fd3913ff1a1eb7c5c62d7b33f0 Mon Sep 17 00:00:00 2001 From: Vince Knight Date: Mon, 6 Apr 2020 21:42:09 +0100 Subject: [PATCH 16/20] Revert "Add error to setup.py" This reverts commit 3acab965ba5d7a35555cf665380a7ef141d22579. --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 508479b9f..c49ed695c 100644 --- a/setup.py +++ b/setup.py @@ -12,7 +12,7 @@ long_description = f.read() # Read in the version number -exec(open("axelrod/version.py", "r").read() +exec(open("axelrod/version.py", "r").read()) setup( name="Axelrod", From 5f080503467c6c1158d2c54619445f8e3759e851 Mon Sep 17 00:00:00 2001 From: Vince Knight Date: Mon, 6 Apr 2020 21:49:42 +0100 Subject: [PATCH 17/20] Remove unnecessary badges. --- README.rst | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/README.rst b/README.rst index 1b925160f..35d416c57 100644 --- a/README.rst +++ b/README.rst @@ -1,15 +1,12 @@ -.. image:: https://coveralls.io/repos/github/Axelrod-Python/Axelrod/badge.svg?branch=master - :target: https://coveralls.io/github/Axelrod-Python/Axelrod?branch=master - .. image:: https://img.shields.io/pypi/v/Axelrod.svg :target: https://pypi.python.org/pypi/Axelrod -.. image:: https://travis-ci.org/Axelrod-Python/Axelrod.svg?branch=packaging - :target: https://travis-ci.org/Axelrod-Python/Axelrod - .. image:: https://zenodo.org/badge/19509/Axelrod-Python/Axelrod.svg :target: https://zenodo.org/badge/latestdoi/19509/Axelrod-Python/Axelrod +.. image:: https://github.com/Axelrod-Python/Axelrod/workflows/CI/badge.svg + :target: https://github.com/Axelrod-Python/Axelrod/actions + |Join the chat at https://gitter.im/Axelrod-Python/Axelrod| Axelrod From a0bb6f359cf238b22177d65d36b94df02dd3e804 Mon Sep 17 00:00:00 2001 From: Vince Knight Date: Tue, 7 Apr 2020 16:53:32 +0100 Subject: [PATCH 18/20] Fix py >= 3.6 in README and setup.py --- README.rst | 2 +- setup.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.rst b/README.rst index 35d416c57..c104b3811 100644 --- a/README.rst +++ b/README.rst @@ -71,7 +71,7 @@ a peer reviewed paper introducing the library (22 authors). Installation ------------ -The library requires Python 3.5 or greater. +The library requires Python 3.6 or greater. The simplest way to install is:: diff --git a/setup.py b/setup.py index c49ed695c..afc223c0f 100644 --- a/setup.py +++ b/setup.py @@ -33,5 +33,5 @@ "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3 :: Only", ], - python_requires=">=3.5", + python_requires=">=3.6", ) From 97fa65fd9b7f2fbaf1970019e7e1a9313a5fcfff Mon Sep 17 00:00:00 2001 From: Vince Knight Date: Wed, 8 Apr 2020 10:59:27 +0100 Subject: [PATCH 19/20] Fix broken data file imports. --- MANIFEST.in | 2 +- setup.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/MANIFEST.in b/MANIFEST.in index bb4c1be0a..d42cd9a37 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,3 +1,3 @@ include *.txt recursive-include docs *.rst -recursive-include axelrod/data *.csv +recursive-include axelrod/data * diff --git a/setup.py b/setup.py index c49ed695c..63fbb2ed0 100644 --- a/setup.py +++ b/setup.py @@ -27,7 +27,7 @@ long_description=long_description, long_description_content_type="text/x-rst", include_package_data=True, - package_data={"": ["axelrod/data/*.csv"]}, + package_data={"": ["axelrod/data/*"]}, classifiers=[ "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", From f4bd6abeb2a25fc83a6aad8a4c3b3f37fe4c0d73 Mon Sep 17 00:00:00 2001 From: Vince Knight Date: Wed, 8 Apr 2020 11:04:46 +0100 Subject: [PATCH 20/20] Add a test that library installs properly Check that can be imported from another directory. --- .github/workflows/config.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/config.yml b/.github/workflows/config.yml index d098b2c7d..347edb097 100644 --- a/.github/workflows/config.yml +++ b/.github/workflows/config.yml @@ -52,3 +52,5 @@ jobs: - name: Check that installs run: | python setup.py install + cd .. + python -c "import axelrod"