Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
2 changes: 1 addition & 1 deletion axelrod/strategies/backstabber.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
C, D = Actions.C, Actions.D


@FinalTransformer([D, D]) # End with two defections
@FinalTransformer((D, D)) # End with two defections
class BackStabber(Player):
"""
Forgives the first 3 defections but on the fourth
Expand Down
40 changes: 20 additions & 20 deletions axelrod/strategies/mindreader.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,23 @@
import inspect

from axelrod import Actions, Player, RoundRobin, update_history
from .cycler import Cycler

C, D = Actions.C, Actions.D

def limited_simulate_play(player_1, player_2, h1):
"""Here we want to replay player_1's history to player_2, allowing
player_2's strategy method to set any internal variables as needed. If you
need a more complete simulation, see `simulate_play` in player.py. This
function is specifically designed for the needs of MindReader."""
h2 = player_2.strategy(player_1)
update_history(player_1, h1)
update_history(player_2, h2)

def simulate_match(player_1, player_2, strategy, rounds=10):
"""Simulates a number of matches."""
for match in range(rounds):
play_1, play_2 = strategy, player_2.strategy(player_1)
# Update histories and counts
update_history(player_1, play_1)
update_history(player_2, play_2)

def roll_back_history(player, rounds):
"""Undo the last `rounds` rounds as sufficiently as possible."""
for i in range(rounds):
play = player.history.pop(-1)
if play == C:
player.cooperations -= 1
elif play == D:
player.defections -= 1
limited_simulate_play(player_1, player_2, strategy)

def look_ahead(player_1, player_2, game, rounds=10):
"""Looks ahead for `rounds` and selects the next strategy appropriately."""
Expand All @@ -29,14 +27,16 @@ def look_ahead(player_1, player_2, game, rounds=10):
# Simulate plays for `rounds` rounds
strategies = [C, D]
for strategy in strategies:
opponent_ = copy.deepcopy(player_2) # need deepcopy here
round_robin = RoundRobin(players=[player_1, opponent_], game=game,
turns=rounds)
simulate_match(player_1, opponent_, strategy, rounds)
results.append(round_robin._calculate_scores(player_1, opponent_)[0])
# Instead of a deepcopy, create a new opponent and play out the history
opponent_ = player_2.clone()
player_ = Cycler(strategy) # Either cooperator or defector
for h1 in player_1.history:
limited_simulate_play(player_, opponent_, h1)

# Restore histories and counts
roll_back_history(player_1, rounds)
round_robin = RoundRobin(players=[player_, opponent_], game=game,
turns=rounds)
simulate_match(player_, opponent_, strategy, rounds)
results.append(round_robin._calculate_scores(player_, opponent_)[0])

return strategies[results.index(max(results))]

Expand Down
6 changes: 6 additions & 0 deletions axelrod/strategy_transformers.py
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,12 @@ def final_sequence(player, opponent, action, seq):
return action

index = length - len(player.history)
# If for some reason we've overrun the expected game length, just pass
# the intended action through
if len(player.history) >= length:
return action
# Check if we're near the end and need to start passing the actions
# from seq for the final few rounds.
if index <= len(seq):
return seq[-index]
return action
Expand Down
3 changes: 2 additions & 1 deletion axelrod/tests/unit/test_backstabber.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,8 @@ def test_strategy(self):
# Defects on rounds 199, and 200 no matter what
self.responses_test([C] * 197 , [C] * 197, [C, D, D],
tournament_length=200)
self.responses_test([C] * 198 , [C] * 198, [D, D, D],
# Test that exceeds tournament length
self.responses_test([C] * 198 , [C] * 198, [D, D, C],
tournament_length=200)
# But only if the tournament is known
self.responses_test([C] * 198 , [C] * 198, [C, C, C],
Expand Down
14 changes: 10 additions & 4 deletions axelrod/tests/unit/test_tournament.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,10 +106,7 @@ def test_serial_play(self):
{'cooperation': [], 'payoff': []})
self.assertFalse(tournament._run_parallel_repetitions.called)

#@given(s=lists(sampled_from(axelrod.strategies),
# Removing this as Hypothesis seems to have found a py2 bug.
# This is a temporary fix. For some reason mind reader seems to fail a test.
@given(s=lists(sampled_from([s for s in axelrod.strategies if s not in axelrod.cheating_strategies]),
@given(s=lists(sampled_from(axelrod.strategies),
min_size=2, # Errors are returned if less than 2 strategies
max_size=5, unique=True),
turns=integers(min_value=2, max_value=50),
Expand All @@ -118,9 +115,18 @@ def test_serial_play(self):
@settings(max_examples=50, timeout=0)
@example(s=test_strategies, turns=test_turns, repetitions=test_repetitions,
rm=random.seed(0))

# These two examples are to make sure #465 is fixed.
# As explained there: https://github.com/Axelrod-Python/Axelrod/issues/465,
# these two examples were identified by hypothesis.
@example(s=[axelrod.BackStabber, axelrod.MindReader], turns=2, repetitions=1,
rm=random.seed(0))
@example(s=[axelrod.ThueMorse, axelrod.MindReader], turns=2, repetitions=1,
rm=random.seed(0))
def test_property_serial_play(self, s, turns, repetitions, rm):
"""Test serial play using hypothesis"""
# Test that we get an instance of ResultSet

players = [strat() for strat in s]

tournament = axelrod.Tournament(
Expand Down