Skip to content

Commit e350cf4

Browse files
committed
Add strategies TF1, TF2, and TF3
1 parent 97f78e3 commit e350cf4

File tree

3 files changed

+204
-19
lines changed

3 files changed

+204
-19
lines changed

axelrod/strategies/_strategies.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
from .finite_state_machines import (
2323
Fortress3, Fortress4, Predator, Pun1, Raider, Ripoff, SolutionB1,
2424
SolutionB5, Thumper, FSMPlayer, EvolvedFSM4, EvolvedFSM16,
25-
EvolvedFSM16Noise05)
25+
EvolvedFSM16Noise05, TF1, TF2, TF3)
2626
from .forgiver import Forgiver, ForgivingTitForTat
2727
from .geller import Geller, GellerCooperator, GellerDefector
2828
from .gambler import (
@@ -238,6 +238,9 @@
238238
StochasticWSLS,
239239
SuspiciousTitForTat,
240240
Tester,
241+
TF1,
242+
TF2,
243+
TF3,
241244
ThueMorse,
242245
ThueMorseInverse,
243246
Thumper,

axelrod/strategies/finite_state_machines.py

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -571,3 +571,130 @@ def __init__(self) -> None:
571571
)
572572

573573
super().__init__(transitions=transitions, initial_state=0, initial_action=C)
574+
575+
576+
## Strategies trained with Moran process objectives
577+
578+
579+
class TF1(FSMPlayer):
580+
"""
581+
A FSM player trained to maximize Moran fixation probabilities.
582+
583+
Names:
584+
585+
- TF1: Original name by Marc Harper
586+
"""
587+
588+
name = "TF1"
589+
classifier = {
590+
'memory_depth': 16, # Estimate
591+
'stochastic': False,
592+
'makes_use_of': set(),
593+
'long_run_time': False,
594+
'inspects_source': False,
595+
'manipulates_source': False,
596+
'manipulates_state': False
597+
}
598+
599+
def __init__(self) -> None:
600+
transitions = (
601+
(0, C, 7, C), (0, D, 1, C),
602+
(1, C, 11, D), (1, D, 11, D),
603+
(2, C, 8, D), (2, D, 8, C),
604+
(3, C, 3, C), (3, D, 12, D),
605+
(4, C, 6, C), (4, D, 3, C),
606+
(5, C, 11, C), (5, D, 8, D),
607+
(6, C, 13, D), (6, D, 14, C),
608+
(7, C, 4, D), (7, D, 2, D),
609+
(8, C, 14, D), (8, D, 8, D),
610+
(9, C, 0, C), (9, D, 10, D),
611+
(10, C, 8, C), (10, D, 15, C),
612+
(11, C, 6, D), (11, D, 5, D),
613+
(12, C, 6, D), (12, D, 9, D),
614+
(13, C, 9, D), (13, D, 8, D),
615+
(14, C, 8, D), (14, D, 13, D),
616+
(15, C, 4, C), (15, D, 5, C)
617+
)
618+
619+
super().__init__(transitions=transitions, initial_state=0,
620+
initial_action=C)
621+
622+
623+
class TF2(FSMPlayer):
624+
"""
625+
A FSM player trained to maximize Moran fixation probabilities.
626+
627+
Names:
628+
629+
- TF2: Original name by Marc Harper
630+
"""
631+
632+
name = "TF2"
633+
classifier = {
634+
'memory_depth': 16, # Estimate
635+
'stochastic': False,
636+
'makes_use_of': set(),
637+
'long_run_time': False,
638+
'inspects_source': False,
639+
'manipulates_source': False,
640+
'manipulates_state': False
641+
}
642+
643+
def __init__(self) -> None:
644+
transitions = (
645+
(0, C, 13, D), (0, D, 12, D),
646+
(1, C, 3, D), (1, D, 4, D),
647+
(2, C, 14, D), (2, D, 9, D),
648+
(3, C, 0, C), (3, D, 1, D),
649+
(4, C, 1, D), (4, D, 2, D),
650+
# (5, C, 12, C), (5, D, 6, C),
651+
# (6, C, 1, C), (6, D, 14, D),
652+
(7, C, 12, D), (7, D, 2, D),
653+
(8, C, 7, D), (8, D, 9, D),
654+
(9, C, 8, D), (9, D, 0, D),
655+
(10, C, 2, C), (10, D, 15, C),
656+
(11, C, 7, D), (11, D, 13, D),
657+
(12, C, 3, C), (12, D, 8, D),
658+
(13, C, 7, C), (13, D, 10, D),
659+
(14, C, 10, D), (14, D, 7, D),
660+
(15, C, 15, C), (15, D, 11, D)
661+
)
662+
663+
super().__init__(transitions=transitions, initial_state=0,
664+
initial_action=C)
665+
666+
667+
class TF3(FSMPlayer):
668+
"""
669+
A FSM player trained to maximize Moran fixation probabilities.
670+
671+
Names:
672+
673+
- TF3: Original name by Marc Harper
674+
"""
675+
676+
name = "TF3"
677+
classifier = {
678+
'memory_depth': 8, # Estimate
679+
'stochastic': False,
680+
'makes_use_of': set(),
681+
'long_run_time': False,
682+
'inspects_source': False,
683+
'manipulates_source': False,
684+
'manipulates_state': False
685+
}
686+
687+
def __init__(self) -> None:
688+
transitions = (
689+
(0, C, 0, C), (0, D, 3, C),
690+
(1, C, 5, D), (1, D, 0, C),
691+
(2, C, 3, C), (2, D, 2, D),
692+
(3, C, 4, D), (3, D, 6, D),
693+
(4, C, 3, C), (4, D, 1, D),
694+
(5, C, 6, C), (5, D, 3, D),
695+
(6, C, 6, D), (6, D, 6, D),
696+
(7, C, 7, D), (7, D, 5, C)
697+
)
698+
699+
super().__init__(transitions=transitions, initial_state=0,
700+
initial_action=C)

