Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
81f652d
[#688] Add methods and tests for player unique_id
meatballs Aug 15, 2016
e725340
[#688] Add comments to test
meatballs Aug 15, 2016
3ee5430
[#688] Fix PEP8 errors
meatballs Aug 15, 2016
4485c88
[#688] Fix PEP8 errors
meatballs Aug 15, 2016
f4763e1
[#688] Fix PEP8 errors
meatballs Aug 15, 2016
c6959f8
[#688] Fix PEP8 errors
meatballs Aug 15, 2016
1c8760d
[#688] Fix PEP8 errors
meatballs Aug 15, 2016
43fa94b
[#688] Add test for id in player init
meatballs Aug 15, 2016
f309b1d
[#688] Add comments to player methods
meatballs Aug 15, 2016
b0bd0d2
[#688] Remove player methods and create id and index in strategies.__…
meatballs Aug 15, 2016
2db0298
[#688] Add encoding instruction to test_player.py
meatballs Aug 16, 2016
95a2ce6
[#688] Add test to ensure all strategies have an id
meatballs Aug 16, 2016
82e2bb6
[#688] Add id tests for single and multi word strategy names
meatballs Aug 16, 2016
89cefe1
[#688] Add tests for strategy_index
meatballs Aug 16, 2016
7d18f2c
[#688] Fix PEP8 errors
meatballs Aug 16, 2016
b87b2ec
[#688] Add test to ensure length of strategy_index matches that of al…
meatballs Aug 16, 2016
a2eb433
[#688] Fix names for Cycler strategies
meatballs Aug 16, 2016
9a63d6b
[#688] Fix names for Retaliate strategies
meatballs Aug 16, 2016
38be270
[#688] Fix names for GoBtMajority strategies
meatballs Aug 16, 2016
3c93bf8
[#688] Fix instance name for Cycler classes
meatballs Aug 16, 2016
5de01b9
[#688] Use format() instead of % to keep quantified code happy
meatballs Aug 16, 2016
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 9 additions & 2 deletions axelrod/player.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,19 @@ def is_basic(s):
inspects_source = s.classifier['inspects_source']
manipulates_source = s.classifier['manipulates_source']
manipulates_state = s.classifier['manipulates_state']
return (not stochastic) and (not inspects_source) and (not manipulates_source) and (not manipulates_state) and (depth in (0, 1))
return (
not stochastic and
not inspects_source and
not manipulates_source and
not manipulates_state and
depth in (0, 1)
)


def obey_axelrod(s):
"""
A function to check if a strategy obeys Axelrod's original tournament rules.
A function to check if a strategy obeys Axelrod's original tournament
rules.
"""
classifier = s.classifier
return not (
Expand Down
15 changes: 10 additions & 5 deletions axelrod/strategies/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,19 @@
MetaMajorityMemoryOne, MetaWinnerMemoryOne, MetaMajorityFiniteMemory,
MetaWinnerFiniteMemory, MetaMajorityLongMemory, MetaWinnerLongMemory,
MetaMixer
)
)

all_strategies.extend([MetaHunter, MetaMajority, MetaMinority, MetaWinner,
MetaMajorityMemoryOne, MetaWinnerMemoryOne,
MetaMajorityFiniteMemory, MetaWinnerFiniteMemory,
MetaMajorityLongMemory, MetaWinnerLongMemory, MetaMixer])
all_strategies.extend([
MetaHunter, MetaMajority, MetaMinority, MetaWinner, MetaMajorityMemoryOne,
MetaWinnerMemoryOne, MetaMajorityFiniteMemory, MetaWinnerFiniteMemory,
MetaMajorityLongMemory, MetaWinnerLongMemory, MetaMixer])


def strategy_id(strategy):
return strategy.name.lower().replace(' ', '_')

strategy_index = {strategy_id(s): s for s in all_strategies}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is index the right word? Makes me think of a number... Not terribly offended by index though.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It makes me think of an index at the back of a book, or a database index - something where you look things up!!

Not too bothered myself, if there's a better suggestion.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No I think now that you've said that I'm cool with index. Ignore me :)


# Distinguished strategy collections in addition to
# `all_strategies` from _strategies.py
demo_strategies = [Cooperator, Defector, TitForTat, Grudger, Random]
Expand Down
13 changes: 12 additions & 1 deletion axelrod/strategies/cycler.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import copy


class AntiCycler(Player):
"""
A player that follows a sequence of plays that contains no cycles:
Expand Down Expand Up @@ -67,7 +68,7 @@ def __init__(self, cycle="CCD"):
"""
Player.__init__(self)
self.cycle = cycle
self.name += " " + cycle
self.name = "Cycler {0}".format(cycle)
self.classifier['memory_depth'] = len(cycle) - 1

def strategy(self, opponent):
Expand All @@ -77,6 +78,8 @@ def strategy(self, opponent):


class CyclerDC(Cycler):

name = 'Cycler DC'
classifier = copy.copy(Cycler.classifier)
classifier['memory_depth'] = 1

Expand All @@ -86,6 +89,8 @@ def __init__(self, cycle="DC"):


class CyclerCCD(Cycler):

name = 'Cycler CCD'
classifier = copy.copy(Cycler.classifier)
classifier['memory_depth'] = 2

Expand All @@ -95,6 +100,8 @@ def __init__(self, cycle="CCD"):


class CyclerDDC(Cycler):

name = 'Cycler DDC'
classifier = copy.copy(Cycler.classifier)
classifier['memory_depth'] = 2

Expand All @@ -104,6 +111,8 @@ def __init__(self, cycle="DDC"):


class CyclerCCCD(Cycler):

name = 'Cycler CCCD'
classifier = copy.copy(Cycler.classifier)
classifier['memory_depth'] = 3

Expand All @@ -113,6 +122,8 @@ def __init__(self, cycle="CCCD"):


class CyclerCCCCCD(Cycler):

name = 'Cycler CCCCCD'
classifier = copy.copy(Cycler.classifier)
classifier['memory_depth'] = 5

Expand Down
13 changes: 12 additions & 1 deletion axelrod/strategies/gobymajority.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ class GoByMajority(Player):
default this is 0)
"""

name = 'Go By Marjority'
classifier = {
'stochastic': False,
'inspects_source': False,
Expand Down Expand Up @@ -49,7 +50,8 @@ def __init__(self, memory_depth=float('inf'), soft=True):
else:
self.memory = 0

self.name = 'Go By Majority' + (self.memory > 0) * (": %i" % self.memory)
self.name = (
'Go By Majority' + (self.memory > 0) * (": %i" % self.memory))
if self.soft:
self.name = "Soft " + self.name
else:
Expand Down Expand Up @@ -80,6 +82,7 @@ class GoByMajority40(GoByMajority):
"""
GoByMajority player with a memory of 40.
"""
name = 'Go By Majority 40'
classifier = copy.copy(GoByMajority.classifier)
classifier['memory_depth'] = 40

Expand All @@ -93,6 +96,7 @@ class GoByMajority20(GoByMajority):
"""
GoByMajority player with a memory of 20.
"""
name = 'Go By Majority 20'
classifier = copy.copy(GoByMajority.classifier)
classifier['memory_depth'] = 20

Expand All @@ -106,6 +110,7 @@ class GoByMajority10(GoByMajority):
"""
GoByMajority player with a memory of 10.
"""
name = 'Go By Majority 10'
classifier = copy.copy(GoByMajority.classifier)
classifier['memory_depth'] = 10

Expand All @@ -119,6 +124,7 @@ class GoByMajority5(GoByMajority):
"""
GoByMajority player with a memory of 5.
"""
name = 'Go By Majority 5'
classifier = copy.copy(GoByMajority.classifier)
classifier['memory_depth'] = 5

Expand All @@ -136,6 +142,7 @@ class HardGoByMajority(GoByMajority):
An optional memory attribute will limit the number of turns remembered (by
default this is 0)
"""
name = 'Hard Go By Majority'

@init_args
def __init__(self, memory_depth=float('inf'), soft=False):
Expand All @@ -147,6 +154,7 @@ class HardGoByMajority40(HardGoByMajority):
"""
HardGoByMajority player with a memory of 40.
"""
name = 'Hard Go By Majority 40'
classifier = copy.copy(GoByMajority.classifier)
classifier['memory_depth'] = 40

Expand All @@ -160,6 +168,7 @@ class HardGoByMajority20(HardGoByMajority):
"""
HardGoByMajority player with a memory of 20.
"""
name = 'Hard Go By Majority 20'
classifier = copy.copy(GoByMajority.classifier)
classifier['memory_depth'] = 20

Expand All @@ -173,6 +182,7 @@ class HardGoByMajority10(HardGoByMajority):
"""
HardGoByMajority player with a memory of 10.
"""
name = 'Hard Go By Majority 10'
classifier = copy.copy(GoByMajority.classifier)
classifier['memory_depth'] = 10

Expand All @@ -186,6 +196,7 @@ class HardGoByMajority5(HardGoByMajority):
"""
HardGoByMajority player with a memory of 5.
"""
name = 'Hard Go By Majority 5'
classifier = copy.copy(GoByMajority.classifier)
classifier['memory_depth'] = 5

Expand Down
12 changes: 12 additions & 0 deletions axelrod/strategies/retaliate.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ class Retaliate(Player):
A player starts by cooperating but will retaliate once the opponent
has won more than 10 percent times the number of defections the player has.
"""

name = 'Retaliate'
classifier = {
'memory_depth': float('inf'), # Long memory
'stochastic': False,
Expand Down Expand Up @@ -52,11 +54,14 @@ def reset(self):
Player.reset(self)
self.play_counts = defaultdict(int)


class Retaliate2(Retaliate):
"""
Retaliate player with a threshold of 8 percent.
"""

name = 'Retaliate 2'

def __init__(self, retaliation_threshold=0.08):
super(Retaliate2, self).__init__(
retaliation_threshold=retaliation_threshold)
Expand All @@ -67,6 +72,8 @@ class Retaliate3(Retaliate):
Retaliate player with a threshold of 5 percent.
"""

name = 'Retaliate 3'

def __init__(self, retaliation_threshold=0.05):
super(Retaliate3, self).__init__(
retaliation_threshold=retaliation_threshold)
Expand All @@ -80,6 +87,7 @@ class LimitedRetaliate(Player):
retaliation limit (20 defections).
"""

name = 'Limited Retaliate'
classifier = {
'memory_depth': float('inf'), # Long memory
'stochastic': False,
Expand Down Expand Up @@ -156,6 +164,8 @@ class LimitedRetaliate2(LimitedRetaliate):
retaliation limit of 15.
"""

name = 'Limited Retaliate 2'

def __init__(self, retaliation_threshold=0.08, retaliation_limit=15):
super(LimitedRetaliate2, self).__init__(
retaliation_threshold=retaliation_threshold,
Expand All @@ -168,6 +178,8 @@ class LimitedRetaliate3(LimitedRetaliate):
retaliation limit of 20.
"""

name = 'Limited Retaliate 3'

def __init__(self, retaliation_threshold=0.05, retaliation_limit=20):
super(LimitedRetaliate3, self).__init__(
retaliation_threshold=retaliation_threshold,
Expand Down
29 changes: 27 additions & 2 deletions axelrod/tests/unit/test_classification.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ def test_known_classifiers(self):

for s in axelrod.all_strategies:
s = s()
self.assertTrue(None not in [s.classifier[key] for key in known_keys])
self.assertTrue(
None not in [s.classifier[key] for key in known_keys])

def test_multiple_instances(self):
"""Certain instances of classes of strategies will have different
Expand Down Expand Up @@ -130,6 +131,29 @@ def test_is_basic(self):

class TestStrategies(unittest.TestCase):

def test_strategy_id(self):
for strategy in axelrod.all_strategies:
self.assertIsNotNone(axelrod.strategy_id(strategy))

self.assertEqual(
axelrod.strategy_id(axelrod.TitForTat),
'tit_for_tat')

self.assertEqual(
axelrod.strategy_id(axelrod.Defector),
'defector')

def test_strategy_index(self):
for strategy in axelrod.all_strategies:
unique_id = strategy.name.lower().replace(' ', '_')
self.assertIn(unique_id, axelrod.strategy_index)

self.assertEqual(
len(axelrod.all_strategies), len(axelrod.strategy_index))

self.assertIn('tit_for_tat', axelrod.strategy_index)
self.assertIn('defector', axelrod.strategy_index)

def test_strategy_list(self):
for strategy_list in ["all_strategies",
"demo_strategies",
Expand Down Expand Up @@ -184,7 +208,8 @@ def test_meta_inclusion(self):
self.assertTrue(axelrod.MetaMajority in axelrod.strategies)

self.assertTrue(axelrod.MetaHunter in axelrod.strategies)
self.assertFalse(axelrod.MetaHunter in axelrod.long_run_time_strategies)
self.assertFalse(
axelrod.MetaHunter in axelrod.long_run_time_strategies)

def test_demo_strategies(self):
demo_strategies = [axelrod.Cooperator,
Expand Down
27 changes: 15 additions & 12 deletions axelrod/tests/unit/test_player.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
import copy
# -*- coding: utf-8 -*-
import inspect
import random
import unittest

import axelrod
from axelrod import DefaultGame, Game, Player, simulate_play

from axelrod import DefaultGame, Player, simulate_play

C, D = axelrod.Actions.C, axelrod.Actions.D


def cooperate(self):
return C


def defect(self):
return D

Expand Down Expand Up @@ -71,7 +71,9 @@ def test_noisy_play(self):
self.assertEqual(p2.history[0], D)

def test_strategy(self):
self.assertRaises(NotImplementedError, self.player().strategy, self.player())
self.assertRaises(
NotImplementedError, self.player().strategy, self.player())


def test_responses(test_class, P1, P2, history_1, history_2, responses,
random_seed=None, attrs=None):
Expand Down Expand Up @@ -128,8 +130,9 @@ def test_initialisation(self):
if self.__class__ != TestPlayer:
player = self.player()
self.assertEqual(player.history, [])
self.assertEqual(player.match_attributes,
{'length': -1, 'game': DefaultGame, 'noise': 0})
self.assertEqual(
player.match_attributes,
{'length': -1, 'game': DefaultGame, 'noise': 0})
self.assertEqual(player.cooperations, 0)
self.assertEqual(player.defections, 0)
self.classifier_test(self.expected_class_classifier)
Expand Down Expand Up @@ -242,7 +245,6 @@ def responses_test(self, history_1, history_2, responses, random_seed=None,
self, P1, P2, history_1, history_2, responses,
random_seed=random_seed, attrs=attrs)


def classifier_test(self, expected_class_classifier=None):
"""Test that the keys in the expected_classifier dictionary give the
expected values in the player classifier dictionary. Also checks that
Expand All @@ -259,12 +261,13 @@ def classifier_test(self, expected_class_classifier=None):
self.assertTrue('memory_depth' in player.classifier,
msg="memory_depth not in classifier")
self.assertTrue('stochastic' in player.classifier,
msg="stochastic not in classifier")
msg="stochastic n§ot in classifier")
for key in TestOpponent.classifier:
self.assertEqual(player.classifier[key],
self.expected_classifier[key],
msg="%s - Behaviour: %s != Expected Behaviour: %s" %
(key, player.classifier[key], self.expected_classifier[key]))
self.assertEqual(
player.classifier[key],
self.expected_classifier[key],
msg="%s - Behaviour: %s != Expected Behaviour: %s" %
(key, player.classifier[key], self.expected_classifier[key]))


class TestHeadsUp(unittest.TestCase):
Expand Down