Skip to content

Commit 391cf7b

Browse files
committed
Merge pull request #295 from Axelrod-Python/294
294 - adds classifier dictionary and applies to all strategies with tests
2 parents abec603 + ab563e7 commit 391cf7b

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

66 files changed

+1395
-269
lines changed

axelrod/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,4 @@
1010
from .tournament import *
1111
from .tournament_manager import *
1212
from .strategies import *
13-
from .ecosystem import *
13+
from .ecosystem import *

axelrod/player.py

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import inspect
22
import random
3+
import copy
34

45
C, D = 'C', 'D'
56
flip_dict = {C: D, D: C}
@@ -28,14 +29,27 @@ class Player(object):
2829
"""
2930

3031
name = "Player"
32+
classifier = {}
33+
default_classifier = {
34+
'stochastic': False,
35+
'memory_depth': float('inf'),
36+
'inspects_source': None,
37+
'manipulates_source': None,
38+
'manipulates_state': None
39+
}
3140

3241
def __init__(self):
3342
"""Initiates an empty history and 0 score for a player."""
3443
self.history = []
35-
self.stochastic = "random" in inspect.getsource(self.__class__)
36-
self.tournament_attributes = {'length': -1, 'game': None}
44+
self.classifier = copy.copy(self.classifier)
45+
self.classifier['stochastic'] = (
46+
"random" in inspect.getsource(self.__class__))
3747
if self.name == "Player":
38-
self.stochastic = False
48+
self.classifier['stochastic'] = False
49+
for dimension in self.default_classifier:
50+
if dimension not in self.classifier:
51+
self.classifier[dimension] = self.default_classifier[dimension]
52+
self.tournament_attributes = {'length': -1, 'game': None}
3953
self.cooperations = 0
4054
self.defections = 0
4155

axelrod/round_robin.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -97,8 +97,8 @@ def _pair_of_players(self, player1_index, player2_index):
9797
def _stochastic_interaction(self, player1, player2):
9898
return (
9999
self._noise or
100-
player1.stochastic or
101-
player2.stochastic)
100+
player1.classifier['stochastic'] or
101+
player2.classifier['stochastic'])
102102

103103
def _play_single_interaction(self, player1, player2, classes):
104104
turn = 0
@@ -130,7 +130,7 @@ def _cache_update_required(self, p1, p2):
130130
return (
131131
not self._noise and
132132
self.cache_mutable and
133-
not (p1.stochastic or p2.stochastic))
133+
not (p1.classifier['stochastic'] or p2.classifier['stochastic']))
134134

135135
def _calculate_cooperation(self, player):
136136
return player.history.count('C')

axelrod/strategies/_strategies.py

Lines changed: 32 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
from .retaliate import *
3131
from .titfortat import *
3232

33-
33+
# A list of strategies to quickly create a tournament
3434
basic_strategies = [
3535
Alternator,
3636
Cooperator,
@@ -39,12 +39,13 @@
3939
TitForTat,
4040
]
4141

42-
ordinary_strategies = [
42+
# All the strategies in the tournament
43+
strategies = basic_strategies + [
4344
Aggravater,
4445
AlternatorHunter,
45-
Appeaser,
4646
AntiCycler,
4747
AntiTitForTat,
48+
Appeaser,
4849
ArrogantQLearner,
4950
AverageCopier,
5051
BackStabber,
@@ -53,33 +54,37 @@
5354
CautiousQLearner,
5455
Champion,
5556
CooperatorHunter,
56-
CyclerCCD,
57-
CyclerCCCD,
5857
CyclerCCCCCD,
58+
CyclerCCCD,
59+
CyclerCCD,
60+
Darwin,
5961
Davis,
6062
DefectorHunter,
6163
DoubleCrosser,
6264
Eatherley,
63-
FoolMeOnce,
65+
Feld,
6466
FoolMeForever,
67+
FoolMeOnce,
6568
ForgetfulFoolMeOnce,
6669
ForgetfulGrudger,
6770
Forgiver,
6871
ForgivingTitForTat,
6972
GTFT,
73+
Geller,
74+
GellerCooperator,
75+
GellerDefector,
7076
GoByMajority,
7177
GoByMajority10,
7278
GoByMajority20,
7379
GoByMajority40,
7480
GoByMajority5,
75-
Feld,
7681
Golden,
7782
Grofman,
7883
Grudger,
7984
Grumpy,
8085
HardProber,
81-
HardTitForTat,
8286
HardTitFor2Tats,
87+
HardTitForTat,
8388
HesitantQLearner,
8489
Inverse,
8590
InversePunisher,
@@ -92,22 +97,27 @@
9297
MetaMajority,
9398
MetaMinority,
9499
MetaWinner,
100+
MindBender,
101+
MindController,
102+
MindReader,
103+
MindWarper,
95104
NiceAverageCopier,
96105
OnceBitten,
97106
OppositeGrudger,
98107
Pi,
99108
Prober,
100109
Prober2,
101110
Prober3,
111+
ProtectedMindReader,
102112
Punisher,
103113
RandomHunter,
104114
Retaliate,
105115
Retaliate2,
106116
Retaliate3,
107117
RiskyQLearner,
108118
Shubik,
109-
SoftJoss,
110119
SneakyTitForTat,
120+
SoftJoss,
111121
StochasticWSLS,
112122
SuspiciousTitForTat,
113123
Tester,
@@ -120,17 +130,17 @@
120130
ZDExtort2,
121131
ZDGTFT2,
122132
e,
123-
]
133+
]
124134

125-
# These are strategies that do not follow the rules of Axelrods tournament
126-
cheating_strategies = [
127-
Darwin,
128-
Geller,
129-
GellerCooperator,
130-
GellerDefector,
131-
MindBender,
132-
MindController,
133-
MindReader,
134-
MindWarper,
135-
ProtectedMindReader,
136-
]
135+
136+
def is_cheater(s):
137+
"""
138+
A function to check if a strategy cheats.
139+
"""
140+
classifier = s.classifier
141+
return classifier['inspects_source'] or\
142+
classifier['manipulates_source'] or\
143+
classifier['manipulates_state']
144+
145+
ordinary_strategies = [s for s in strategies if not is_cheater(s)]
146+
cheating_strategies = [s for s in strategies if is_cheater(s)]

axelrod/strategies/alternator.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,13 @@ class Alternator(Player):
55
"""A player who alternates between cooperating and defecting."""
66

77
name = 'Alternator'
8-
memory_depth = 1
8+
classifier = {
9+
'memory_depth': 1,
10+
'stochastic': False,
11+
'inspects_source': False,
12+
'manipulates_source': False,
13+
'manipulates_state': False
14+
}
915

1016
def strategy(self, opponent):
1117
if len(self.history) == 0:

axelrod/strategies/appeaser.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,18 @@
44
class Appeaser(Player):
55
"""A player who tries to guess what the opponent wants.
66
7-
Switch the behaviour every time the opponent plays 'D'.
7+
Switch the classifier every time the opponent plays 'D'.
88
Start with 'C', switch between 'C' and 'D' when opponent plays 'D'.
99
"""
1010

1111
name = 'Appeaser'
12-
memory_depth = float('inf') # Depends on internal memory.
12+
classifier = {
13+
'memory_depth': float('inf'), # Depends on internal memory.
14+
'stochastic': False,
15+
'inspects_source': False,
16+
'manipulates_source': False,
17+
'manipulates_state': False
18+
}
1319

1420
def strategy(self, opponent):
1521
if not len(self.history):

axelrod/strategies/averagecopier.py

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,13 @@ class AverageCopier(Player):
88
"""The player will cooperate with probability p if the opponent's cooperation ratio is p."""
99

