Skip to content

Change namespace and add adapter #1335

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 7 commits into from
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
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
44 changes: 24 additions & 20 deletions axelrod/__init__.py
Original file line number Diff line number Diff line change
@@ -1,24 +1,28 @@
DEFAULT_TURNS = 200

# The order of imports matters!
from axelrod.ipd import graph
from axelrod.ipd.action import Action
from axelrod.ipd.random_ import random_choice, random_flip, seed, Pdf
from axelrod.ipd import eigen
from axelrod.ipd.plot import Plot
from axelrod.ipd.history import History, LimitedHistory
from axelrod.player import BasePlayer
from axelrod.ipd.player import IpdPlayer
from axelrod.ipd.classifier import Classifiers
from axelrod.ipd.evolvable_player import EvolvablePlayer
from axelrod.game import BaseGame
from axelrod.ipd.game import IpdGame, DefaultGame
from axelrod.ipd.moran import MoranProcess, ApproximateMoranProcess
from axelrod.ipd.strategies import *
from axelrod.ipd.match_generator import *
from axelrod.ipd.tournament import IpdTournament
Copy link
Member

@drvinceknight drvinceknight Apr 21, 2020

Choose a reason for hiding this comment

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

Would the idea be (for now from the pov of keeping the current API) to change this to:

Suggested change
from axelrod.ipd.tournament import IpdTournament
import axelrod.ipd.tournament.IpdTournament as Tournament

Or perhaps it would be nicer to have:

axelrod.ipd.tournament.IpdTournament

as

axelrod.ipd.tournament.Tournament

As the namespace takes care of the tournament? So theoretically we would also have:

axelrod.<other_game>.tournament.Tournament

At some point?

Copy link
Member

Choose a reason for hiding this comment

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

And then similarly for the IpdMatch? Perhaps just have axelrod.ipd.match.Match? Which makes things easier now but I believe also later as when we have multiple game types a Match is always the name of the object needed and the namespace takes care of behaviour?

Copy link
Member

Choose a reason for hiding this comment

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

I'm not sure we need a new Match for each game -- maybe a generic Match class could work? Same for Tournaments -- maybe these classes don't need to know about the Game and the Players, they just need to be handed Players and a compatible Game.

Copy link
Member

Choose a reason for hiding this comment

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

That would be great!

from axelrod.ipd.ecosystem import Ecosystem
from axelrod.ipd.match import IpdMatch
from axelrod.ipd.result_set import ResultSet
from axelrod.ipd.deterministic_cache import DeterministicCache
from axelrod.ipd import fingerprint
from axelrod.ipd.fingerprint import AshlockFingerprint, TransitiveFingerprint
from axelrod.ipd import interaction_utils
from axelrod.ipd.mock_player import MockPlayer
from axelrod.version import __version__
from axelrod.load_data_ import load_pso_tables, load_weights
from axelrod import graph
from axelrod.action import Action
from axelrod.random_ import random_choice, random_flip, seed, Pdf
from axelrod.plot import Plot
from axelrod.game import DefaultGame, Game
from axelrod.history import History, LimitedHistory
from axelrod.player import Player
from axelrod.classifier import Classifiers
from axelrod.evolvable_player import EvolvablePlayer
from axelrod.mock_player import MockPlayer
from axelrod.match import Match
from axelrod.moran import MoranProcess, ApproximateMoranProcess
from axelrod.strategies import *
from axelrod.deterministic_cache import DeterministicCache
from axelrod.match_generator import *
from axelrod.tournament import Tournament
from axelrod.result_set import ResultSet
from axelrod.ecosystem import Ecosystem
from axelrod.fingerprint import AshlockFingerprint, TransitiveFingerprint
55 changes: 8 additions & 47 deletions axelrod/game.py
Original file line number Diff line number Diff line change
@@ -1,46 +1,18 @@
from typing import Tuple, Union

from axelrod import Action

C, D = Action.C, Action.D
import axelrod as axl

Score = Union[int, float]


class Game(object):
"""Container for the game matrix and scoring logic.

Attributes
----------
scores: dict
The numerical score attribute to all combinations of action pairs.
"""

def __init__(self, r: Score = 3, s: Score = 0, t: Score = 5, p: Score = 1) -> None:
"""Create a new game object.

Parameters
----------
r: int or float
Score obtained by both players for mutual cooperation.
s: int or float
Score obtained by a player for cooperating against a defector.
t: int or float
Score obtained by a player for defecting against a cooperator.
p: int or float
Score obtained by both player for mutual defection.
"""
self.scores = {(C, C): (r, r), (D, D): (p, p), (C, D): (s, t), (D, C): (t, s)}
class BaseGame(object):
"""Container for the scoring logic."""

def RPST(self) -> Tuple[Score, Score, Score, Score]:
"""Returns game matrix values in Press and Dyson notation."""
R = self.scores[(C, C)][0]
P = self.scores[(D, D)][0]
S = self.scores[(C, D)][0]
T = self.scores[(D, C)][0]
return R, P, S, T
def __init__(self) -> None:
"""Create a new game object."""
pass

