Repository: Axelrod-Python/Axelrod

Issue:
Finite state machine players don't reset properly
```
>>> import axelrod as axl
>>> tft = axl.TitForTat()
>>> predator = axl.Predator()
>>> predator.fsm.state
1
>>> m = axl.Match((tft, predator), 2)
>>> m.play()
[('C', 'C'), ('C', 'D')]
>>> predator.fsm.state
 2
>>> predator.reset()
>>> predator.fsm.state
2
```

Stumbled on this working on #636 (writing a hypothesis strategy that contrite TfT reduces to TfT in 0 noise) so the above is reduced from seeing that when playing the same match again we get a different output:

```
>>> m = axl.Match((tft, predator), 2)
>>> m.play()
[('C', 'C'), ('C', 'C')]
```

Am going to work on a fix now and include a hypothesis test that checks that random deterministic matches give the same outcomes.

Discussion:

Patch:
diff --git a/axelrod/strategies/finite_state_machines.py b/axelrod/strategies/finite_state_machines.py
index defc4770..1c231d43 100644
--- a/axelrod/strategies/finite_state_machines.py
+++ b/axelrod/strategies/finite_state_machines.py
@@ -54,6 +54,7 @@ class FSMPlayer(Player):
             initial_state = 1
             initial_action = C
         Player.__init__(self)
+        self.initial_state = initial_state
         self.initial_action = initial_action
         self.fsm = SimpleFSM(transitions, initial_state)
 
@@ -67,6 +68,10 @@ class FSMPlayer(Player):
             self.state = self.fsm.state
             return action
 
+    def reset(self):
+        Player.reset(self)
+        self.fsm.state = self.initial_state
+
 
 class Fortress3(FSMPlayer):
     """Finite state machine player specified in DOI:10.1109/CEC.2006.1688322.


Test patch:
diff --git a/axelrod/tests/integration/test_matches.py b/axelrod/tests/integration/test_matches.py
new file mode 100644
index 00000000..b6241145
--- /dev/null
+++ b/axelrod/tests/integration/test_matches.py
@@ -0,0 +1,25 @@
+"""Tests for some expected match behaviours"""
+import unittest
+import axelrod
+
+from hypothesis import given
+from hypothesis.strategies import integers
+from axelrod.tests.property import strategy_lists
+
+C, D = axelrod.Actions.C, axelrod.Actions.D
+
+deterministic_strategies = [s for s in axelrod.ordinary_strategies
+                            if not s().classifier['stochastic']]  # Well behaved strategies
+
+class TestMatchOutcomes(unittest.TestCase):
+
+    @given(strategies=strategy_lists(strategies=deterministic_strategies,
+                                     min_size=2, max_size=2),
+           turns=integers(min_value=1, max_value=20))
+    def test_outcome_repeats(self, strategies, turns):
+        """A test that if we repeat 3 matches with deterministic and well
+        behaved strategies then we get the same result"""
+        players = [s() for s in strategies]
+        matches = [axelrod.Match(players, turns) for _ in range(3)]
+        self.assertEqual(matches[0].play(), matches[1].play())
+        self.assertEqual(matches[1].play(), matches[2].play())
diff --git a/axelrod/tests/unit/test_finite_state_machines.py b/axelrod/tests/unit/test_finite_state_machines.py
index 043834a1..d8147a59 100644
--- a/axelrod/tests/unit/test_finite_state_machines.py
+++ b/axelrod/tests/unit/test_finite_state_machines.py
@@ -111,6 +111,12 @@ class TestFSMPlayer(TestPlayer):
         fsm = player.fsm
         self.assertTrue(check_state_transitions(fsm.state_transitions))
 
+    def test_reset_initial_state(self):
+        player = self.player()
+        player.fsm.state = -1
+        player.reset()
+        self.assertFalse(player.fsm.state == -1)
+
 
 class TestFortress3(TestFSMPlayer):