Skip to content

Commit aafb4be

Browse files
authored
Merge pull request #1147 from gaffney2010/master
Implemented MoreTidemanAndChieruzzi, K84R from Axelrod's second
2 parents 9822c9c + 440638a commit aafb4be

File tree

4 files changed

+167
-4
lines changed

4 files changed

+167
-4
lines changed

axelrod/strategies/_strategies.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@
99
UnnamedStrategy, SteinAndRapoport, TidemanAndChieruzzi)
1010
from .axelrod_second import (
1111
Champion, Eatherley, Tester, Gladstein, Tranquilizer, MoreGrofman,
12-
Kluepfel, Borufsen, Cave, WmAdams, GraaskampKatzen, Weiner, Harrington)
12+
Kluepfel, Borufsen, Cave, WmAdams, GraaskampKatzen, Weiner, Harrington,
13+
MoreTidemanAndChieruzzi)
1314
from .backstabber import BackStabber, DoubleCrosser
1415
from .better_and_better import BetterAndBetter
1516
from .bush_mosteller import BushMosteller
@@ -208,6 +209,7 @@
208209
MindWarper,
209210
MirrorMindReader,
210211
MoreGrofman,
212+
MoreTidemanAndChieruzzi,
211213
Negation,
212214
NiceAverageCopier,
213215
NTitsForMTats,

axelrod/strategies/axelrod_second.py

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1305,3 +1305,114 @@ def strategy(self, opponent: Player) -> Action:
13051305
self.prob += 0.05
13061306
self.more_coop, self.last_generous_n_turns_ago = 2, 1
13071307
return self.try_return(D, lower_flags=False)
1308+
1309+
1310+
class MoreTidemanAndChieruzzi(Player):
1311+
"""
1312+
Strategy submitted to Axelrod's second tournament by T. Nicolaus Tideman
1313+
and Paula Chieruzzi (K84R) and came in ninth in that tournament.
1314+
1315+
This strategy Cooperates if this player's score exceeds the opponent's
1316+
score by at least `score_to_beat`. `score_to_beat` starts at zero and
1317+
increases by `score_to_beat_inc` every time the opponent's last two moves
1318+
are a Cooperation and Defection in that order. `score_to_beat_inc` itself
1319+
increase by 5 every time the opponent's last two moves are a Cooperation
1320+
and Defection in that order.
1321+
1322+
Additionally, the strategy executes a "fresh start" if the following hold:
1323+
1324+
- The strategy would Defect by score (difference less than `score_to_beat`)
1325+
- The opponent did not Cooperate and Defect (in order) in the last two
1326+
turns.
1327+
- It's been at least 10 turns since the last fresh start. Or since the
1328+
match started if there hasn't been a fresh start yet.
1329+
1330+
A "fresh start" entails two Cooperations and resetting scores,
1331+
`scores_to_beat` and `scores_to_beat_inc`.
1332+
1333+
Names:
1334+
1335+
- MoreTidemanAndChieruzzi: [Axelrod1980b]_
1336+
"""
1337+
1338+
name = 'More Tideman and Chieruzzi'
1339+
classifier = {
1340+
'memory_depth': float('inf'),
1341+
'stochastic': False,
1342+
'makes_use_of': {"game"},
1343+
'long_run_time': False,
1344+
'inspects_source': False,
1345+
'manipulates_source': False,
1346+
'manipulates_state': False
1347+
}
1348+
1349+
def __init__(self) -> None:
1350+
super().__init__()
1351+
self.current_score = 0
1352+
self.opponent_score = 0
1353+
self.last_fresh_start = 0
1354+
self.fresh_start = False
1355+
self.score_to_beat = 0
1356+
self.score_to_beat_inc = 0
1357+
1358+
def _fresh_start(self):
1359+
"""Give the opponent a fresh start by forgetting the past"""
1360+
self.current_score = 0
1361+
self.opponent_score = 0
1362+
self.score_to_beat = 0
1363+
self.score_to_beat_inc = 0
1364+
1365+
def _score_last_round(self, opponent: Player):
1366+
"""Updates the scores for each player."""
1367+
# Load the default game if not supplied by a tournament.
1368+
game = self.match_attributes["game"]
1369+
last_round = (self.history[-1], opponent.history[-1])
1370+
scores = game.score(last_round)
1371+
self.current_score += scores[0]
1372+
self.opponent_score += scores[1]
1373+
1374+
def strategy(self, opponent: Player) -> Action:
1375+
current_round = len(self.history) + 1
1376+
1377+
if current_round == 1:
1378+
return C
1379+
1380+
# Calculate the scores.
1381+
self._score_last_round(opponent)
1382+
1383+
# Check if we have recently given the strategy a fresh start.
1384+
if self.fresh_start:
1385+
self._fresh_start()
1386+
self.last_fresh_start = current_round
1387+
self.fresh_start = False
1388+
return C # Second cooperation
1389+
1390+
opponent_CDd = False
1391+
1392+
opponent_two_turns_ago = C # Default value for second turn.
1393+
if len(opponent.history) >= 2:
1394+
opponent_two_turns_ago = opponent.history[-2]
1395+
# If opponent's last two turns are C and D in that order.
1396+
if opponent_two_turns_ago == C and opponent.history[-1] == D:
1397+
opponent_CDd = True
1398+
self.score_to_beat += self.score_to_beat_inc
1399+
self.score_to_beat_inc += 5
1400+
1401+
# Cooperate if we're beating opponent by at least `score_to_beat`
1402+
if self.current_score - self.opponent_score >= self.score_to_beat:
1403+
return C
1404+
1405+
# Wait at least ten turns for another fresh start.
1406+
if (not opponent_CDd) and current_round - self.last_fresh_start >= 10:
1407+
# 50-50 split is based off the binomial distribution.
1408+
N = opponent.cooperations + opponent.defections
1409+
# std_dev = sqrt(N*p*(1-p)) where p is 1 / 2.
1410+
std_deviation = (N ** (1 / 2)) / 2
1411+
lower = N / 2 - 3 * std_deviation
1412+
upper = N / 2 + 3 * std_deviation
1413+
if opponent.defections <= lower or opponent.defections >= upper:
1414+
# Opponent deserves a fresh start
1415+
self.fresh_start = True
1416+
return C # First cooperation
1417+
1418+
return D