def score(self, pair: Tuple[Action, Action]) -> Tuple[Score, Score]:
def score(self, pair: Tuple[axl.Action, axl.Action]) -> Tuple[Score, Score]:
"""Returns the appropriate score for a decision pair.

Parameters
Expand All @@ -53,15 +25,4 @@ def score(self, pair: Tuple[Action, Action]) -> Tuple[Score, Score]:
tuple of int or float
Scores for two player resulting from their actions.
"""
return self.scores[pair]

def __repr__(self) -> str:
return "Axelrod game: (R,P,S,T) = {}".format(self.RPST())

def __eq__(self, other):
if not isinstance(other, Game):
return False
return self.RPST() == other.RPST()


DefaultGame = Game()
raise NotImplementedError()
File renamed without changes.
34 changes: 17 additions & 17 deletions axelrod/_strategy_utils.py → axelrod/ipd/_strategy_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@
import itertools
from functools import lru_cache

from axelrod.action import Action
from axelrod.strategies.cooperator import Cooperator
from axelrod.strategies.defector import Defector
from axelrod.ipd.action import Action
from axelrod.ipd.strategies.cooperator import Cooperator
from axelrod.ipd.strategies.defector import Defector

C, D = Action.C, Action.D

Expand Down Expand Up @@ -53,9 +53,9 @@ def inspect_strategy(inspector, opponent):

Parameters
----------
inspector: Player
inspector: IpdPlayer
The player doing the inspecting
opponent: Player
opponent: IpdPlayer
The player being inspected

Returns
Expand All @@ -82,9 +82,9 @@ def _limited_simulate_play(player_1, player_2, h1):

Parameters
----------
player_1: Player
player_1: IpdPlayer
The player whose move is already known.
player_2: Player
player_2: IpdPlayer
The player the we want to inspect.
h1: Action
The next action for first player.
Expand All @@ -99,9 +99,9 @@ def simulate_match(player_1, player_2, strategy, rounds=10):

Parameters
----------
player_1: Player
player_1: IpdPlayer
The player that will have a constant strategy.
player_2: Player
player_2: IpdPlayer
The player we want to simulate.
strategy: Action
The constant strategy to use for first player.
Expand All @@ -117,12 +117,12 @@ def _calculate_scores(p1, p2, game):

Parameters
----------
p1: Player
p1: IpdPlayer
The first player.
p2: Player
p2: IpdPlayer
The second player.
game: Game
Game object used to score rounds in the players' histories.
game: IpdGame
IpdGame object used to score rounds in the players' histories.

Returns
-------
Expand All @@ -142,12 +142,12 @@ def look_ahead(player_1, player_2, game, rounds=10):

Parameters
----------
player_1: Player
player_1: IpdPlayer
The player that will look ahead.
player_2: Player
player_2: IpdPlayer
The opponent that will be inspected.
game: Game
The Game object used to score rounds.
game: IpdGame
The IpdGame object used to score rounds.
rounds: int
The number of rounds to look ahead.

Expand Down
File renamed without changes.
30 changes: 15 additions & 15 deletions axelrod/classifier.py → axelrod/ipd/classifier.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,18 +14,18 @@
import warnings
import yaml

from axelrod.player import Player
from axelrod.ipd.player import IpdPlayer

ALL_CLASSIFIERS_PATH = "data/all_classifiers.yml"

T = TypeVar("T")


class Classifier(Generic[T]):
"""Describes a Player (strategy).
"""Describes a IpdPlayer (strategy).

User sets a name and function, f, at initialization. Through
classify_player, looks for the classifier to be set in the passed Player
classify_player, looks for the classifier to be set in the passed IpdPlayer
class. If not set, then passes to f for calculation.

