Skip to content

Commit b4e770b

Browse files
committed
Merge pull request #298 from Axelrod-Python/297
297 - demo_strategies and make basic_strategies dynamic
2 parents 1100a92 + 42b1577 commit b4e770b

File tree

5 files changed

+82
-48
lines changed

5 files changed

+82
-48
lines changed

axelrod/player.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,17 @@
88

99
# Strategy classifiers
1010

11+
def is_basic(s):
12+
"""
13+
Defines criteria for a strategy to be considered 'basic'
14+
"""
15+
stochastic = s.classifier['stochastic']
16+
depth = s.classifier['memory_depth']
17+
inspects_source = s.classifier['inspects_source']
18+
manipulates_source = s.classifier['manipulates_source']
19+
manipulates_state = s.classifier['manipulates_state']
20+
return (not stochastic) and (not inspects_source) and (not manipulates_source) and (not manipulates_state) and (depth in (0, 1))
21+
1122
def is_cheater(s):
1223
"""
1324
A function to check if a strategy cheats.

axelrod/strategies/__init__.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from ..player import is_cheater
1+
from ..player import is_basic, is_cheater
22
from ._strategies import *
33

44
# `from ._strategies import *` import the collection `strategies`
@@ -11,8 +11,7 @@
1111
# Distinguished strategy collections in addition to
1212
# `strategies` from _strategies.py
1313

14+
demo_strategies = [Cooperator, Defector, TitForTat, Grudger, Random]
15+
basic_strategies = [s for s in strategies if is_basic(s())]
1416
ordinary_strategies = [s for s in strategies if not is_cheater(s())]
1517
cheating_strategies = [s for s in strategies if is_cheater(s())]
16-
17-
# Defined by fiat for demo purposes
18-
basic_strategies = [Alternator, Cooperator, Defector, Random, TitForTat]

axelrod/strategies/_strategies.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,7 @@
4141
SuspiciousTitForTat, AntiTitForTat, HardTitForTat, HardTitFor2Tats)
4242

4343

44-
# Note: Meta* strategies are handled in .__init__.py, so this is not the
45-
# final form of the list
44+
# Note: Meta* strategies are handled in .__init__.py
4645

4746
strategies = [
4847
Aggravater,

axelrod/tests/unit/test_classification.py

Lines changed: 35 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,16 @@ def test_is_cheater(self):
6262
axelrod.MindWarper,
6363
axelrod.MindReader]
6464

65+
known_basic = [axelrod.Alternator,
66+
axelrod.AntiTitForTat,
67+
axelrod.Bully,
68+
axelrod.Cooperator,
69+
axelrod.Defector,
70+
axelrod.GoByMajority,
71+
axelrod.SuspiciousTitForTat,
72+
axelrod.TitForTat,
73+
axelrod.WinStayLoseShift]
74+
6575
known_ordinary = [axelrod.AverageCopier,
6676
axelrod.ForgivingTitForTat,
6777
axelrod.GoByMajority20,
@@ -72,26 +82,42 @@ def test_is_cheater(self):
7282

7383
for strategy in known_cheaters:
7484
self.assertTrue(axelrod.is_cheater(strategy()), msg=strategy)
85+
self.assertFalse(axelrod.is_basic(strategy()), msg=strategy)
86+
87+
for strategy in known_basic:
88+
self.assertTrue(axelrod.is_basic(strategy()), msg=strategy)
89+
self.assertFalse(axelrod.is_cheater(strategy()), msg=strategy)
7590

7691
for strategy in known_ordinary:
92+
self.assertFalse(axelrod.is_basic(strategy()), msg=strategy)
7793
self.assertFalse(axelrod.is_cheater(strategy()), msg=strategy)
7894

7995

8096
class TestStrategies(unittest.TestCase):
8197

8298
def test_strategy_list(self):
83-
self.assertTrue(hasattr(axelrod, "strategies"))
84-
self.assertTrue(hasattr(axelrod, "basic_strategies"))
85-
self.assertTrue(hasattr(axelrod, "ordinary_strategies"))
86-
self.assertTrue(hasattr(axelrod, "cheating_strategies"))
99+
for strategy_list in ["strategies",
100+
"demo_strategies",
101+
"basic_strategies",
102+
"ordinary_strategies",
103+
"cheating_strategies"]:
104+
self.assertTrue(hasattr(axelrod, strategy_list))
87105

88106
def test_lists_not_empty(self):
89-
self.assertTrue(len(axelrod.strategies) > 0)
90-
self.assertTrue(len(axelrod.basic_strategies) > 0)
91-
self.assertTrue(len(axelrod.ordinary_strategies) > 0)
92-
self.assertTrue(len(axelrod.cheating_strategies) > 0)
107+
for strategy_list in [axelrod.strategies,
108+
axelrod.demo_strategies,
109+
axelrod.basic_strategies,
110+
axelrod.ordinary_strategies,
111+
axelrod.cheating_strategies]:
112+
self.assertTrue(len(strategy_list) > 0)
93113

94114
def test_meta_inclusion(self):
95115
self.assertTrue(axelrod.MetaMajority in axelrod.strategies)
96116

97-
117+
def test_demo_strategies(self):
118+
demo_strategies = [axelrod.Cooperator,
119+
axelrod.Defector,
120+
axelrod.TitForTat,
121+
axelrod.Grudger,
122+
axelrod.Random]
123+
self.assertTrue(demo_strategies, axelrod.demo_strategies)

docs/usage.rst

Lines changed: 32 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ repository::
1717

1818
pip install axelrod
1919

20-
Take a look at this asciicast which demonstrates how to do this (and run a basic
20+
Take a look at this asciicast which demonstrates how to do this (and run a demo
2121
tournament):
2222

2323
.. image:: https://asciinema.org/a/18590.png
@@ -42,10 +42,10 @@ Using as a library
4242
Creating and running a tournament
4343
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
4444

45-
We can list the so called 'basic strategies' by doing the following::
45+
We can list the so called 'demo strategies' by doing the following::
4646

4747
import axelrod
48-
strategies = [s() for s in axelrod.basic_strategies]
48+
strategies = [s() for s in axelrod.demo_strategies]
4949
for s in strategies:
5050
print s
5151

@@ -54,14 +54,14 @@ which gives::
5454
Alternator
5555
Cooperator
5656
Defector
57-
Random: 0.5
57+
Random
5858
Tit For Tat
5959

6060
Before creating a tournament let us add another :code:`Defector` to our strategies::
6161

6262
strategies.append(axelrod.Defector())
6363

64-
We can easily create a tournament with these basic strategies by doing the following::
64+
We can easily create a tournament with these demo strategies by doing the following::
6565

6666
tournament = axelrod.Tournament(strategies)
6767

@@ -71,7 +71,7 @@ To view the player types in our tournament::
7171

7272
which gives::
7373

74-
[Alternator, Cooperator, Defector, Random: 0.5, Tit For Tat, Defector]
74+
[Alternator, Cooperator, Defector, Random, Tit For Tat, Defector]
7575

7676
Now to run the tournament and save the results::
7777

@@ -84,8 +84,7 @@ First, let us view the scores::
8484

8585
which gives::
8686

87-
[[1.94, 1.927, 1.929, 1.962, 1.961, 1.977, 1.907, 1.948, 1.954, 1.967], [1.2, 1.146, 1.194, 1.215, 1.188, 1.191, 1.203, 1.2, 1.191, 1.179], [2.588, 2.588, 2.608, 2.624, 2.632, 2.596, 2.62, 2.592, 2.612, 2.572], [1.889, 1.976, 1.91, 1.888, 1.899, 1.893, 1.919, 1.926, 1.921, 1.912], [1.927, 1.95, 1.943, 1.944, 1.941, 1.943, 1.942, 1.942, 1.957, 1.951], [2.636, 2.532, 2.628, 2.58, 2.604, 2.648, 2.584, 2.556, 2.584, 2.62]]
88-
87+
[[1.952, 1.943, 1.951, 1.96, 1.924, 1.943, 2.007, 1.966, 2.003, 1.963], [1.221, 1.185, 1.173, 1.218, 1.206, 1.218, 1.221, 1.224, 1.188, 1.221], [2.588, 2.616, 2.608, 2.632, 2.588, 2.624, 2.612, 2.532, 2.588, 2.564], [1.917, 1.896, 1.901, 1.884, 1.931, 1.896, 1.87, 1.912, 1.886, 1.899], [1.967, 1.94, 1.929, 1.934, 1.957, 1.959, 1.948, 1.95, 1.937, 1.955], [2.636, 2.664, 2.632, 2.592, 2.588, 2.644, 2.604, 2.572, 2.612, 2.588]]
8988

9089
We see here that when we ran :code:`tournament.play()` it automatically repeated the round robin tournament 10 times (this is to deal with the stochasticity of the random players).
9190
The :code:`normalised_scores` contains a list of normalized scores for all players.
@@ -104,20 +103,20 @@ Finally, to obtain the ranking in a helpful format with all the names::
104103

105104
which gives::
106105

107-
['Defector', 'Defector', 'Alternator', 'Tit For Tat', 'Random: 0.5', 'Cooperator']
108-
106+
['Defector', 'Defector', 'Alternator', 'Tit For Tat', 'Random', 'Cooperator']
109107

110108
So in this particular instance our two defectors have won.
111-
Let us write a little script that will throw in a new :code:`TitForTat` player until the Tit-For-Tat player wins::
109+
Let us write a little script that will throw in a new :code:`TitForTat` player until the tit for tat player wins::
112110

113-
while results.ranked_names[0] == 'Defector':
111+
while ranks[0] == 'Defector':
114112
strategies.append(axelrod.TitForTat()) # Adding a new tit for tat player
115113
tournament = axelrod.Tournament(strategies)
116114
results = tournament.play()
115+
ranks = results.ranked_names
117116

118117
Once that has run let us see how many :code:`TitForTat` players were required::
119118

120-
results.ranked_names.count('Tit For Tat')
119+
ranks.count('Tit For Tat')
121120

122121
which gives::
123122

@@ -126,7 +125,7 @@ which gives::
126125
We can wrap all this in a function and use it to see how many :code:`TitForTat` are needed to overcome a varying number :code:`Defector`::
127126

128127
def find_number_of_tit_for_tat(number_of_defectors):
129-
strategies = [s() for s in axelrod.basic_strategies]
128+
strategies = [s() for s in axelrod.demo_strategies]
130129
for d in range(number_of_defectors - 1):
131130
strategies.append(axelrod.Defector())
132131
ranks = ['Defector'] # Creating a dummy list to start
@@ -161,10 +160,10 @@ Graphics
161160

162161
There are a variety of graphical outputs that the library can produce.
163162

164-
Let us see the global scores for the basic strategies::
163+
Let us see the global scores for the demo strategies::
165164

166165
import axelrod
167-
strategies = [s() for s in axelrod.basic_strategies]
166+
strategies = [s() for s in axelrod.demo_strategies]
168167
tournament = axelrod.Tournament(strategies)
169168
results = tournament.play()
170169
plot = axelrod.Plot(results)
@@ -173,13 +172,13 @@ Let us see the global scores for the basic strategies::
173172

174173
We see the output of this here:
175174

176-
.. image:: http://axelrod-python.github.io/tournament/assets/basic_strategies_boxplot.svg
175+
.. image:: _static/usage/demo_strategies_boxplot.svg
177176
:width: 50%
178177
:align: center
179178

180179
If we run the same tournament but with 5 :code:`Defector` and 3 :code:`TitForTat` we get:
181180

182-
.. image:: _static/usage/basic_strategies-5-Defector-3-TitForTat.svg
181+
.. image:: _static/usage/demo_strategies-5-Defector-3-TitForTat.svg
183182
:width: 50%
184183
:align: center
185184

@@ -190,15 +189,15 @@ By default the tournament is run for 200 rounds and repeated 10 times. This are
190189
the default values and can be changed::
191190

192191
import axelrod
193-
strategies = [s() for s in axelrod.basic_strategies]
192+
strategies = [s() for s in axelrod.demo_strategies]
194193
tournament = axelrod.Tournament(strategies, turns=20, repetitions=50)
195194
results = tournament.play()
196195
plot = axelrod.Plot(results)
197196
p = plot.boxplot()
198197
p.show()
199198

200199

201-
.. image:: _static/usage/basic_strategies_20_turns_50_repetitions.svg
200+
.. image:: _static/usage/demo_strategies_20_turns_50_repetitions.svg
202201
:width: 50%
203202
:align: center
204203

@@ -208,15 +207,15 @@ that is repeated. Here is an example showing the standard strategies playing a
208207
scaled version of the standard game::
209208

210209
import axelrod
211-
strategies = [s() for s in axelrod.basic_strategies]
210+
strategies = [s() for s in axelrod.demo_strategies]
212211
tournament = axelrod.Tournament(strategies, game=Game(30, 0, 50, 10))
213212
results = tournament.play()
214213
plot = axelrod.Plot(results)
215214
p = plot.boxplot()
216215
p.show()
217216

218217

219-
.. image:: _static/usage/basic_strategies_scaled_games.svg
218+
.. image:: _static/usage/demo_strategies_scaled_games.svg
220219
:width: 50%
221220
:align: center
222221

@@ -226,7 +225,7 @@ Payoff matrix
226225
Once a tournament has been run we can generate the payoff matrix that corresponds to it::
227226

228227
import axelrod
229-
strategies = [s() for s in axelrod.basic_strategies]
228+
strategies = [s() for s in axelrod.demo_strategies]
230229
tournament = axelrod.Tournament(strategies)
231230
results = tournament.play()
232231
results.payoff_matrix
@@ -249,7 +248,7 @@ Again, if :code:`matplotlib` is installed we can visualise this::
249248

250249
this is shown here:
251250

252-
.. image:: http://axelrod-python.github.io/tournament/assets/basic_strategies_payoff.svg
251+
.. image:: _static/usage/demo_strategies_payoff.svg
253252
:width: 50%
254253
:align: center
255254

@@ -366,23 +365,23 @@ Ecological variant
366365
To further study how this system evolves over time and how robust some of the observations we have made are let us look at how this game can be interpreted in an ecological setting.
367366

368367
The previous examples seem to indicate that even with a large amount of :code:`Defector`, :code:`TitForTat` wins the tournament.
369-
However, the Nash equilibria for the basic tournament shows that we have equilibria involving both those two strategies.
368+
However, the Nash equilibria for the demo tournament shows that we have equilibria involving both those two strategies.
370369

371370
An ecological variant of the tournament can be run with this library which allows to see how each strategy does in a population over time where the performance in the tournament indicates how likely the given strategy is to reproduce. To create such a variant simply run::
372371

373372
import axelrod
374-
strategies = [s() for s in axelrod.basic_strategies]
373+
strategies = [s() for s in axelrod.demo_strategies]
375374
tournament = axelrod.Tournament(strategies)
376375
results = tournament.play()
377376
eco = axelrod.Ecosystem(results)
378-
eco.reproduce(50) # Evolve the population over 50 time steps
377+
eco.reproduce(100) # Evolve the population over 100 time steps
379378
plot = axelrod.Plot(results)
380379
p = plot.stackplot(eco.population_sizes)
381380
p.show()
382381

383382
We see the output here:
384383

385-
.. image:: http://axelrod-python.github.io/tournament/assets/basic_strategies_reproduce.svg
384+
.. image:: _static/usage/demo_strategies_reproduce.svg
386385
:width: 50%
387386
:align: center
388387

@@ -392,7 +391,7 @@ The final population is completely cooperative.
392391
We can see how this differs when the initial population contains a large number of :code:`Defector`::
393392

394393
import axelrod
395-
strategies = [s() for s in axelrod.basic_strategies]
394+
strategies = [s() for s in axelrod.demo_strategies]
396395
tournament = axelrod.Tournament(strategies)
397396
results = tournament.play()
398397
eco = axelrod.Ecosystem(results, population=[.1, .05, .7, .1, .05])
@@ -403,14 +402,14 @@ We can see how this differs when the initial population contains a large number
403402

404403
We see the output here:
405404

406-
.. image:: _static/usage/basic_strategies-reproduce-large-initial-D.svg
405+
.. image:: _static/usage/demo_strategies-reproduce-large-initial-D.svg
407406
:width: 50%
408407
:align: center
409408

410409
Here is a with an even larger initial number of :code:`Defector` (note that it takes a little longer to stabilise)::
411410

412411
import axelrod
413-
strategies = [s() for s in axelrod.basic_strategies]
412+
strategies = [s() for s in axelrod.demo_strategies]
414413
tournament = axelrod.Tournament(strategies)
415414
results = tournament.play()
416415
eco = axelrod.Ecosystem(results, population=[.1, .05, 7, .1, .05])
@@ -421,7 +420,7 @@ Here is a with an even larger initial number of :code:`Defector` (note that it t
421420

422421
The output is shown here:
423422

424-
.. image:: _static/usage/basic_strategies-reproduce-huge-initial-D.svg
423+
.. image:: _static/usage/demo_strategies-reproduce-huge-initial-D.svg
425424
:width: 50%
426425
:align: center
427426

@@ -441,7 +440,7 @@ where C(b) is the total number of turns where a player chose to cooperate and TT
441440
A matrix of cooperation rates is available within a tournament's ResultSet::
442441

443442
import axelrod
444-
strategies = [s() for s in axelrod.basic_strategies]
443+
strategies = [s() for s in axelrod.demo_strategies]
445444
tournament = axelrod.Tournament(strategies)
446445
results = tournament.play()
447446
results.normalised_cooperation

0 commit comments

Comments
 (0)