-
Notifications
You must be signed in to change notification settings - Fork 268
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
issue#844 backstabber.py #924
issue#844 backstabber.py #924
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for this @eric-s-s it looks good.
- Requests for docstrings (even if just a line)
- I'd like you to tweak the tests a bit. Moving the sub calls to their own
test_...
method so that they get recognised as individual tests byunittest
. This just helps in the case of test failures.
Could you point out and expand on the off by 1 error that you've fixed? Just to make it clear please.
axelrod/strategies/backstabber.py
Outdated
return _backstabber_strategy(opponent) | ||
|
||
|
||
def _backstabber_strategy(opponent): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you add a docstring here please.
axelrod/strategies/backstabber.py
Outdated
return C | ||
|
||
|
||
def _alt_strategy(opponent): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Docstring please.
axelrod/strategies/backstabber.py
Outdated
return C | ||
|
||
|
||
def _opponent_triggers_alt_strategy(opponent): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Docstring please.
axelrod/strategies/backstabber.py
Outdated
return before_alt_strategy < rounds_opponent_played < after_alt_strategy | ||
|
||
|
||
def _opponent_defected_in_first_n_rounds(opponent, first_n_rounds): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Docstring please.
|
||
# Defects on rounds 199, and 200 no matter what | ||
self.responses_test([C, D, D], [C] * 197, [C] * 197, length=200) | ||
self._when_alt_strategy_is_triggered() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you put these as their own test methods.
So remove them from here and rename them to start with the word test
:
_when_alt_stragegy_is_triggered -> test_when_alt_strategy_is_triggered
...
This would make the test failures easier to read (by having them as specific tests instances so to speak).
@@ -24,58 +24,100 @@ def test_strategy(self): | |||
Forgives the first 3 defections but on the fourth | |||
will defect forever. Defects after the 198th round unconditionally. | |||
""" | |||
self._defects_after_four_defections() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove these and change the name of the methods to be test_defects_after_four_defections
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is ok that there will be no "test_strategy" method? it will get replaced by the more specifically named ones.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yup that's fine, you'll still run test_strategy
from the super TestBackStabber
class so it's kind of like what you had before :)
alternator_actions = [(C, C), (C, D)] * 4 + [(D, C), (D, D)] * 2 | ||
self.versus_test(axelrod.Alternator(), expected_actions=alternator_actions, match_attributes={"length": 200}) | ||
|
||
def _defects_on_last_two_rounds_by_match_len(self): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
change to test_defects...
self._alt_strategy_stops_at_round_180() | ||
super(TestDoubleCrosser, self).test_strategy() | ||
|
||
def _when_alt_strategy_is_triggered(self): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
test_when_...
self.versus_test(axelrod.MockPlayer(opponent_actions), expected_actions=expected_actions, | ||
match_attributes={"length": 200}) | ||
|
||
def _starting_defect_keeps_alt_strategy_from_triggering(self): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
test_starting_...
expected_actions=defects_on_last_actions + expected_actions_suffix, | ||
match_attributes={"length": 200}) | ||
|
||
def _alt_strategy_stops_at_round_180(self): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
test_alt_
return C | ||
if len(opponent.history) < 180: | ||
if len(opponent.history) > cutoff: | ||
if D not in opponent.history[:cutoff + 1]: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
here's the off-by-one. It should only check for defection in the first 6, but opponent.history[:cutoff +1] is the first 7.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, looks like you are right to me. Would be good to have @uglyfruitcake's thoughts on this PR too :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes the code doesn't match the documentation, however, It's the documentation that's wrong. I spent ages optimises the numbers in Doublecrosser to get it to perform optimally and its current state will be it's optimal performance. When I wrote the description I will have put the wrong number of turns and so it should say "the first 7 rounds". It is a mistake but its wrong in the documentation not the code. Sorry!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
rewriting that now. in a moment, comments and tests should follow the specs.
@drvinceknight thank you for all the comments. i'll get on it ASAP. |
axelrod/strategies/backstabber.py
Outdated
""" | ||
before_alt_strategy = 6 | ||
after_alt_strategy = 180 | ||
if _opponent_defected_in_first_n_rounds(opponent, before_alt_strategy): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you explicitly write first_n_rounds=before_alt_strategy
(for clarity).
return C | ||
|
||
|
||
def _opponent_triggers_alt_strategy(opponent: Player) -> bool: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@uglyfruitcake is this correct?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes that looks good to me.
return C | ||
|
||
|
||
def _alt_strategy(opponent: Player) -> Action: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you write specific tests for these module functions please.
The don't need to be extensive but just enough so that they'd fail if something got refactored in the strategy methods removing the need for them.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
actually. this brings up a problem i had, to which module methods was the most expedient solution.
as i see it, these should all be private methods of their classes and DoubleCrosser should inherit from BackStabber. The tests, as they are, should fully cover all those methods (i don't have a coverage tool, but i think i got it).
I originally wrote class DoubleCrosser(BackStabber):
, but strange things would happen with @FinalTransformer((D, D), name_prefix=None)
If only BackStabber had that decorator, DoubleCrosser would not inherit that behavior. If both had that decorator I got a maximum recursion depth error.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
that aside, will write tests for module as is.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
errrr. i hope complete tests is ok. trying to write non-complete tests is, for me, like not completing a
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Haha, this is way more than I was expecting but it looks good to me :)
I've labelled this as ready to go but we have a 2 core reviewer process, so either @marcharper or @meatballs will be along when they have a moment and might make further requests (or indeed disagree with my requests :)) 👍 |
axelrod/strategies/backstabber.py
Outdated
""" | ||
If opponent's last two plays were defect, then defects on next round. Otherwise, cooperates. | ||
""" | ||
final_two_plays = opponent.history[-2:] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could we rename this variable? Given that a major feature of these strategies is to defect unconditionally for the final two rounds of the match, it's confusing to call this variable final_two_plays
How about previous_two_plays
instead?
added tests.
also refactored backstabber and fixed an off-by-one error.
#884