a simulation of the evolution of brain equipped agents
This program simulates agents that are equipped with several sensors and actors. Sensors and actors are conected through an artificial neural network which is unique for every single angent. The weights of the feed forward net are updated through an evolutionary algorithm. The age of the agent provides an implicit fitness function.
To run simulation.py, pygame and numpy need to be installed.
$ pip install pygame
$ pip install numpy
The agents live on a grid of food, which partly gets consumed on the position where an agent is passing over it. When doing so, the agent replenishes health which he loses constantly or through special interactions. Once an agent's health reaches 0, the agent dies. In every frame, every agent has a chance to reproduce. Reproduction can happen sexually (only possible when agents collide) or asexually. The offspring shares the DNA of its parent or a mix of the DNAs of its parents in the former case (cross-over). The offspring's dna also has a chance to mutate individual genes. Agent with similar DNA belong to a certain clan, which also defines their names. New clans can emerge when the genetic distance between parent and child dna exceeds are certain threshold.
Aside from the main simulation area the program has several informative sections:
- the population graph (bottom): shows the amount of food in the world and the numer of agents over time
- the agent ranking (top right): lists the oldest agents and a ranking of the most successful clans
- the agent's brain (right): shows the neural network weights of a representative agent from the dominant clan
Agents are equipped with 13 sensors that form the input vector for the neural network:
- health: the current health percentage (also mirrored in the agents color intensity)
- speed: the current speed (relative to max_speed)
- center_food: the amount of food on the tile just below the agent
- feel_right_food: the amount of food on the tile below the agents right feeler
- feel_left_food: -analogous-
- proximity_right: inverse of the distance to the closest other agent on the right side (normlized by the sensing range)
- red_right: the amount of red shown by the agent that is closest on the right side
- green_right: the amount of green shown by the agent that is closest on the right side
- proximity_left: -analogous-
- red_left: -analogous-
- green_left: -analogous-
- ear_back: the sum of inverse distances of other agents behind the agent. Capped on a set maximum value.
- collision: binary signal of weather or not the agent collides with another
According to the sensory input and its brain, an agent will show certain output values:
- torque: the angle of further movement
- acceleration: the movement speed for the next frame
- spike: the spike length - defines the agents strength, but increases it's ressource costs
- aggressivness: defines what happens when the agent collides. Makes the agent more red.
- altruisticness: defines what happens when the agent collides. Makes the agent more green.
Allowing agents to "choose" between being aggressive and altruistic, aims to have different survival strategies emerging. Aggressive agents bite on collision, while altruistic agents transfuse health to the agent they collide with. The amout of bitten or tranfused health depends on an agents spike size/power.
Several agent agnostic parameters may be changed within the agents 'init()' and 'setPheno()' methods to further generate interesting evolution.
def __init__(...):
[...]
self.power = 3
self.max_age = 7000
self.asexual_reproduction_rate = 0.002
self.sexual_reproduction_rate = 0.006
self.metabolism = 1
self.reproduction_cost = 0
[...]
def setPheno(self):
self.max_health = 50*self.size
self.health = self.max_health / 1.5 # self.reproduction_cost * 2
self.bitesize = self.size * 2
self.energyefficiency = 400 / (self.size * self.size)
self.max_velocity = 1000 / (self.size * self.size)
self.max_acceleration = 200 / (self.size * self.size)One might also change what exactly happens when two agents collide within the agents 'collide()' method, to observe how this in turn affects the agents behavioral evolution.
def collide(self):
self.collission = 1 if self.collisionList else 0
for otherAgent in self.collisionList:
## plain damage
#self.health -= 25
## instant death
#self.health = -100
## only the faster one bites
#if self.velocity > otherAgent.velocity:
# self.bite(otherAgent)
#both transfuse and bite
self.bite(otherAgent)
self.transfuse(otherAgent)Philipp Skudlik

