Skip to content

Commit 56bd294

Browse files
authored
Merge branch 'master' into typeHint7
2 parents 56a79d6 + ce40b93 commit 56bd294

5 files changed

Lines changed: 40 additions & 36 deletions

File tree

axelrod/moran.py

Lines changed: 17 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
from collections import Counter
22
import random
3-
from typing import Sequence, List, Tuple
43

54
import numpy as np
65

@@ -9,7 +8,7 @@
98
from .random_ import randrange
109

1110

12-
def fitness_proportionate_selection(scores: Sequence[int]) -> int :
11+
def fitness_proportionate_selection(scores):
1312
"""Randomly selects an individual proportionally to score.
1413
1514
Parameters
@@ -31,8 +30,8 @@ def fitness_proportionate_selection(scores: Sequence[int]) -> int :
3130

3231

3332
class MoranProcess(object):
34-
def __init__(self, players, turns: int=100, noise: float=0, deterministic_cache=None,
35-
mutation_rate: float=0., mode: str='bd', match_class=Match):
33+
def __init__(self, players, turns=100, noise=0, deterministic_cache=None,
34+
mutation_rate=0., mode='bd', match_class=Match):
3635
"""
3736
An agent based Moran process class. In each round, each player plays a
3837
Match with each other player. Players are assigned a fitness score by
@@ -108,7 +107,7 @@ def set_players(self):
108107
self.players.append(player)
109108
self.populations = [self.population_distribution()]
110109

111-
def mutate(self, index: int) -> List[str] :
110+
def mutate(self, index):
112111
"""Mutate the player at index."""
113112
# Choose another strategy at random from the initial population
114113
r = random.random()
@@ -122,7 +121,7 @@ def mutate(self, index: int) -> List[str] :
122121
new_player = self.players[index].clone()
123122
return new_player
124123