f must operate on the class, and not an instance. If necessary, f may
Expand All @@ -38,18 +38,18 @@ class Classifier(Generic[T]):
Attributes
----------
name: An identifier for the classifier, used as a dict key in storage and in
'classifier' dicts of Player classes.
player_class_classifier: A function that takes in a Player class (not an
'classifier' dicts of IpdPlayer classes.
player_class_classifier: A function that takes in a IpdPlayer class (not an
instance) and returns a value.
"""

def __init__(
self, name: Text, player_class_classifier: Callable[[Type[Player]], T]
self, name: Text, player_class_classifier: Callable[[Type[IpdPlayer]], T]
):
self.name = name
self.player_class_classifier = player_class_classifier

def classify_player(self, player: Type[Player]) -> T:
def classify_player(self, player: Type[IpdPlayer]) -> T:
"""Look for this classifier in the passed player's 'classifier' dict,
otherwise pass to the player to f."""
try:
Expand Down Expand Up @@ -80,7 +80,7 @@ def classify_player(self, player: Type[Player]) -> T:

def rebuild_classifier_table(
classifiers: List[Classifier],
players: List[Type[Player]],
players: List[Type[IpdPlayer]],
path: Text = ALL_CLASSIFIERS_PATH,
) -> None:
"""Builds the classifier table in data.
Expand Down Expand Up @@ -142,7 +142,7 @@ def known_classifier(cls, classifier_name: Text) -> bool:
@classmethod
def __getitem__(
cls, key: Union[Classifier, Text]
) -> Callable[[Union[Player, Type[Player]]], Any]:
) -> Callable[[Union[IpdPlayer, Type[IpdPlayer]]], Any]:
"""Looks up the classifier for the player.

Given a passed classifier key, return a function that:
Expand All @@ -152,7 +152,7 @@ def __getitem__(
player in the all_player_dicts. Returns None if the classifier is not
found in either of those.

The returned function expects Player instances, but if a Player class is
The returned function expects IpdPlayer instances, but if a IpdPlayer class is
passed, then it will create an instance by calling an argument-less
initializer. If no such initializer exists on the class, then an error
will result.
Expand All @@ -164,7 +164,7 @@ def __getitem__(

Returns
-------
A function that will map Player (or Player instances) to their value for
A function that will map IpdPlayer (or IpdPlayer instances) to their value for
this classification.
"""
# Key may be the name or an instance. Convert to name.
Expand All @@ -175,7 +175,7 @@ def __getitem__(
raise KeyError("Unknown classifier")

def classify_player_for_this_classifier(
player: Union[Player, Type[Player]]
player: Union[IpdPlayer, Type[IpdPlayer]]
) -> Any:
def try_lookup() -> Any:
try:
Expand All @@ -187,7 +187,7 @@ def try_lookup() -> Any:

# If the passed player is not an instance, then try to initialize an
# instance without arguments.
if not isinstance(player, Player):
if not isinstance(player, IpdPlayer):
try:
player = player()
warnings.warn(
Expand All @@ -214,7 +214,7 @@ def try_lookup() -> Any:
return classify_player_for_this_classifier

@classmethod
def is_basic(cls, s: Union[Player, Type[Player]]):
def is_basic(cls, s: Union[IpdPlayer, Type[IpdPlayer]]):
"""
Defines criteria for a strategy to be considered 'basic'
"""
Expand All @@ -232,7 +232,7 @@ def is_basic(cls, s: Union[Player, Type[Player]]):
)

@classmethod
def obey_axelrod(cls, s: Union[Player, Type[Player]]):
def obey_axelrod(cls, s: Union[IpdPlayer, Type[IpdPlayer]]):
"""
A function to check if a strategy obeys Axelrod's original tournament
rules.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from axelrod.action import Action
from axelrod.ipd.action import Action
from collections import defaultdict, namedtuple
from typing import DefaultDict, Iterator, Dict, Tuple, Set, List

Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@

from axelrod import Classifiers
from .action import Action
from .player import Player
from .player import IpdPlayer

CachePlayerKey = Tuple[Player, Player]
CachePlayerKey = Tuple[IpdPlayer, IpdPlayer]
CacheKey = Tuple[str, str]


Expand All @@ -38,7 +38,7 @@ def _key_transform(key: CachePlayerKey) -> CacheKey:
def _is_valid_key(key: CachePlayerKey) -> bool:
"""Validate a deterministic cache player key.

The key should always be a 2-tuple, with a pair of axelrod.Player
The key should always be a 2-tuple, with a pair of axelrodPlayer
instances and one integer. Both players should be deterministic.

Parameters
Expand All @@ -52,7 +52,7 @@ def _is_valid_key(key: CachePlayerKey) -> bool:
if not isinstance(key, tuple) or len(key) != 2:
return False

if not (isinstance(key[0], Player) and isinstance(key[1], Player)):
if not (isinstance(key[0], IpdPlayer) and isinstance(key[1], IpdPlayer)):
return False

if Classifiers["stochastic"](key[0]) or Classifiers["stochastic"](key[1]):
Expand Down Expand Up @@ -89,8 +89,8 @@ class DeterministicCache(UserDict):
By also storing those cached results in a file, we can re-use the cache
between multiple tournaments if necessary.

The cache is a dictionary mapping pairs of Player classes to a list of
resulting interactions. e.g. for a 3 turn Match between Cooperator and
The cache is a dictionary mapping pairs of IpdPlayer classes to a list of
resulting interactions. e.g. for a 3 turn IpdMatch between Cooperator and
Alternator, the dictionary entry would be:

(axelrod.Cooperator, axelrod.Alternator): [(C, C), (C, D), (C, C)]
Expand Down Expand Up @@ -132,7 +132,7 @@ def __setitem__(self, key: CachePlayerKey, value):

if not _is_valid_key(key):
raise ValueError(
"Key must be a tuple of 2 deterministic axelrod Player classes"
"Key must be a tuple of 2 deterministic axelrod IpdPlayer classes"
)

if not _is_valid_value(value):
Expand Down
Loading