Python Forum
Noob - What attributes to use for agents in evo sim (GA type) - Printable Version

+- Python Forum (https://python-forum.io)
+-- Forum: Python Coding (https://python-forum.io/forum-7.html)
+--- Forum: Data Science (https://python-forum.io/forum-44.html)
+--- Thread: Noob - What attributes to use for agents in evo sim (GA type) (/thread-4861.html)



Noob - What attributes to use for agents in evo sim (GA type) - PySam - Sep-11-2017

Ok, hopefully this is not the wrong forum!

I'm a hatchling to Python, but understand general concepts. I want to try my hand at creating a simple life evolution sim like the 1000000 others, mostly because I want to see it work and learn. Along the way I will try to represent it with graphics so I can watch pixels moving around the screen. :)

So for the 'agents' (creatures), what stats, or attributes do I give them that they will want to use and also be relevant 'genes' to pass on to the next gen?

This is what I have come up with so far in about an hour of A.D.D.'ing and googling (haven't been able to figure out how to search for something specific like this lol).

Nevermind the empty While loop or the Fitness stat (not sure what I would use).

(Python3.6)

from random import random, randint
import time
import numpy as np

class Agent:
    def __init__(self):
        self.x = randint(0,500)
        self.y = randint(0,500)
        self.ang = 0
        self.dx = 0
        self.dy = 0
        self.speed = 1
        self.food = 100
        self.target = {}
        self.age = 1

class Plant:
    def __init__(self):
        self.x = 0
        self.y = 0
        self.food = 20
        self.color = 1

def fitness (self, age):
    return (np.tanh (age/4))

agent = Agent()

i = 1
while i < 1000:
    i += 1
I feel like the self.xxxxx stuff is useless as genes because those would be "realtime" states of the creature, and not necessarily characteristics it would have... so I guess my issue is, just WHAT "evolvable" characteristics/attribs should I be thinking about using?

The agents need to be able to move around (perhaps varying max speeds would be a gene?)
The agents use food up to move (maybe varying metabolism like X food per Move speed that scales up exponentially the faster they move)?
The "Plants" give their food value to the Agent when eaten (not much to do there)
I want the Plants to have varying color giving varying food dependent on that color (maybe 'bad ones too that reduce food).
I want the Agents to be able to "see" the color and "learn" which plants are best (or even bad)

Thanks!


RE: Noob - What attributes to use for agents in evo sim (GA type) - Lux - Sep-12-2017

Not sure how helpful this will be, but my advice would just be to start with a simpler version of this and try to modify it from there, which is generally what I do when working on a Python project.

As for the specific case of an evolution simulator, you might start with a few basic stats- maybe one that impacted the chance of death and one that impacted reproduction. You might repeat this in 'rounds', where every round, your organisms have a chance of dying and a chance of mating. Something like that.
If you can get that to work, you can build off of it to add complexity to your simulator.

Hope that helps!


RE: Noob - What attributes to use for agents in evo sim (GA type) - PySam - Sep-12-2017

(Sep-12-2017, 11:36 PM)Lux Wrote: Not sure how helpful this will be, but my advice would just be to start with a simpler version of this and try to modify it from there, which is generally what I do when working on a Python project.

As for the specific case of an evolution simulator, you might start with a few basic stats- maybe one that impacted the chance of death and one that impacted reproduction. You might repeat this in 'rounds', where every round, your organisms have a chance of dying and a chance of mating. Something like that.
If you can get that to work, you can build off of it to add complexity to your simulator.

Hope that helps!

Thanks. I was beginning to think I was too vague (maybe I was).

I've made some progress from that barebones code above to something...'working' if it can be called that.
I can spawn in a few 'cells' and represent them on screen. I have the code in for plants (food) as well as far as their stats, just not drawn on screen yet.

So after thinking about and reading other tutorials (Genetic algorithms) I've realized that I need some "substance" to my animal's genes, i.e. variables that get 'set' randomly that would dictate some sort of ability to survive (fitness?) and also are accessible for me to 'grasp' in the code and turn into a "gene" list that I can then splice and dice / mutate and pass to child(ren).

In any case, in the near term, I have a basic structure up as you mentioned. Right now my point of STUCK is how do I "kill" an animal and remove it from the "agent[i]" references/lists/objects? and not screw up the index? Running this code should show you this (as soon as something runs out of food).

This is what the error looks like:
Traceback (most recent call last):
  File "C:\Python\GA_sim.py", line 111, in <module>
    update_cells()
  File "C:\Python\GA_sim.py", line 86, in update_cells
    agent.remove(i)
ValueError: list.remove(x): x not in list
Hopefully the formatting isn't screwed.

import math
import numpy as np
from random import random, randint
import time
import pygame as pg

pg.init()
screen = pg.display.set_mode ((500, 500))

clock = pg.time.Clock()

black = (0,0,0)
white= (255,255,255)

class Agent:
    def __init__(self, sense_range, size):
        self.x = randint(0,500)
        self.y = randint(0,500)
        self.ang = 0
        self.dx = 0
        self.dy = 0
        self.speed = 1
        self.food = 100 + randint(-25,50)
        self.target = []
        self.age = 1
        self.sense_range = sense_range  # generic sensor range to allow it to see
        self.size = size                # how large the cell is
        self.color = (randint(0,255), randint(0,255),randint(0,255)) 

class Plant:
    def __init__(self):
        self.x = randint(0,500)
        self.y = randint(0,500)
        self.age = 1
        #varying colors 1-4
        #varying food value based on color
        self.color = 1 + randint(0,3)  
        self.food = self.color * 10 + randint(1,10)
        
def fitness (self, age):
    return (np.tanh (age/4))

def populate_cells (num): # Create initial cell animals
    for x in range(num):
        smell = randint(25,50)
        size = randint(1,5)
        agent.append(Agent(smell, size))

def populate_plants (num): # Create initial plants (food)
    for x in range(num):
        plant.append(Plant())

# ==== Initialize global vars / Create entities ====
agent = []
plant = []
gen = 1
populate_cells(20)
populate_plants(10)

#Some debug stuff to verify cell population
#------------
#for i in range(len(agent[:])):
#   print (agent[i].x, agent[i].y)
#------------

def update_cells():
    for i in range(len(agent[:])):
        cell = agent[i]
        cell.age += 1
        cell.food -= 0.5
        if cell.food < 0:
            cell.food = 0
        cell.size = (cell.food/10) # Change size based on its food level
        if cell.size < 1:
            cell.size= 1
        cell.dx = randint(-2,2)
        cell.dy = randint(-2,2)
    
        cell.x += cell.dx
        cell.y += cell.dy
        cell.x = int(cell.x)
        cell.y = int(cell.y)
        pg.draw.circle (screen, cell.color, (cell.x,cell.y), int(cell.size))

        if cell.food <= 0:
            agent.remove(i)
        
def update_plants():
    for i in range(len(plant[:])):
        shrub = plant[i]
        shrub.age += 1
    
rep_limit = 500
rep = 0
done = False

# ==== Main loop ====
while done == False:

    for event in pg.event.get():
        if event.type == pg.QUIT:
            pg.quit()

    screen.fill(white)

    # Debug info showing food for agent[1]  
    font = pg.font.SysFont(None, 20)
    text= font.render ("Food: "+str(agent[1].food), True, black)
    screen.blit (text,(agent[1].x,agent[1].y+10))

    update_cells()
    update_plants()

    rep += 1
    if rep >= rep_limit:
        done = True
        print (done)

    
    pg.display.update()
    clock.tick(60)

pg.quit()



RE: Noob - What attributes to use for agents in evo sim (GA type) - Lux - Sep-13-2017

First of all, I think it would be helpful to read up on classes. I find this website pretty helpful. Learning more about classes can be very helpful.

As for your list error, it seems like you're using the list index instead of the object. the remove function takes an object, so instead of doing 
agent.remove(index)
you could do
agent.remove(agent[index])



RE: Noob - What attributes to use for agents in evo sim (GA type) - PySam - Sep-13-2017

Thanks! I actually figured it out somehow after stumbling across google again...

   def update_cells():
    # Iterate their food and age, change their physical size to reflect food content
    for i in range(len(agent[:])):
        cell = agent[i]
        cell.age += 1
        cell.food -= 0.5
        if cell.food < 0:
            cell.food = 0
        cell.size = (cell.food/10) # Change size based on its food level
        if cell.size < 1:
            cell.size= 1
        cell.dx = randint(-2,2)
        cell.dy = randint(-2,2)

        # Update position and draw on screen
        cell.x += cell.dx
        cell.y += cell.dy
        cell.x = int(cell.x)
        cell.y = int(cell.y)
        pg.draw.circle (screen, cell.color, (cell.x,cell.y), int(cell.size))

    # Kill off starved cells
    for cell in agent:
        if cell.food <= 0:
            agent.remove(cell)
For now I feel like my own learning is a 'genetic algorithm' in that I keep stumbling upon solutions. In any case, I'm curious if my "kill" solution is less efficient or has any dire effects compared to the way you wrote it (which I did end up sort of stumbling onto and tested out as well, last night).

For those curious, my code is now 'evolving' into a scary big mess like so.....
(I'm trying to do collision checks now by incorporating Sprites....that might be what you see in the Class inits....except I think my use of 'freeform' shapes (cells, plants that stretch/shrink) might not work "easily" with the Sprite requirement of "capturing" a static image and trying to manipulate that (without losing my goal to keep things relatively 'noob simple'. However, I'm positive that sprite groups are the key to doing collision checking for multiple Cells and Plants so they can efficiently 'eat' in each "check_collision()."

import math
import numpy as np
from random import random, randint
import time
import pygame as pg
import pygame.sprite as sprite

pg.init()
screen = pg.display.set_mode ((500, 500))
clock = pg.time.Clock()

black = (0,0,0)
white= (255,255,255)
red = (255,0,0)
green = (0,255,0)
blue = (0,0,255)

# ===== Sprite Groups for various entities ======

spr_cell_group = sprite.Group()
spr_plant_group = sprite.Group()


#======== Object Classes ========================

class Agent(sprite.Sprite):
    def __init__(self, sense_range, size, food, maxspeed):
        sprite.Sprite.__init__(self)
        self.x = randint(0,500)
        self.y = randint(0,500)
        self.ang = 0
        self.dx = 0
        self.dy = 0
        self.speed = 0
        self.maxspeed = maxspeed
        self.food = food
        self.target = []
        self.age = 1
        self.sense_range = sense_range  # generic sensor range to allow it to see
        self.size = size                # how large the cell is
        self.color = (randint(0,255), randint(0,255),randint(0,255))

class Plant (sprite.Sprite):
    def __init__(self):
        sprite.Sprite.__init__(self)
        self.x = randint(0,500)
        self.y = randint(0,500)
        self.age = 1 + randint(0,50)
        #varying colors 1-4
        #varying food value based on color
        self.color = 1 + randint(0,3)
        self.food = self.color * 10 + randint(1,10)
        self.size = self.food / 7

# Create initial random cell animals
def populate_cells (num): 
    for x in range(num):
        smell = randint(50,75)
        size = randint(1,5)
        food = 100 + randint(-25,50)
        maxspeed = randint(1,3)
        agent.append (Agent(smell, size, food, maxspeed))

# Create initial plants (food)
def populate_plants (num): 
    for x in range(num):
        plant.append (Plant())

# Animal 'fitness' to help gauge their survival
def fitness (self, age):
    return (np.tanh (age/4))

# ==== Initialize global vars / Create entities ====
agent = []
plant = []
gen = 1
populate_cells(50)
populate_plants(20)

#Some debug stuff to verify some cell population stats
#------------
#for i in agent:
#    print (i.food)
#------------

def update_cells():
    # Iterate their food and age, change their physical size to reflect food content
    for i in range(len(agent[:])):
        cell = agent[i]
        cell.age += 1
        cell.food -= 0.5
        if cell.food < 0:
            cell.food = 0
        cell.size = (cell.food/10) # Change size based on its food level
        if cell.size < 1:
            cell.size= 1
        cell.dx = randint(-2,2)
        cell.dy = randint(-2,2)

        # Spawn a 'child' cell if current cell has over X amount food, passing mixed stats
        # from the parent(s), giving half the parent's food to it
        if cell.food >= 120:
            if randint(1,100) == 1: 
                smell = cell.sense_range
                size = cell.size
                food = cell.food / 2
                maxspeed= cell.maxspeed
                agent.append (Agent(smell, size, food, maxspeed))


        # Update position and draw on screen
        cell.x += cell.dx
        cell.y += cell.dy
        cell.x = int(cell.x)
        cell.y = int(cell.y)
        pg.draw.circle (screen, cell.color, (cell.x,cell.y), int(cell.size))

    # Kill off starved cells
    for cell in agent:
        if cell.food <= 0:
            agent.remove(cell)
      
        
def update_plants():
    for shrub in plant:
        shrub.age += 1
        
        if shrub.color == 1:
            color = (0,50,0)
        elif shrub.color == 2:
            color = (0,100,0)
        elif shrub.color == 3:
            color = (0,150,0)
        elif shrub.color == 4:
            color = (0,250,0)
            
        pg.draw.circle (screen, color, (shrub.x,shrub.y), int(shrub.size))

        # Respawn 'old' plants in a different place
        if shrub.age >= 200:
            plant.remove(shrub)
            plant.append(Plant())

def check_collisions()
    cellgroup = 

    
rep_limit = 500
rep = 0
done = False

# ==== Main loop ====
while done == False:

    for event in pg.event.get():
        if event.type == pg.QUIT:
            pg.quit()
            break

    screen.fill(black)

    # Debug info showing food for an agent at index [3]  
    #if agent[3] in agent: 
    #    font = pg.font.SysFont(None, 20)
    #    text = font.render ("Food: "+str(agent[3].food), True, white)
    #    screen.blit (text,(agent[3].x,agent[3].y+10))

    update_cells()
    update_plants()
    check_collisions()

    rep += 1
    if rep >= rep_limit:
        done = True
        print ("Sim completed =", done)

    
    pg.display.update()
    clock.tick(60)

pg.quit()