125-
def death(self, index: int=None) -> int:
124+
def death(self, index=None):
126125
"""Selects the player to be removed. Note that the in the birth-death
127126
case, the player that is reproducing may also be replaced. However in
128127
the death-birth case, this player will be excluded from the choices.
@@ -132,7 +131,7 @@ def death(self, index: int=None) -> int:
132131
i = randrange(0, len(self.players))
133132
return i
134133

135-
def birth(self, index: int=None) -> int:
134+
def birth(self, index=None):
136135
"""The birth event."""
137136
# Compute necessary fitnesses.
138137
scores = self.score_all()
@@ -148,7 +147,7 @@ def birth(self, index: int=None) -> int:
148147
j = fitness_proportionate_selection(scores)
149148
return j
150149

151-
def fixation_check(self) -> bool:
150+
def fixation_check(self):
152151
"""Is the population of a single type?"""
153152
if self.mutation_rate > 0:
154153
return False
@@ -191,7 +190,7 @@ def __next__(self):
191190
self.fixation_check()
192191
return self
193192

194-
def _matchup_indices(self) -> Tuple[str]:
193+
def _matchup_indices(self):
195194
"""Generate the matchup pairs."""
196195
indices = []
197196
N = len(self.players)
@@ -204,7 +203,7 @@ def _matchup_indices(self) -> Tuple[str]:
204203
indices.append((i, j))
205204
return indices
206205

207-
def score_all(self) -> Tuple[str]:
206+
def score_all(self):
208207
"""Plays the next round of the process. Every player is paired up
209208
against every other player and the total scores are recorded."""
210209
N = len(self.players)
@@ -222,7 +221,7 @@ def score_all(self) -> Tuple[str]:
222221
self.score_history.append(scores)
223222
return scores
224223

225-
def population_distribution(self) -> int:
224+
def population_distribution(self):
226225
"""Returns the population distribution of the last iteration."""
227226
player_names = [str(player) for player in self.players]
228227
counter = Counter(player_names)
@@ -249,14 +248,14 @@ def play(self):
249248
break
250249
return self.populations
251250

252-
def __len__(self) -> int:
251+
def __len__(self):
253252
return len(self.populations)
254253

255254

256255
class MoranProcessGraph(MoranProcess):
257256
def __init__(self, players, interaction_graph, reproduction_graph=None,
258-
turns: int=100, noise: float =0, deterministic_cache=None,
259-
mutation_rate: float=0., mode: str='bd', match_class=Match):
257+
turns=100, noise=0, deterministic_cache=None,
258+
mutation_rate=0., mode='bd', match_class=Match):
260259
"""
261260
An agent based Moran process class. In each round, each player plays a
262261
Match with each neighboring player according to the interaction graph.
@@ -321,7 +320,7 @@ def __init__(self, players, interaction_graph, reproduction_graph=None,
321320
self.index = dict(zip(interaction_graph.vertices(),
322321
range(len(players))))
323322

324-
def birth(self, index: int=None) -> int:
323+
def birth(self, index=None):
325324
"""Compute the birth index."""
326325
scores = self.score_all()
327326
if index:
@@ -335,7 +334,7 @@ def birth(self, index: int=None) -> int:
335334
j = fitness_proportionate_selection(scores)
336335
return j
337336

338-
def death(self, index: int=None) -> int:
337+
def death(self, index=None):
339338
"""Selects the player to be removed."""
340339
if self.mode == "db":
341340
# Select a player to be replaced globally
@@ -350,7 +349,7 @@ def death(self, index: int=None) -> int:
350349
i = self.index[vertex]
351350
return i
352351

353-
def _matchup_indices(self) -> Tuple[str]:
352+
def _matchup_indices(self):
354353
"""Generate the matchup pairs"""
355354
indices = set()
356355
# For death-birth we only want the neighbors of the dead node
@@ -373,7 +372,7 @@ def _matchup_indices(self) -> Tuple[str]:
373372
indices.add((i, j))
374373
return indices
375374

376-
def population_distribution(self) -> int:
375+
def population_distribution(self):
377376
"""Returns the population distribution of the last iteration."""
378377
player_names = [str(player) for player in self.players]
379378
counter = Counter(player_names)

axelrod/strategies/geller.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import inspect
22

3-
from axelrod.actions import Actions
3+
from axelrod.actions import Actions, Action
44
from axelrod.player import Player
55
from axelrod.random_ import random_choice
66

@@ -42,7 +42,7 @@ class Geller(Player):
4242
'manipulates_state': False
4343
}
4444