1010
name = 'Average Copier'
11-
memory_depth = float('inf') # Long memory
11+
classifier = {
12+
'memory_depth': float('inf'), # Long memory
13+
'stochastic': True,
14+
'inspects_source': False,
15+
'manipulates_source': False,
16+
'manipulates_state': False
17+
}
1218

1319
@staticmethod
1420
def strategy(opponent):
@@ -21,11 +27,18 @@ def strategy(opponent):
2127
return 'C'
2228
return 'D'
2329

30+
2431
class NiceAverageCopier(Player):
2532
"""Same as Average Copier, but always starts by cooperating."""
2633

2734
name = 'Nice Average Copier'
28-
memory_depth = float('inf') # Long memory
35+
classifier = {
36+
'memory_depth': float('inf'), # Long memory
37+
'stochastic': True,
38+
'inspects_source': False,
39+
'manipulates_source': False,
40+
'manipulates_state': False
41+
}
2942

3043
@staticmethod
3144
def strategy(opponent):

axelrod/strategies/axelrod_tournaments.py

Lines changed: 49 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,13 @@ class Davis(Player):
1616
defecting if at any point the opponent has defected."""
1717

1818
name = 'Davis'
19-
memory_depth = float('inf') # Long memory
19+
classifier = {
20+
'memory_depth': float('inf'), # Long memory
21+
'stochastic': False,
22+
'inspects_source': False,
23+
'manipulates_source': False,
24+
'manipulates_state': False
25+
}
2026

2127
def __init__(self, rounds_to_cooperate=10):
2228
Player.__init__(self)
@@ -39,7 +45,13 @@ class Feld(Player):
3945
"""
4046

