Skip to content

Commit 98434e7

Browse files
committed
Add evolvable_player.py
1 parent 4693ca2 commit 98434e7

File tree

1 file changed

+89
-0
lines changed

1 file changed

+89
-0
lines changed

axelrod/evolvable_player.py

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
from pickle import dumps, loads
2+
import random
3+
from .player import Player
4+
5+
6+
class InsufficientParametersError(Exception):
7+
"""Error indicating that insufficient parameters were specified to initialize an Evolvable Player."""
8+
9+
def __init__(self, *args):
10+
super().__init__(*args)
11+
12+
13+
class EvolvablePlayer(Player):
14+
"""A class for a player that can evolve, for use in the Moran process or with reinforcement learning algorithms.
15+
16+
This is an abstract base class, not intended to be used directly.
17+
"""
18+
19+
name = "EvolvablePlayer"
20+
21+
def overwrite_init_kwargs(self, **kwargs):
22+
"""Use to overwrite parameters for proper cloning and testing."""
23+
for k, v in kwargs.items():
24+
self.init_kwargs[k] = v
25+
26+
def create_new(self, **kwargs):
27+
"""Creates a new variant with parameters overwritten by kwargs."""
28+
init_kwargs = self.init_kwargs.copy()
29+
init_kwargs.update(kwargs)
30+
return self.__class__(**init_kwargs)
31+
32+
# Serialization and Deserialization to strings. You may overwrite to obtain more human readable serializations
33+
# but you must overwrite both.
34+
35+
def serialize_parameters(self):
36+
"""Serialize parameters to a string for reinforcement learning."""
37+
return dumps(self.init_kwargs)
38+
39+
@classmethod
40+
def deserialize_parameters(cls, serialized):
41+
"""Deserialize parameters to a Player instance."""
42+
init_kwargs = loads(serialized)
43+
return cls(**init_kwargs)
44+
45+
# Optional methods for evolutionary algorithms and Moran processes.
46+
47+
def mutate(self):
48+
"""Optional method to allow Player to produce a variant (not in place)."""
49+
pass
50+
51+
def crossover(self, other):
52+
"""Optional method to allow Player to produce variants in combination with another player. Returns a new
53+
Player."""
54+
pass
55+
56+
# Optional methods for particle swarm algorithm.
57+
58+
def receive_vector(self, vector):
59+
"""Receive a vector of params and overwrite the Player."""
60+
pass
61+
62+
def create_vector_bounds(self):
63+
"""Creates the bounds for the decision variables for Particle Swarm Algorithm."""
64+
pass
65+
66+
67+
def copy_lists(lists):
68+
return list(map(list, lists))
69+
70+
71+
def crossover_lists(list1, list2):
72+
cross_point = random.randrange(len(list1))
73+
new_list = list(list1[:cross_point]) + list(list2[cross_point:])
74+
return new_list
75+
76+
77+
def crossover_lists_of_lists(lists1, lists2):
78+
cross_point = random.randrange(len(lists1))
79+
new_lists = copy_lists(lists1[:cross_point]) + copy_lists(lists2[cross_point:])
80+
return new_lists
81+
82+
83+
def crossover_dictionaries(table1, table2):
84+
keys = list(table1.keys())
85+
cross_point = random.randrange(len(keys))
86+
new_items = [(k, table1[k]) for k in keys[:cross_point]]
87+
new_items += [(k, table2[k]) for k in keys[cross_point:]]
88+
new_table = dict(new_items)
89+
return new_table

0 commit comments

Comments
 (0)