45-
def strategy(self, opponent):
45+
def strategy(self, opponent: Player) -> Action:
4646
"""
4747
Look at what the opponent will play in the next round and choose a strategy
4848
that gives the least jail time, which is is equivalent to playing the same

axelrod/strategies/hunter.py

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
1-
from axelrod.actions import Actions
1+
from axelrod.actions import Actions, Action
22
from axelrod.player import Player
33
from axelrod._strategy_utils import detect_cycle
44

5+
from typing import List, Tuple
6+
57
C, D = Actions.C, Actions.D
68

79

@@ -19,7 +21,7 @@ class DefectorHunter(Player):
1921
'manipulates_state': False
2022
}
2123

22-
def strategy(self, opponent):
24+
def strategy(self, opponent: Player) -> Action:
2325
if len(self.history) >= 4 and len(opponent.history) == opponent.defections:
2426
return D
2527
return C
@@ -39,13 +41,13 @@ class CooperatorHunter(Player):
3941
'manipulates_state': False
4042
}
4143

42-
def strategy(self, opponent):
44+
def strategy(self, opponent: Player) -> Action:
4345
if len(self.history) >= 4 and len(opponent.history) == opponent.cooperations:
4446
return D
4547
return C
4648

4749

48-
def is_alternator(history):
50+
def is_alternator(history: List[Action]) -> bool:
4951
for i in range(len(history) - 1):
5052
if history[i] == history[i + 1]:
5153
return False
@@ -66,11 +68,11 @@ class AlternatorHunter(Player):
6668
'manipulates_state': False
6769
}
6870

69-
def __init__(self):
71+
def __init__(self) -> None:
7072
super().__init__()
7173
self.is_alt = False
7274

73-
def strategy(self, opponent):
75+
def strategy(self, opponent: Player) -> Action:
7476
if len(opponent.history) < 6:
7577
return C
7678
if len(self.history) == 6:
@@ -100,11 +102,11 @@ class CycleHunter(Player):
100102
'manipulates_state': False
101103
}
102104

103-
def __init__(self):
105+
def __init__(self) -> None:
104106
super().__init__()
105-
self.cycle = None
107+
self.cycle = None # type: Tuple[Action]
106108

107-
def strategy(self, opponent):
109+
def strategy(self, opponent: Player) -> Action:
108110
if self.cycle:
109111
return D
110112
cycle = detect_cycle(opponent.history, min_size=3)
@@ -124,7 +126,7 @@ class EventualCycleHunter(CycleHunter):
124126

125127
name = 'Eventual Cycle Hunter'
126128

127-
def strategy(self, opponent):
129+
def strategy(self, opponent: Player) -> None:
128130
if len(opponent.history) < 10:
129131
return C
130132
if len(opponent.history) == opponent.cooperations:
@@ -153,7 +155,7 @@ class MathConstantHunter(Player):
153155
'manipulates_state': False
154156
}
155157

156-
def strategy(self, opponent):
158+
def strategy(self, opponent: Player) -> Action:
157159
"""
158160
Check whether the number of cooperations in the first and second halves
159161
of the history are close. The variance of the uniform distribution (1/4)
@@ -191,12 +193,12 @@ class RandomHunter(Player):
191193
'manipulates_state': False
192194
}
193195

194-
def __init__(self):
196+
def __init__(self) -> None:
195197
self.countCC = 0
196198
self.countDD = 0
197199
super().__init__()
198200

199-
def strategy(self, opponent):
201+
def strategy(self, opponent: Player) -> Action:
200202
"""
201203
A random player is unpredictable, which means the conditional frequency
202204
of cooperation after cooperation, and defection after defections, should

axelrod/strategies/memorytwo.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from axelrod.actions import Actions
1+
from axelrod.actions import Actions, Action
22
from axelrod.player import Player
33
from .titfortat import TitForTat, TitFor2Tats
44
from .defector import Defector
@@ -30,7 +30,7 @@ class MEM2(Player):
3030
'manipulates_state': False
3131
}
3232

33-
def __init__(self):
33+
def __init__(self) -> None:
3434
super().__init__()
3535
self.players = {
3636
"TFT" : TitForTat(),
@@ -41,7 +41,7 @@ def __init__(self):
4141
self.shift_counter = 3
4242
self.alld_counter = 0
4343

44-
def strategy(self, opponent):
44+
def strategy(self, opponent: Player) -> Action:
4545
# Update Histories
4646
# Note that this assumes that TFT and TFTT do not use internal counters,
4747
# Rather that they examine the actual history of play

type_tests.sh

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,3 +31,6 @@ mypy --ignore-missing-imports --follow-imports skip axelrod/strategies/mindcontr
3131
mypy --ignore-missing-imports --follow-imports skip axelrod/strategies/mindreader.py
3232
mypy --ignore-missing-imports --follow-imports skip axelrod/strategies/mutual.py
3333
mypy --ignore-missing-imports --follow-imports skip axelrod/strategies/negation.py
34+
mypy --ignore-missing-imports --follow-imports skip axelrod/strategies/hunter.py
35+
mypy --ignore-missing-imports --follow-imports skip axelrod/strategies/geller.py
36+
mypy --ignore-missing-imports --follow-imports skip axelrod/strategies/memorytwo.py

0 commit comments

Comments
 (0)