Skip to content

Commit b38a016

Browse files
committed
Updated classifier checker to new API
1 parent fc53eee commit b38a016

23 files changed

+424
-348
lines changed

axelrod/classifier.py

+25-9
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
from typing import Any, Callable, Generic, List, Optional, Set, Text, TypeVar, \
2-
Union
1+
from typing import Any, Callable, Generic, List, Optional, Set, Text, Type, \
2+
TypeVar, Union
33

44
import yaml
55

@@ -11,11 +11,11 @@
1111

1212

1313
class Classifier(Generic[T]):
14-
def __init__(self, name: Text, f: Callable[[Player], T]):
14+
def __init__(self, name: Text, f: Callable[[Type[Player]], T]):
1515
self.name = name
1616
self.f = f
1717

18-
def calc_for_player(self, player: Player) -> T:
18+
def calc_for_player(self, player: Type[Player]) -> T:
1919
if self.name in player.classifier:
2020
return player.classifier[self.name]
2121

@@ -45,7 +45,7 @@ def calc_for_player(self, player: Player) -> T:
4545

4646

4747
def rebuild_classifier_table(classifiers: List[Classifier],
48-
players: List[Player],
48+
players: List[Type[Player]],
4949
path: Text = ALL_CLASSIFIERS_PATH) -> None:
5050
all_player_dicts = dict()
5151
for p in players:
@@ -72,16 +72,32 @@ def __new__(cls):
7272
return cls._instance
7373

7474
@classmethod
75-
def get(cls, classifier: Classifier, player: Player) -> Any:
75+
def get(cls, classifier: Union[Classifier, Text],
76+
player: Player) -> Any:
77+
# Classifier may be the name or an instance. Convert to name.
78+
if not isinstance(classifier, str):
79+
classifier = classifier.name
80+
81+
# Factory-generated players won't exist in the table. As well, some
82+
# players, like Random, may change classifiers at construction time;
83+
# this get() function takes a player instance, while the saved-values
84+
# are from operations on the player object itself.
85+
if classifier in player.classifier:
86+
return player.classifier[classifier]
87+
7688
def return_missing() -> None:
89+
"""What to do with a missing entry."""
7790
nonlocal classifier
7891
nonlocal player
79-
print("Classifier {} not found for {}.".format(classifier, player))
92+
93+
print("Classifier {} not found for {}.".format(classifier,
94+
player.name))
8095
print("Consider rebuilding classifier table.")
96+
return None
8197

82-
if player not in cls.all_player_dicts:
98+
if player.name not in cls.all_player_dicts:
8399
return return_missing()
84-
player_classifiers = cls.all_player_dicts[player]
100+
player_classifiers = cls.all_player_dicts[player.name]
85101

86102
if classifier not in player_classifiers:
87103
return return_missing()

axelrod/deterministic_cache.py

+3-1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
from collections import UserDict
1717
from typing import List, Tuple
1818

19+
from axelrod.classifier import Classifiers
1920
from .action import Action
2021
from .player import Player
2122

@@ -57,7 +58,8 @@ def _is_valid_key(key: CachePlayerKey) -> bool:
5758
):
5859
return False
5960

60-
if key[0].classifier["stochastic"] or key[1].classifier["stochastic"]:
61+
if Classifiers().get("stochastic", key[0]) or Classifiers().get(
62+
"stochastic", key[1]):
6163
return False
6264

6365
return True

axelrod/match.py

+4-3
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44
import axelrod.interaction_utils as iu
55
from axelrod import DEFAULT_TURNS
66
from axelrod.action import Action
7+
from axelrod.classifier import Classifiers
78
from axelrod.game import Game
8-
99
from .deterministic_cache import DeterministicCache
1010