4147
name = "Feld"
42-
memory_depth = 200 # Varies actually, eventually becomes depth 1
48+
classifier = {
49+
'memory_depth': 200, # Varies actually, eventually becomes depth 1
50+
'stochastic': False,
51+
'inspects_source': False,
52+
'manipulates_source': False,
53+
'manipulates_state': False
54+
}
4355

4456
def __init__(self, start_coop_prob=1.0, end_coop_prob=0.5,
4557
rounds_of_decay=200):
@@ -78,7 +90,13 @@ class Shubik(Player):
7890
"""
7991

8092
name = 'Shubik'
81-
memory_depth = float('inf')
93+
classifier = {
94+
'memory_depth': float('inf'),
95+
'stochastic': False,
96+
'inspects_source': False,
97+
'manipulates_source': False,
98+
'manipulates_state': False
99+
}
82100

83101
def __init__(self):
84102
Player.__init__(self)
@@ -129,7 +147,13 @@ class Tullock(Player):
129147
than the opponent has in previous rounds."""
130148

131149
name = "Tullock"
132-
memory_depth = 11 # long memory, modified by init
150+
classifier = {
151+
'memory_depth': 11, # long memory, modified by init
152+
'stochastic': False,
153+
'inspects_source': False,
154+
'manipulates_source': False,
155+
'manipulates_state': False
156+
}
133157

134158
def __init__(self, rounds_to_cooperate=11):
135159
Player.__init__(self)
@@ -157,7 +181,13 @@ class Champion(Player):
157181
"""
158182

159183
name = "Champion"
160-
memory_depth = float('inf')
184+
classifier = {
185+
'memory_depth': float('inf'),
186+
'stochastic': False,
187+
'inspects_source': False,
188+
'manipulates_source': False,
189+
'manipulates_state': False
190+
}
161191

162192
def strategy(self, opponent):
163193
current_round = len(self.history)
@@ -185,7 +215,13 @@ class Eatherley(Player):
185215
"""
186216

187217
name = "Eatherley"
188-
memory_depth = float('inf')
218+
classifier = {
219+
'memory_depth': float('inf'),
220+
'stochastic': False,
221+
'inspects_source': False,
222+
'manipulates_source': False,
223+
'manipulates_state': False
224+
}
189225

190226
def strategy(self, opponent):
191227
# Cooperate on the first move
@@ -212,7 +248,13 @@ class Tester(Player):
212248
"""
213249

214250
name = "Tester"
215-
memory_depth = float('inf')
251+
classifier = {
252+
'memory_depth': float('inf'),
253+
'stochastic': False,
254+
'inspects_source': False,
255+
'manipulates_source': False,
256+
'manipulates_state': False
257+
}
216258

217259
def __init__(self):
218260
Player.__init__(self)

0 commit comments

Comments
 (0)