Skip to content
Closed
Show file tree
Hide file tree
Changes from 4 commits
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
4 changes: 4 additions & 0 deletions .github/workflows/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ jobs:
python -m pip install coverage
python -m pip install hypothesis==3.2
python -m pip install mypy
python -m pip install black
- name: Run tests
run: |
coverage run --source=axelrod -m unittest discover
Expand All @@ -54,6 +55,9 @@ jobs:
- name: Check that all strategies are indexed
run: |
python run_strategy_indexer.py
- name: Check format
run: |
python -m black -l 80 . --check
- name: Check that installs
run: |
python setup.py install
Expand Down
4 changes: 3 additions & 1 deletion .prepare-commit-msg.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,9 @@

if branch.startswith(issue_prefix):
issue_number = re.match("%s(.*)" % issue_prefix, branch).group(1)
print("prepare-commit-msg: Prepending [#%s] to commit message" % issue_number)
print(
"prepare-commit-msg: Prepending [#%s] to commit message" % issue_number
)

with open(commit_msg_filepath, "r+") as f:
content = f.read()
Expand Down
12 changes: 9 additions & 3 deletions axelrod/classifier.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,12 +59,18 @@ def classify_player(self, player: Type[Player]) -> T:


stochastic = Classifier[bool]("stochastic", lambda _: False)
memory_depth = Classifier[Union[float, int]]("memory_depth", lambda _: float("inf"))
memory_depth = Classifier[Union[float, int]](
"memory_depth", lambda _: float("inf")
)
makes_use_of = Classifier[Optional[Set[Text]]]("makes_use_of", lambda _: None)
long_run_time = Classifier[bool]("long_run_time", lambda _: False)
inspects_source = Classifier[Optional[bool]]("inspects_source", lambda _: None)
manipulates_source = Classifier[Optional[bool]]("manipulates_source", lambda _: None)
manipulates_state = Classifier[Optional[bool]]("manipulates_state", lambda _: None)
manipulates_source = Classifier[Optional[bool]](
"manipulates_source", lambda _: None
)
manipulates_state = Classifier[Optional[bool]](
"manipulates_state", lambda _: None
)

# Should list all known classifiers.
all_classifiers = [
Expand Down
6 changes: 4 additions & 2 deletions axelrod/compute_finite_state_machine_memory.py
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,10 @@ def get_accessible_transitions(
if trans.state in accessible_states:
accessible_transitions[
(trans.state, trans.last_opponent_action)
] = (trans.next_state, trans.next_action)
] = (
trans.next_state,
trans.next_action,
)

return accessible_transitions

Expand Down Expand Up @@ -263,4 +266,3 @@ def get_memory_from_transitions(
if len(next_action_set) == 1:
return 0
return 1

3 changes: 2 additions & 1 deletion axelrod/evolvable_player.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

class InsufficientParametersError(Exception):
"""Error indicating that insufficient parameters were specified to initialize an Evolvable Player."""

def __init__(self, *args):
super().__init__(*args)

Expand Down Expand Up @@ -38,7 +39,7 @@ def create_new(self, **kwargs):
def serialize_parameters(self):
"""Serialize parameters."""
pickled = dumps(self.init_kwargs) # bytes
s = base64.b64encode(pickled).decode('utf8') # string
s = base64.b64encode(pickled).decode("utf8") # string
return s

@classmethod
Expand Down
21 changes: 16 additions & 5 deletions axelrod/fingerprint.py
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,10 @@ def _generate_data(interactions: dict, points: list, edges: list) -> dict:
"""
edge_scores = [
np.mean(
[compute_final_score_per_turn(scores)[0] for scores in interactions[edge]]
[
compute_final_score_per_turn(scores)[0]
for scores in interactions[edge]
]
)
for edge in edges
]
Expand Down Expand Up @@ -216,7 +219,9 @@ def _reshape_data(data: dict, points: list, size: int) -> np.ndarray:

class AshlockFingerprint(object):
def __init__(
self, strategy: Union[type, Player], probe: Union[type, Player] = axl.TitForTat
self,
strategy: Union[type, Player],
probe: Union[type, Player] = axl.TitForTat,
) -> None:
"""
Parameters
Expand Down Expand Up @@ -512,7 +517,9 @@ def analyse_cooperation_ratio(filename):
opponent in each turn. The ith row corresponds to the ith opponent
and the jth column the jth turn.
"""
did_c = np.vectorize(lambda actions: [int(action == "C") for action in actions])
did_c = np.vectorize(
lambda actions: [int(action == "C") for action in actions]
)

cooperation_rates = {}
df = dd.read_csv(filename)
Expand All @@ -521,7 +528,10 @@ def analyse_cooperation_ratio(filename):
df = df[df["Player index"] == 0][["Opponent index", "Actions"]]

for _, row in df.iterrows():
opponent_index, player_history = row["Opponent index"], row["Actions"]
opponent_index, player_history = (
row["Opponent index"],
row["Actions"],
)
if opponent_index in cooperation_rates:
cooperation_rates[opponent_index].append(did_c(player_history))
else:
Expand Down Expand Up @@ -586,7 +596,8 @@ def plot(

if display_names:
plt.yticks(
range(len(self.opponents)), [str(player) for player in self.opponents]
range(len(self.opponents)),
[str(player) for player in self.opponents],
)
else:
plt.yticks([0, len(self.opponents) - 1], [0, 1])
Expand Down
11 changes: 9 additions & 2 deletions axelrod/game.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@ class Game(object):
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:
def __init__(
self, r: Score = 3, s: Score = 0, t: Score = 5, p: Score = 1
) -> None:
"""Create a new game object.

Parameters
Expand All @@ -30,7 +32,12 @@ def __init__(self, r: Score = 3, s: Score = 0, t: Score = 5, p: Score = 1) -> No
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)}
self.scores = {
(C, C): (r, r),
(D, D): (p, p),
(C, D): (s, t),
(D, C): (t, s),
}