axelrod/tests/strategies/test_axelrod_second.py

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -854,3 +854,55 @@ def test_strategy(self):
854854
actions += [(C, D)] * 2
855855
self.versus_test(Rand_Then_Def, expected_actions=actions, seed=10,
856856
attrs={"mode": "Normal", "was_defective": True})
857+
858+
859+
class TestMoreTidemanAndChieruzzi(TestPlayer):
860+
name = 'More Tideman and Chieruzzi'
861+
player = axelrod.MoreTidemanAndChieruzzi
862+
expected_classifier = {
863+
'memory_depth': float('inf'),
864+
'stochastic': False,
865+
'makes_use_of': {"game"},
866+
'long_run_time': False,
867+
'inspects_source': False,
868+
'manipulates_source': False,
869+
'manipulates_state': False
870+
}
871+
872+
def test_strategy(self):
873+
actions = [(C, C)] * 100
874+
self.versus_test(axelrod.Cooperator(), expected_actions=actions)
875+
876+
actions = [(C, D)] + [(D, D)] * 8
877+
self.versus_test(axelrod.Defector(), expected_actions=actions, attrs={"score_to_beat_inc": 5})
878+
879+
actions = [(C, D)] + [(D, D)] * 8
880+
# On tenth turn, try a fresh start
881+
actions += [(C, D), (C, D)] + [(D, D)] * 2
882+
self.versus_test(axelrod.Defector(), expected_actions=actions, attrs={"last_fresh_start": 11})
883+
884+
actions = [(C, C), (C, D)]
885+
# Scores and score_to_beat variables are a turn behind
886+
self.versus_test(axelrod.Alternator(), expected_actions=actions,
887+
attrs={"current_score": 3, "opponent_score": 3, "score_to_beat": 0, "score_to_beat_inc": 0})
888+
actions += [(D, C), (C, D)]
889+
self.versus_test(axelrod.Alternator(), expected_actions=actions,
890+
attrs={"current_score": 8, "opponent_score": 8, "score_to_beat": 0, "score_to_beat_inc": 5})
891+
actions += [(D, C), (D, D)]
892+
self.versus_test(axelrod.Alternator(), expected_actions=actions,
893+
attrs={"current_score": 13, "opponent_score": 13, "score_to_beat": 5, "score_to_beat_inc": 10})
894+
actions += [(D, C), (D, D)]
895+
self.versus_test(axelrod.Alternator(), expected_actions=actions,
896+
attrs={"current_score": 19, "opponent_score": 14, "score_to_beat": 15, "score_to_beat_inc": 15})
897+
actions += [(D, C), (D, D)]
898+
self.versus_test(axelrod.Alternator(), expected_actions=actions,
899+
attrs={"current_score": 25, "opponent_score": 15, "score_to_beat": 30, "score_to_beat_inc": 20})
900+
901+
# Build an opponent who will cause us to consider a Fresh Start, but
902+
# will fail the binomial test.
903+
opponent_actions = [C] * 5 + [D] * 5
904+
C5D5_Player = axelrod.MockPlayer(actions=opponent_actions)
905+
actions = [(C, C)] * 5 + [(C, D)] + [(D, D)] * 3
906+
actions += [(D, D)] # No Defection here means no Fresh Start.
907+
self.versus_test(C5D5_Player, expected_actions=actions)
908+

docs/reference/overview_of_strategies.rst

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,6 @@ An indication is given as to whether or not this strategy is implemented in the
3636
Tideman and Chieruzzi
3737
^^^^^^^^^^^^^^^^^^^^^
3838

39-
**Not implemented yet**
40-
4139
This strategy begins by playing Tit For Tat and then things get slightly
4240
complicated:
4341

@@ -155,7 +153,7 @@ repository.
155153
"K81R_", "Martyn Jones", "Not Implemented"
156154
"K82R_", "Robert A Leyland", "Not Implemented"
157155
"K83R_", "Paul E Black", "Not Implemented"
158-
"K84R_", "T Nicolaus Tideman and Paula Chieruzz", "Not Implemented"
156+
"K84R_", "T Nicolaus Tideman and Paula Chieruzzi", ":class:`More Tideman And Chieruzzi <axelrod.strategies.axelrod_second.MoreTidemanAndChieruzzi>`"
159157
"K85R_", "Robert B Falk and James M Langsted", "Not Implemented"
160158
"K86R_", "Bernard Grofman", "Not Implemented"
161159
"K87R_", "E E H Schurmann", "Not Implemented"

0 commit comments

Comments
 (0)