Thanks! I actually figured it out somehow after stumbling across google again...
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()."
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()