def RPST(self) -> Tuple[Score, Score, Score, Score]:
"""Returns game matrix values in Press and Dyson notation."""
Expand Down
5 changes: 3 additions & 2 deletions axelrod/graph.py
Original file line number Diff line number Diff line change
Expand Up @@ -155,8 +155,9 @@ def attached_complete_graphs(length, loops=True, directed=False):
for cluster in range(2):
for i in range(length):
for j in range(i + 1, length):
edges.append(("{}:{}".format(cluster, i),
"{}:{}".format(cluster, j)))
edges.append(
("{}:{}".format(cluster, i), "{}:{}".format(cluster, j))
)
# Attach at one node
edges.append(("0:0", "1:0"))
graph = Graph(directed=directed, edges=edges)
Expand Down
4 changes: 3 additions & 1 deletion axelrod/history.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,9 @@ def __eq__(self, other):
if isinstance(other, list):
return self._plays == other
elif isinstance(other, History):
return self._plays == other._plays and self._coplays == other._coplays
return (
self._plays == other._plays and self._coplays == other._coplays
)
raise TypeError("Cannot compare types.")

def __getitem__(self, key):
Expand Down
3 changes: 2 additions & 1 deletion axelrod/interaction_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@ def compute_final_score(interactions, game=None):
return None

final_score = tuple(
sum([score[player_index] for score in scores]) for player_index in [0, 1]
sum([score[player_index] for score in scores])
for player_index in [0, 1]
)
return final_score

Expand Down
31 changes: 23 additions & 8 deletions axelrod/moran.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ def __init__(
reproduction_graph: Graph = None,
fitness_transformation: Callable = None,
mutation_method="transition",
stop_on_fixation=True
stop_on_fixation=True,
) -> None:
"""
An agent based Moran process class. In each round, each player plays a
Expand Down Expand Up @@ -132,7 +132,9 @@ def __init__(
if m in ["atomic", "transition"]:
self.mutation_method = m
else:
raise ValueError("Invalid mutation method {}".format(mutation_method))
raise ValueError(
"Invalid mutation method {}".format(mutation_method)
)
assert (mutation_rate >= 0) and (mutation_rate <= 1)
assert (noise >= 0) and (noise <= 1)
mode = mode.lower()
Expand All @@ -152,7 +154,9 @@ def __init__(
d[str(p)] = p
mutation_targets = dict()
for key in sorted(keys):
mutation_targets[key] = [v for (k, v) in sorted(d.items()) if k != key]
mutation_targets[key] = [
v for (k, v) in sorted(d.items()) if k != key
]
self.mutation_targets = mutation_targets

if interaction_graph is None:
Expand All @@ -171,7 +175,9 @@ def __init__(
self.fitness_transformation = fitness_transformation
# Map players to graph vertices
self.locations = sorted(interaction_graph.vertices)
self.index = dict(zip(sorted(interaction_graph.vertices), range(len(players))))
self.index = dict(
zip(sorted(interaction_graph.vertices), range(len(players)))
)
self.fixated = self.fixation_check()

def set_players(self) -> None:
Expand All @@ -193,7 +199,9 @@ def mutate(self, index: int) -> Player:

if self.mutation_method == "atomic":
if not issubclass(self.players[index].__class__, EvolvablePlayer):
raise TypeError("Player is not evolvable. Use a subclass of EvolvablePlayer.")
raise TypeError(
"Player is not evolvable. Use a subclass of EvolvablePlayer."
)
return self.players[index].mutate()

# Assuming mutation_method == "transition"
Expand Down Expand Up @@ -230,7 +238,9 @@ def death(self, index: int = None) -> int:
# Select locally
# index is not None in this case
vertex = random.choice(
sorted(self.reproduction_graph.out_vertices(self.locations[index]))
sorted(
self.reproduction_graph.out_vertices(self.locations[index])
)
)
i = self.index[vertex]
return i
Expand Down Expand Up @@ -476,7 +486,10 @@ class ApproximateMoranProcess(MoranProcess):
"""