axelrod/tests/strategies/test_finite_state_machines.py

Lines changed: 73 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -66,16 +66,18 @@ def test_bad_transitions_raise_error(self):
6666

6767
def test_bad_initial_state_raises_error(self):
6868
self.assertRaises(ValueError, SimpleFSM,
69-
transitions=self.two_state_transition, initial_state=5)
69+
transitions=self.two_state_transition,
70+
initial_state=5)
7071

7172
def test_state_setter_raises_error_for_bad_input(self):
7273
with self.assertRaises(ValueError) as cm:
7374
self.two_state.state = 5
7475
error_msg = cm.exception.args[0]
75-
self.assertEqual(error_msg, 'state: 5 does not have values for both C and D')
76+
self.assertEqual(error_msg,
77+
'state: 5 does not have values for both C and D')
7678

7779

78-
class TestFSMPlayer(TestPlayer):
80+
class TestSampleFSMPlayer(TestPlayer):
7981
"""Test a few sample tables to make sure that the finite state machines are
8082
working as intended."""
8183

@@ -98,7 +100,8 @@ def test_cooperator(self):
98100
cooperator_init_kwargs = {'transitions': ((1, C, 1, C), (1, D, 1, C)),
99101
'initial_state': 1,
100102
'initial_action': C}
101-
self.versus_test(axelrod.Alternator(), expected_actions=[(C, C), (C, D)] * 5,
103+
self.versus_test(axelrod.Alternator(),
104+
expected_actions=[(C, C), (C, D)] * 5,
102105
init_kwargs=cooperator_init_kwargs)
103106

104107
def test_defector(self):
@@ -107,7 +110,8 @@ def test_defector(self):
107110
defector_init_kwargs = {'transitions': ((1, C, 1, D), (1, D, 1, D)),
108111
'initial_state': 1,
109112
'initial_action': D}
110-
self.versus_test(axelrod.Alternator(), expected_actions=[(D, C), (D, D)] * 5,
113+
self.versus_test(axelrod.Alternator(),
114+
expected_actions=[(D, C), (D, D)] * 5,
111115
init_kwargs=defector_init_kwargs)
112116

113117
def test_tft(self):
@@ -132,7 +136,7 @@ def test_wsls(self):
132136
init_kwargs=wsls_init_kwargs)
133137

134138

135-
class TestFsmTransitions(TestPlayer):
139+
class TestFSMPlayer(TestPlayer):
136140
name = "FSM Player: ((1, 'C', 1, 'C'), (1, 'D', 1, 'D')), 1, C"
137141
player = axelrod.FSMPlayer
138142

@@ -219,7 +223,7 @@ def test_strategy(self):
219223
init_kwargs={"transitions": transitions})
220224

221225

222-
class TestFortress3(TestFsmTransitions):
226+
class TestFortress3(TestFSMPlayer):
223227

224228
name = "Fortress3"
225229
player = axelrod.Fortress3
@@ -259,7 +263,7 @@ def test_incorrect_transitions(self):
259263
self.transitions_test(state_and_actions)
260264

261265

262-
class TestFortress4(TestFsmTransitions):
266+
class TestFortress4(TestFSMPlayer):
263267

264268
name = "Fortress4"
265269
player = axelrod.Fortress4
@@ -299,7 +303,7 @@ def test_strategy(self):
299303
self.transitions_test(state_and_actions)
300304

301305

302-
class TestPredator(TestFsmTransitions):
306+
class TestPredator(TestFSMPlayer):
303307

304308
name = "Predator"
305309
player = axelrod.Predator
@@ -350,7 +354,7 @@ def test_strategy(self):
350354
self.transitions_test(state_and_actions)
351355

