1  """ 
  2  Springbot evolution extension. 
  3  Implements genetic operations like mutation and crossover 
  4  """ 
  5   
  6  from springbot import Springbot 
  7  from gear import Node, Spring 
  8  from random import choice, uniform, randint 
  9  from latimname import latimname 
 10  from math import sqrt, pi 
 11  from vector import Vector 
 12  from copy import copy 
 13   
 14   
 15  _bloodline_count = 0 
 16   
 17   
 18  BLOODLINE_SEP = ':' 
 19   
 21      """ 
 22      Extends springbot to evolution methods 
 23      """ 
 24   
 25 -    def __init__(self, parent=None, name="Unnamed", startangle=0, random=False): 
  40   
 42          """ 
 43          Return generations number 
 44          """ 
 45          return len(self['bloodline'].split(BLOODLINE_SEP)) - 1 
  46   
 53   
 55          """ 
 56          Crosses this springbot with another one, returning a new one 
 57          """ 
 58          global _bloodline_count 
 59   
 60           
 61          breed = EvolveSpringbot() 
 62   
 63           
 64          for key in self: 
 65              breed[key] = self[key] 
 66   
 67          breed['fitness'] = 0 
 68          breed['name'] = ' '.join(set(self['name'].split() + other['name'].split())) 
 69          breed['adapted'] = "random" 
 70   
 71           
 72          try: 
 73              breed['bloodline'] += 'X' + \ 
 74                  other['bloodline'].split(BLOODLINE_SEP)[0] + '...' + other['bloodline'].split(BLOODLINE_SEP)[-2] + \ 
 75                  BLOODLINE_SEP 
 76          except KeyError: 
 77              pass 
 78   
 79           
 80          for springA, springB in zip(self.springs + ([None] * ((len(other.springs)-len(self.springs))/2)), 
 81                                      other.springs + ([None] * ((len(self.springs)-len(other.springs))/2))): 
 82   
 83              if springA is None: springA = springB 
 84              elif springB is None: springB = springA 
 85   
 86               
 87              spring = choice([springA,springB]) 
 88   
 89               
 90              nodeA = breed.getNode(spring.a.id) 
 91              if nodeA is None: 
 92                  nodeA = choice([self,other]).getNode(spring.a.id) 
 93                  if nodeA is None: nodeA = spring.a 
 94   
 95                   
 96                  new_nodeA = Node(nodeA.pos, nodeA.vel, nodeA.acc) 
 97                  new_nodeA.id = nodeA.id 
 98                  nodeA = new_nodeA 
 99   
100                   
101                  breed.add(nodeA) 
102   
103               
104              nodeB = breed.getNode(spring.b.id) 
105              if nodeB is None: 
106                  nodeB = choice([self,other]).getNode(spring.b.id) 
107                  if nodeB is None: nodeB = spring.b 
108   
109                   
110                  new_nodeB = Node(nodeB.pos, nodeB.vel, nodeB.acc) 
111                  new_nodeB.id = nodeB.id 
112                  nodeB = new_nodeB 
113   
114                   
115                  breed.add(nodeB) 
116   
117               
118              breed.add(Spring(nodeA, nodeB, spring.amplitude, 
119                               spring.offset, spring.normal)) 
120   
121           
122          breed.removeUnconnected() 
123   
124           
125          return breed 
 126   
127 -    def mutate(self, newnodedist=100, nodevariation=10): 
 128          """ 
129          Mutates a random structure of the springbot, which may be 
130          adding or removing a node, adding or removing a spring, 
131          changing any spring's parameter or changing a node position. 
132          """ 
133           
134           
135           
136           
137           
138           
139           
140   
141          if len(self.nodes) == 0: 
142              return 
143   
144           
145          tipo = choice(range(6)) 
146   
147          if tipo == 0:  
148              neigh = choice(self.nodes) 
149              newnode = Node(pos=(neigh.pos.x + uniform(-newnodedist, newnodedist), 
150                              neigh.pos.y + uniform(-newnodedist, newnodedist))) 
151   
152              self.add(newnode)        
153              self.add(Spring(neigh, newnode, offset=uniform(0,pi*2)))  
154   
155          elif tipo == 1 and len(self.nodes) > 1:  
156   
157               
158              copia = Springbot() 
159              copia.nodes = copy(self.nodes) 
160              copia.springs = copy(self.springs) 
161   
162               
163              toremove = choice(copia.nodes) 
164   
165               
166              copia.remove(toremove) 
167              if not copia.unconnected(): 
168                   
169                  for node in self.nodes: 
170                      if node.id == toremove.id: 
171                          self.remove(node) 
172                          break 
173   
174          elif tipo == 2 and len(self.nodes) > 1:  
175              a = choice(self.nodes) 
176              b = choice(self.nodes) 
177   
178               
179              while a is b: 
180                  b = choice(self.nodes) 
181   
182              self.add(Spring(a, b, offset=uniform(0,pi*2)))    
183          elif tipo == 3 and len(self.springs) > 0:  
184   
185               
186              toremove = choice(self.springs) 
187   
188               
189              self.remove(toremove) 
190              if self.unconnected(): 
191                   
192                  self.add(toremove) 
193   
194          elif tipo == 4 and len(self.springs) > 0:  
195              spring = choice(self.springs) 
196              if choice([1, 2]) == 1: 
197                  spring.offset = max(spring.offset + uniform(-pi, pi), 0) 
198              else: 
199                  added = uniform(-0.5, 0.5) 
200                  spring.amplitude = spring.amplitude + added if abs(spring.amplitude + added) <= 0.5 else spring.amplitude 
201   
202          elif tipo == 5:  
203              node = choice(self.nodes) 
204              node.pos.x += uniform(-nodevariation,nodevariation) 
205              node.pos.y += uniform(-nodevariation,nodevariation) 
206   
207               
208              for spring in self.springs: 
209                  if spring.a is node or spring.b is node: 
210                      spring.normal = sqrt(sum((spring.a.pos-spring.b.pos)**2)) 
211   
212           
213          return self 
  214   
215   
216   
217   
218   
220      """ 
221      Creates a new springbot totally random 
222      """ 
223       
224      springbot = EvolveSpringbot(name=latimname(5)) 
225      springbot["adapted"] = "random" 
226   
227      for x in xrange(randint(nodes_num/2, nodes_num)): 
228           
229          newnode = Node(pos=(uniform(-noderadius, noderadius), 
230                  uniform(-noderadius, noderadius))) 
231          springbot.add(newnode)   
232   
233      if len(springbot.nodes) > 1: 
234          for x in xrange(randint(springs_num/2, springs_num)): 
235               
236              a = choice(springbot.nodes) 
237              b = choice(springbot.nodes) 
238   
239               
240              while a is b: 
241                  b = choice(springbot.nodes) 
242   
243               
244              springbot.add(Spring(a, b, offset=uniform(0,pi*2), amplitude=uniform(-0.5, 0.5))) 
245   
246       
247      springbot.removeUnconnected() 
248   
249      return springbot 
 250   
251   
252   
253   
254