def __init__(
self, players: List[Player], cached_outcomes: dict, mutation_rate: float = 0
self,
players: List[Player],
cached_outcomes: dict,
mutation_rate: float = 0,
) -> None:
"""
Parameters
Expand Down Expand Up @@ -511,7 +524,9 @@ def score_all(self) -> List:
scores = [0] * N
for i in range(N):
for j in range(i + 1, N):
player_names = tuple([str(self.players[i]), str(self.players[j])])
player_names = tuple(
[str(self.players[i]), str(self.players[j])]
)

cached_score = self._get_scores_from_cache(player_names)
scores[i] += cached_score[0]
Expand Down
20 changes: 15 additions & 5 deletions axelrod/player.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,9 @@ def __eq__(self, other):
if self.__repr__() != other.__repr__():
return False

for attribute in set(list(self.__dict__.keys()) + list(other.__dict__.keys())):
for attribute in set(
list(self.__dict__.keys()) + list(other.__dict__.keys())
):

value = getattr(self, attribute, None)
other_value = getattr(other, attribute, None)
Expand All @@ -86,14 +88,20 @@ def __eq__(self, other):
):
# Split the original generator so it is not touched
generator, original_value = itertools.tee(value)
other_generator, original_other_value = itertools.tee(other_value)
other_generator, original_other_value = itertools.tee(
other_value
)

if isinstance(value, types.GeneratorType):
setattr(self, attribute, (ele for ele in original_value))
setattr(other, attribute, (ele for ele in original_other_value))
setattr(
other, attribute, (ele for ele in original_other_value)
)
else:
setattr(self, attribute, itertools.cycle(original_value))
setattr(other, attribute, itertools.cycle(original_other_value))
setattr(
other, attribute, itertools.cycle(original_other_value)
)

for _ in range(200):
try:
Expand Down Expand Up @@ -128,7 +136,9 @@ def __repr__(self):
Appends the `__init__` parameters to the strategy's name."""
name = self.name
prefix = ": "
gen = (value for value in self.init_kwargs.values() if value is not None)
gen = (
value for value in self.init_kwargs.values() if value is not None
)
for value in gen:
try:
if issubclass(value, Player):
Expand Down
8 changes: 6 additions & 2 deletions axelrod/plot.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,9 @@ def _winplot_dataset(self):
# Sort wins by median
wins = self.result_set.wins
medians = map(median, wins)
medians = sorted([(m, i) for (i, m) in enumerate(medians)], reverse=True)
medians = sorted(
[(m, i) for (i, m) in enumerate(medians)], reverse=True
)
# Reorder and grab names
wins = [wins[x[-1]] for x in medians]
ranked_names = [str(self.players[x[-1]]) for x in medians]
Expand Down Expand Up @@ -324,7 +326,9 @@ def save_all_plots(
pbar = tqdm.tqdm(total=total, desc="Obtaining plots")

for method, name in plots:
f = getattr(self, method)(title="{} - {}".format(title_prefix, name))
f = getattr(self, method)(
title="{} - {}".format(title_prefix, name)
)
path = pathlib.Path("{}_{}.{}".format(prefix, method, filetype))
f.savefig(axl_filename(path))
plt.close(f)
Expand Down
Loading