def make_net(sensor_count= 16): net = NeuralNetwork([sensor_count, 7, 2], learn_rate=0.05) test_db = create_tests(sensor_count) # print "\n".join([str(x) for x in test_db]) random.shuffle(test_db) for i in range(5): answ = net.calculate(test_db[i][0]) print(test_db[i][0], test_db[i][1], answ) errs = [] for _ in range(200): epoch_error = 0 for test in test_db: y = net.calculate(test[0]) err = math.sqrt((test[1][0]-y[0])**2 + (test[1][1]-y[1])**2) if err < 1.0: net.teach(-0.004) else: net.teach(0.004) epoch_error += err epoch_error /= len(test_db) errs.append(epoch_error) print epoch_error for i in range(10): answ = net.calculate(test_db[i][0]) print(test_db[i][0], test_db[i][1], answ) if __name__=='__main__': plt.plot(errs) plt.show() return net
class Animal(object): DEBUG = False MAX_ENERGY = 30 ENERGY_FOR_EXIST = 0.007 MOVE_ENERGY_RATIO = 0.01 # sensor_count_in_head / sensor_count SENSOR_COUNT_IN_HEAD_RATIO = 0.5 # head angle HEAD_ANGLE = math.pi / 4.0 HALF_HEAD_ANGLE = HEAD_ANGLE / 2.0 READINESS_TO_BUD_THREADSHOULD = 30 READINESS_TO_BUD_INCREASEMENT = 0.2 ENERGY_FULLNES_TO_BUD = 0.7 ENERGY_FOR_BUD = 5 MIN_CHILD_COUNT = 1 MAX_CHILD_COUNT = 3 MUTATE_VALUE = 0.4 HALF_MUTATE_VALUE = MUTATE_VALUE / 2 MUTATE_CHANCE = 0.6 def __init__(self, world): self.world = world self._x = randint(0, self.world.width) self._y = randint(0, self.world.height) self.size = 7 self.angle = 0 self.sensor_count = 7 self._sensor_count_in_head = int(self.sensor_count * Animal.SENSOR_COUNT_IN_HEAD_RATIO) self._sensor_count_not_in_head = self.sensor_count - self._sensor_count_in_head self.sensor_values = [] self._sensors_positions = [] self._sensors_positions_calculated = False self.energy = self.ENERGY_FOR_BUD self.readiness_to_bud = 0 self.brain = NeuralNetwork([self.sensor_count, 2, 2]) # import BrainTrainer # self.brain = clone_brain(BrainTrainer.get_new_brain(self.sensor_count)) @property def sensors_positions(self): # on 45 degrees (pi/4) of main angle located 75% of all sensors if not self._sensors_positions_calculated: self._sensors_positions = [] # calc sensor positions in head delta_angle = Animal.HEAD_ANGLE / (self._sensor_count_in_head-1) angle = -Animal.HALF_HEAD_ANGLE + self.angle for _ in range(self._sensor_count_in_head): self._sensors_positions.append( (math.cos(angle) * self.size + self._x, math.sin(angle) * self.size + self._y)) angle += delta_angle # calc sensor positions in body delta_angle = (TWO_PI - Animal.HEAD_ANGLE) / (self._sensor_count_not_in_head+1) angle = Animal.HALF_HEAD_ANGLE + self.angle for _ in range(self._sensor_count_not_in_head): angle += delta_angle self._sensors_positions.append( (math.cos(angle) * self.size + self._x, math.sin(angle) * self.size + self._y)) self._sensors_positions_calculated = True return self._sensors_positions def update(self, sensor_values): self.sensor_values = sensor_values answer = self.brain.calculate(self.sensor_values) self.answer = answer self.energy -= Animal.ENERGY_FOR_EXIST if self.energy / Animal.MAX_ENERGY > Animal.ENERGY_FULLNES_TO_BUD: self.readiness_to_bud += Animal.READINESS_TO_BUD_INCREASEMENT if self.readiness_to_bud >= Animal.READINESS_TO_BUD_THREADSHOULD: self.readiness_to_bud = 0 self.bud() self.move(answer[0], answer[1]) def bud(self): child_count = randint(Animal.MIN_CHILD_COUNT, Animal.MAX_CHILD_COUNT) # if it tries to bud more child than it can - bud so many as it can and die. if child_count*Animal.ENERGY_FOR_BUD > self.energy: child_count = int(self.energy / Animal.ENERGY_FOR_BUD) self.energy = 0 for _ in range(child_count): self.energy -= Animal.ENERGY_FOR_BUD child = Animal(self.world) child.x = self.x + randint(-30, 30) child.y = self.y + randint(-30, 30) child.brain = clone_brain(self.brain) self.world.add_animal(child) def eat(self, food): value = min(World.World.EATING_VALUE, max(0, Animal.MAX_ENERGY - self.energy)) value = food.beating(value) self.energy += value def move(self, move, rotate): self.energy -= (abs(move) + abs(rotate))*Animal.MOVE_ENERGY_RATIO self._sensors_positions_calculated = False self.angle += rotate self._x += math.cos(self.angle) * move * 2.0 self._y += math.sin(self.angle) * move * 2.0 @property def x(self): return self._x @x.setter def x(self, value): self._x = value self._sensors_positions_calculated = False @property def y(self): return self._y @y.setter def y(self, value): self._y = value self._sensors_positions_calculated = False