352356

353-
class TestPun1(TestFsmTransitions):
357+
class TestPun1(TestFSMPlayer):
354358

355359
name = "Pun1"
356360
player = axelrod.Pun1
@@ -380,7 +384,7 @@ def test_strategy(self):
380384
self.transitions_test(state_and_actions)
381385

382386

383-
class TestRaider(TestFsmTransitions):
387+
class TestRaider(TestFSMPlayer):
384388

385389
name = "Raider"
386390
player = axelrod.Raider
@@ -420,7 +424,7 @@ def test_strategy(self):
420424
self.transitions_test(state_and_actions)
421425

422426

423-
class TestRipoff(TestFsmTransitions):
427+
class TestRipoff(TestFSMPlayer):
424428

425429
name = "Ripoff"
426430
player = axelrod.Ripoff
@@ -455,7 +459,7 @@ def test_strategy(self):
455459
self.transitions_test(state_and_actions)
456460

457461

458-
class TestSolutionB1(TestFsmTransitions):
462+
class TestSolutionB1(TestFSMPlayer):
459463

460464
name = "SolutionB1"
461465
player = axelrod.SolutionB1
@@ -488,7 +492,7 @@ def test_strategy(self):
488492
self.transitions_test(state_and_actions)
489493

490494

491-
class TestSolutionB5(TestFsmTransitions):
495+
class TestSolutionB5(TestFSMPlayer):
492496

493497
name = "SolutionB5"
494498
player = axelrod.SolutionB5
@@ -533,7 +537,7 @@ def test_strategy(self):
533537
self.transitions_test(state_and_actions)
534538

535539

536-
class TestThumper(TestFsmTransitions):
540+
class TestThumper(TestFSMPlayer):
537541

538542
name = "Thumper"
539543
player = axelrod.Thumper
@@ -563,7 +567,7 @@ def test_strategy(self):
563567
self.transitions_test(state_and_actions)
564568

565569

566-
class TestEvolvedFSM4(TestFsmTransitions):
570+
class TestEvolvedFSM4(TestFSMPlayer):
567571

568572
name = "Evolved FSM 4"
569573
player = axelrod.EvolvedFSM4
@@ -601,7 +605,7 @@ def test_strategy(self):
601605
self.transitions_test(state_and_actions)
602606

603607

604-
class TestEvolvedFSM16(TestFsmTransitions):
608+
class TestEvolvedFSM16(TestFSMPlayer):
605609

606610
name = "Evolved FSM 16"
607611
player = axelrod.EvolvedFSM16
@@ -693,7 +697,7 @@ def test_strategy(self):
693697
self.transitions_test(state_and_actions)
694698

695699

696-
class TestEvolvedFSM16Noise05(TestFsmTransitions):
700+
class TestEvolvedFSM16Noise05(TestFSMPlayer):
697701

698702
name = "Evolved FSM 16 Noise 05"
699703
player = axelrod.EvolvedFSM16Noise05
@@ -780,3 +784,54 @@ def test_strategy(self):
780784
# finished 0, 1, 2, 3, 4, 5, 6, 8, 10, 11, 12, 13, 14, 15
781785
state_and_actions = to_state_eleven + [(11, C), (14, D)] + [(13, C)] * 3
782786
self.transitions_test(state_and_actions)
787+
788+
789+
class TestTF1(TestFSMPlayer):
790+
name = "TF1"
791+
player = axelrod.TF1
792+
expected_classifier = {
793+
'memory_depth': 16,
794+
'stochastic': False,
795+
'makes_use_of': set(),
796+
'long_run_time': False,
797+
'inspects_source': False,
798+
'manipulates_source': False,
799+
'manipulates_state': False
800+
}
801+
802+
def test_strategy(self):
803+
self.first_play_test(C)
804+
805+
806+
class TestTF2(TestFSMPlayer):
807+
name = "TF2"
808+
player = axelrod.TF2
809+
expected_classifier = {
810+
'memory_depth': 16,
811+
'stochastic': False,
812+
'makes_use_of': set(),
813+
'long_run_time': False,
814+
'inspects_source': False,
815+
'manipulates_source': False,
816+
'manipulates_state': False
817+
}
818+
819+
def test_strategy(self):
820+
self.first_play_test(C)
821+
822+
823+
class TestTF3(TestFSMPlayer):
824+
name = "TF3"
825+
player = axelrod.TF3
826+
expected_classifier = {
827+
'memory_depth': 8,
828+
'stochastic': False,
829+
'makes_use_of': set(),
830+
'long_run_time': False,
831+
'inspects_source': False,
832+
'manipulates_source': False,
833+
'manipulates_state': False
834+
}
835+
836+
def test_strategy(self):
837+
self.first_play_test(C)

0 commit comments

Comments
 (0)