1111
C, D = Action.C, Action.D
@@ -14,7 +14,7 @@
1414
def is_stochastic(players, noise):
1515
"""Determines if a match is stochastic -- true if there is noise or if any
1616
of the players involved is stochastic."""
17-
return noise or any(p.classifier["stochastic"] for p in players)
17+
return noise or any(Classifiers().get("stochastic", p) for p in players)
1818

1919

2020
class Match(object):
@@ -117,7 +117,8 @@ def _cache_update_required(self):
117117
return (
118118
not self.noise
119119
and self._cache.mutable
120-
and not (any(p.classifier["stochastic"] for p in self.players))
120+
and not (
121+
any(Classifiers().get("stochastic", p) for p in self.players))
121122
)
122123

123124
def _cached_enough_turns(self, cache_key, turns):

axelrod/player.py

+10-11
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import numpy as np
88

99
from axelrod.action import Action
10+
from axelrod.classifier import Classifiers
1011
from axelrod.game import DefaultGame
1112
from axelrod.history import History
1213
from axelrod.random_ import random_flip
@@ -21,11 +22,11 @@ def is_basic(s):
2122
"""
2223
Defines criteria for a strategy to be considered 'basic'
2324
"""
24-
stochastic = s.classifier["stochastic"]
25-
depth = s.classifier["memory_depth"]
26-
inspects_source = s.classifier["inspects_source"]
27-
manipulates_source = s.classifier["manipulates_source"]
28-
manipulates_state = s.classifier["manipulates_state"]
25+
stochastic = Classifiers().get("stochastic", s)
26+
depth = Classifiers().get("depth", s)
27+
inspects_source = Classifiers().get("inspects_source", s)
28+
manipulates_source = Classifiers().get("manipulates_source", s)
29+
manipulates_state = Classifiers().get("manipulates_state", s)
2930
return (
3031
not stochastic
3132
and not inspects_source
@@ -40,12 +41,10 @@ def obey_axelrod(s):
4041
A function to check if a strategy obeys Axelrod's original tournament
4142
rules.
4243
"""
43-
classifier = s.classifier
44-
return not (
45-
classifier["inspects_source"]
46-
or classifier["manipulates_source"]
47-
or classifier["manipulates_state"]
48-
)
44+
for c in ["inspects_source", "manipulates_source", "manipulates_state"]:
45+
if Classifiers().get(c, s):
46+
return False
47+
return True
4948

5049

5150
def simultaneous_play(player, coplayer, noise=0):

axelrod/strategies/__init__.py

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
from ..classifier import Classifiers
12
from ..player import is_basic, obey_axelrod
23
from ._strategies import *
34
from ._filters import passes_filterset
@@ -84,10 +85,10 @@
8485
strategies = [s for s in all_strategies if obey_axelrod(s())]
8586

8687
long_run_time_strategies = [
87-
s for s in all_strategies if s().classifier["long_run_time"]
88+
s for s in all_strategies if Classifiers().get("long_run_time", s)
8889
]
8990
short_run_time_strategies = [
90-
s for s in strategies if not s().classifier["long_run_time"]
91+
s for s in strategies if not Classifiers().get("long_run_time", s)
9192
]
9293
cheating_strategies = [s for s in all_strategies if not obey_axelrod(s())]
9394

axelrod/strategies/_filters.py

+4-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import operator
22
from collections import namedtuple
33

4+
from axelrod.classifier import Classifiers
5+
46

57
def passes_operator_filter(player, classifier_key, value, operator):
68
"""
@@ -43,7 +45,7 @@ class ExampleStrategy(Player):
4345
True if the value from the strategy's classifier dictionary matches
4446
the value and operator passed to the function.
4547
"""
46-
classifier_value = player.classifier[classifier_key]
48+
classifier_value = Classifiers().get(classifier_key, player)
4749
return operator(classifier_value, value)
4850

4951

@@ -85,7 +87,7 @@ class ExampleStrategy(Player):
8587
"""
8688
result = True
8789
for entry in value:
88-
if entry not in player.classifier[classifier_key]:
90+
if entry not in Classifiers().get(classifier_key, player):
8991
result = False
9092
return result
9193

axelrod/strategies/meta.py

+34-44
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
import random
22

3+
import numpy as np
4+
from numpy.random import choice
5+
36
from axelrod.action import Action
7+
from axelrod.classifier import Classifiers
48
from axelrod.player import Player, obey_axelrod
59
from axelrod.strategies import TitForTat
610
from axelrod.strategy_transformers import NiceTransformer
7-
8-
import numpy as np
9-
from numpy.random import choice
10-
1111
from ._strategies import all_strategies
1212
from .hunter import (
1313
AlternatorHunter,
@@ -69,10 +69,12 @@ def __init__(self, team=None):
6969
"manipulates_source",
7070
"manipulates_state",
7171
]:
72-
self.classifier[key] = any(t.classifier[key] for t in self.team)
72+
self.classifier[key] = any(
73+
Classifiers().get(key, t) for t in self.team)
7374

7475
for t in self.team:
75-
self.classifier["makes_use_of"].update(t.classifier["makes_use_of"])
76+
self.classifier["makes_use_of"].update(
77+
Classifiers().get("makes_use_of", t))
7678

7779
self._last_results = None
7880

@@ -332,7 +334,8 @@ class MetaMajorityMemoryOne(MetaMajority):
332334
name = "Meta Majority Memory One"
333335

334336
def __init__(self):
335-
team = [s for s in ordinary_strategies if s().classifier["memory_depth"] <= 1]
337+
team = [s for s in ordinary_strategies if
338+
Classifiers().get("memory_depth", s) <= 1]
336339
super().__init__(team=team)
337340
self.classifier["long_run_time"] = False
338341

@@ -348,11 +351,8 @@ class MetaMajorityFiniteMemory(MetaMajority):
348351
name = "Meta Majority Finite Memory"
349352

350353
def __init__(self):
351-
team = [
352-
s
353-
for s in ordinary_strategies
354-
if s().classifier["memory_depth"] < float("inf")
355-
]
354+
team = [s for s in ordinary_strategies if
355+
Classifiers().get("memory_depth", s) < float("inf")]
356356
super().__init__(team=team)
357357

358358

@@ -367,11 +367,8 @@ class MetaMajorityLongMemory(MetaMajority):
367367
name = "Meta Majority Long Memory"
368368

369369
def __init__(self):
370-
team = [
371-
s
372-
for s in ordinary_strategies
373-
if s().classifier["memory_depth"] == float("inf")
374-
]
370+
team = [s for s in ordinary_strategies if
371+
Classifiers().get("memory_depth", s) == float("inf")]
375372
super().__init__(team=team)
376373

377374

@@ -386,7 +383,8 @@ class MetaWinnerMemoryOne(MetaWinner):
386383
name = "Meta Winner Memory One"
387384

388385
def __init__(self):
389-
team = [s for s in ordinary_strategies if s().classifier["memory_depth"] <= 1]
386+
team = [s for s in ordinary_strategies if
387+
Classifiers().get("memory_depth", s) <= 1]
390388
super().__init__(team=team)
391389
self.classifier["long_run_time"] = False
392390

@@ -402,11 +400,8 @@ class MetaWinnerFiniteMemory(MetaWinner):
402400
name = "Meta Winner Finite Memory"
403401

404402
def __init__(self):
405-
team = [
406-
s
407-
for s in ordinary_strategies
408-
if s().classifier["memory_depth"] < float("inf")
409-
]
403+
team = [s for s in ordinary_strategies if
404+
Classifiers().get("memory_depth", s) < float("inf")]
410405
super().__init__(team=team)
411406

412407

@@ -421,11 +416,8 @@ class MetaWinnerLongMemory(MetaWinner):
421416
name = "Meta Winner Long Memory"
422417

423418
def __init__(self):
424-
team = [
425-
s
426-
for s in ordinary_strategies
427-
if s().classifier["memory_depth"] == float("inf")
428-
]
419+
team = [s for s in ordinary_strategies if
420+
Classifiers().get("memory_depth", s) == float("inf")]
429421
super().__init__(team=team)
430422

431423

@@ -440,7 +432,8 @@ class MetaWinnerDeterministic(MetaWinner):
440432
name = "Meta Winner Deterministic"
441433

442434
def __init__(self):
443-
team = [s for s in ordinary_strategies if not s().classifier["stochastic"]]
435+
team = [s for s in ordinary_strategies if
436+
not Classifiers().get("stochastic", s)]
444437
super().__init__(team=team)
445438
self.classifier["stochastic"] = False
446439

@@ -456,7 +449,8 @@ class MetaWinnerStochastic(MetaWinner):
456449
name = "Meta Winner Stochastic"
457450

458451
def __init__(self):
459-
team = [s for s in ordinary_strategies if s().classifier["stochastic"]]
452+
team = [s for s in ordinary_strategies if
453+
Classifiers().get("stochastic", s)]
460454
super().__init__(team=team)
461455

462456

@@ -512,7 +506,8 @@ class NMWEDeterministic(NiceMetaWinnerEnsemble):
512506
name = "NMWE Deterministic"
513507

514508
def __init__(self):
515-
team = [s for s in ordinary_strategies if not s().classifier["stochastic"]]
509+
team = [s for s in ordinary_strategies if
510+
not Classifiers().get("stochastic", s)]
516511
super().__init__(team=team)
517512
self.classifier["stochastic"] = True
518513

@@ -528,7 +523,8 @@ class NMWEStochastic(NiceMetaWinnerEnsemble):
528523
name = "NMWE Stochastic"
529524

530525
def __init__(self):
531-
team = [s for s in ordinary_strategies if s().classifier["stochastic"]]
526+
team = [s for s in ordinary_strategies if
527+
Classifiers().get("stochastic", s)]
532528
super().__init__(team=team)
533529

534530

@@ -543,11 +539,8 @@ class NMWEFiniteMemory(NiceMetaWinnerEnsemble):
543539
name = "NMWE Finite Memory"
544540

545541
def __init__(self):
546-
team = [
547-
s
548-
for s in ordinary_strategies
549-
if s().classifier["memory_depth"] < float("inf")
550-
]
542+
team = [s for s in ordinary_strategies if
543+
Classifiers().get("memory_depth", s) < float("inf")]
551544
super().__init__(team=team)
552545

553546

@@ -562,11 +555,8 @@ class NMWELongMemory(NiceMetaWinnerEnsemble):
562555
name = "NMWE Long Memory"
563556

564557
def __init__(self):
565-
team = [
566-
s
567-
for s in ordinary_strategies
568-
if s().classifier["memory_depth"] == float("inf")
569-
]
558+
team = [s for s in ordinary_strategies if
559+
Classifiers().get("memory_depth", s) == float("inf")]
570560
super().__init__(team=team)
571561

572562

@@ -581,7 +571,8 @@ class NMWEMemoryOne(NiceMetaWinnerEnsemble):
581571
name = "NMWE Memory One"
582572

583573
def __init__(self):
584-
team = [s for s in ordinary_strategies if s().classifier["memory_depth"] <= 1]
574+
team = [s for s in ordinary_strategies if
575+
Classifiers().get("memory_depth", s) <= 1]
585576
super().__init__(team=team)
586577
self.classifier["long_run_time"] = False
587578

@@ -627,7 +618,6 @@ def __init__(
627618
start_strategy_duration: int = 15,
628619
):
629620
super().__init__(team=[start_strategy])
630-
self.classifier["stochastic"] = True
631621
self.p_memory_delete = p_memory_delete
632622
self.p_memory_alter = p_memory_alter
633623
self.loss_value = loss_value

0 commit comments

Comments
 (0)