Skip to content

Commit a1f8534

Browse files
committed
Add GrudgerAlternator strategy
1 parent 00da984 commit a1f8534

File tree

3 files changed

+86
-1
lines changed

3 files changed

+86
-1
lines changed

axelrod/strategies/_strategies.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
HardGoByMajority5)
3030
from .gradualkiller import GradualKiller
3131
from .grudger import (Grudger, ForgetfulGrudger, OppositeGrudger, Aggravater,
32-
SoftGrudger)
32+
SoftGrudger, GrudgerAlternator)
3333
from .grumpy import Grumpy
3434
from .handshake import Handshake
3535
from .hunter import (
@@ -124,6 +124,7 @@
124124
GradualKiller,
125125
Grofman,
126126
Grudger,
127+
GrudgerAlternator,
127128
Grumpy,
128129
Handshake,
129130
HardGoByMajority,

axelrod/strategies/grudger.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,3 +171,33 @@ def reset(self):
171171
Player.reset(self)
172172
self.grudged = False
173173
self.grudge_memory = 0
174+
175+
176+
177+
class GrudgerAlternator(Player):
178+
"""
179+
A player starts by cooperating until the first opponents defenction,
180+
then alternates D-C.
181+
182+
Names:
183+
184+
- c_then_per_dc: [PRISON1998]_
185+
"""
186+
187+
name = 'GrudgerAlternator'
188+
classifier = {
189+
'memory_depth': float('inf'), # Long memory
190+
'stochastic': False,
191+
'makes_use_of': set(),
192+
'long_run_time': False,
193+
'inspects_source': False,
194+
'manipulates_source': False,
195+
'manipulates_state': False
196+
}
197+
198+
def strategy(self, opponent):
199+
"""Begins by playing C, then plays Alternator for the remaining rounds if the opponent ever plays D."""
200+
if opponent.defections:
201+
if self.history[-1] == Actions.C:
202+
return Actions.D
203+
return Actions.C

axelrod/tests/unit/test_grudger.py

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
"""Tests for grudger strategies."""
22

33
import axelrod
4+
from random import randint
45

56
from .test_player import TestPlayer
67

@@ -173,3 +174,56 @@ def test_reset(self):
173174
p.reset()
174175
self.assertFalse(p.grudged)
175176
self.assertEqual(p.grudge_memory, 0)
177+
178+
179+
180+
class TestGrudgerAlternator(TestPlayer):
181+
182+
name = "GrudgerAlternator"
183+
player = axelrod.GrudgerAlternator
184+
expected_classifier = {
185+
'memory_depth': float('inf'), # Long memory
186+
'stochastic': False,
187+
'makes_use_of': set(),
188+
'long_run_time': False,
189+
'inspects_source': False,
190+
'manipulates_source': False,
191+
'manipulates_state': False
192+
}
193+
194+
def test_initial_strategy(self):
195+
"""
196+
Starts by cooperating
197+
"""
198+
self.first_play_test(C)
199+
200+
def test_strategy(self):
201+
"""
202+
If opponent defects at any point then the player will alternate D-C.
203+
"""
204+
self.responses_test([C, C, C, C, C], [C, C, C, C, C], [C])
205+
self.responses_test([C, C, C, C, C, C], [C, C, C, C, C, D], [D])
206+
self.responses_test([C, C, C, C, C, C, D], [C, C, C, C, C, D, D], [C])
207+
self.responses_test([C, C, C, C, C, C, D, C], [C, C, C, C, C, D, D, C], [D])
208+
self.responses_test([C, C, C, C, C, C, D, C, D], [C, C, C, C, C, D, D, C, C], [C])
209+
210+
def test_starategy_random_number_rounds(self):
211+
"""
212+
Runs test_strategy for a random number of rounds
213+
"""
214+
# Hasn't defected yet
215+
for _ in range(20):
216+
i = randint(1, 30)
217+
j = randint(1, 30)
218+
opp_hist = [C] * i
219+
my_hist = [C] * i
220+
self.responses_test(my_hist, opp_hist, [C]*j)
221+
222+
# Defected at least once
223+
for _ in range(20):
224+
i = randint(1, 30)
225+
j = randint(1, 30)
226+
opp_hist = [C for r in range(i)] + [D]
227+
my_hist = [C] * (i + 1)
228+
expected_response = [D if r % 2 == 0 else C for r in range(j)]
229+
self.responses_test(my_hist, opp_hist, expected_response)

0 commit comments

Comments
 (0)