#!/usr/bin/env python from Tkinter import * from math import * from time import * from random import * R = 20 SX = 25 SY = 15 Ngenerations = 500 DELAY = 0.01 #======================================================================= class Organism: #-------------------------------------------- # __init__ #-------------------------------------------- def __init__(self, canvas, i, j): self.canvas = canvas self.x = 3 + i*2*R + R self.y = 3 + j*2*R + R self.gr = canvas.create_oval(1,1,2,2) self.Randomize() #-------------------------------------------- # Randomize #-------------------------------------------- def Randomize(self): # Randomly set properties of organism. This is # called when the organism is first created or # when the simulation is reset self.predator = random()>0.9 self.alive = random()>0.2 self.r = R*(random()*0.8+0.2) self.camo = random() self.repo_period = randint(1,10) self.Tborn = 1 # will be overwritten if organism is not alive yet self.fat = random()*self.r self.cycles_before_reproducing = randint(0, self.repo_period) self.UpdateSize(self.r) self.UpdateColor() #-------------------------------------------- # UpdateSize #-------------------------------------------- def UpdateSize(self, r): if r>R: r= R if r<0.05*R: r=0.05*R self.r = r x0 = self.x - r x1 = self.x + r y0 = self.y - r y1 = self.y + r self.canvas.coords(self.gr, x0, y0, x1, y1) #-------------------------------------------- # UpdateColor #-------------------------------------------- def UpdateColor(self): if self.alive: # alive red = 0.0 blu = 0.0 grn = self.camo if self.predator: red = 0.5 else: blu = 0.5 color = '#%02x%02x%02x' % (int(255.0*red), int(255.0*grn), int(255.0*blu)) self.canvas.itemconfig(self.gr, fill=color, outline='black') else: # dead self.canvas.itemconfig(self.gr, fill='white', outline='white') #======================================================================= class MyApp: #-------------------------------------------- # __init__ #-------------------------------------------- def __init__(self, master): # Window split into 3 horizontal frames: # top=stats mid=main graphic bot=buttons topframe = Frame(master) midframe = Frame(master) botframe = Frame(master) topframe.pack(side=TOP) midframe.pack(side=TOP) botframe.pack(side=TOP) # buttons self.bstart = Button( botframe, text="START", command=self.start_simulation) self.bstop = Button( botframe, text="STOP", command=self.stop_simulation) self.breset = Button( botframe, text="RESET", command=self.reset_simulation) self.bquit = Button( botframe, text="QUIT", command=master.quit ) self.bstart.pack(side=LEFT) self.bstop.pack(side=LEFT) self.breset.pack(side=LEFT) self.bquit.pack(side=RIGHT) # canvas pixels_wide = 2*R*SX+1 pixels_high = 2*R*SY+1 self.canvas = Canvas(midframe, width=pixels_wide, height=pixels_high, background='white') self.canvas.pack() # Organisms self.organism = [] for i in range(0,SX): self.organism.append([]) for j in range(0,SY): self.organism[i].append(Organism(self.canvas, i, j)) # Open files to record organism traits at time of death self.pred_dead_outfile = open('death_traits_predator.csv', 'w') self.prey_dead_outfile = open('death_traits_prey.csv', 'w') self.pred_live_outfile = open('live_traits_predator.csv', 'w') self.prey_live_outfile = open('live_traits_prey.csv', 'w') #-------------------------------------------- # start_simulation #-------------------------------------------- def start_simulation(self): print 'Simulation starting ....' self.done = False for self.T in range(1, Ngenerations): # Allow predetors to prey self.predator_kills() # Allow prey to eat self.prey_feed() # Allow predetors and prey to starve self.starve() # Allow organisms to breed self.breed() # Update visual self.update_visual() # Record traits of all living organisms self.RecordLiveTraits() if self.done: break sleep(DELAY) print 'done' self.canvas.update() #-------------------------------------------- # stop_simulation #-------------------------------------------- def stop_simulation(self): self.done = True print 'Simulation stopped' self.pred_outfile.close() self.prey_outfile.close() #-------------------------------------------- # reset_simulation #-------------------------------------------- def reset_simulation(self): for i in range(0,SX): for j in range(0,SY): self.organism[i][j].Randomize() #-------------------------------------------- # KillOrganism #-------------------------------------------- def KillOrganism(self, org): # Set organism's alive status to False and record traits org.alive = False if org.predator: self.pred_dead_outfile.write('%d,%f,%f,%f,%f,%f,%d\n' % (self.T, self.T-org.Tborn, org.camo, org.r, org.repo_period, org.fat, org.cycles_before_reproducing)) else: self.prey_dead_outfile.write('%d,%f,%f,%f,%f,%f,%d\n' % (self.T, self.T-org.Tborn, org.camo, org.r, org.repo_period, org.fat, org.cycles_before_reproducing)) #-------------------------------------------- # RecordLiveTraits #-------------------------------------------- def RecordLiveTraits(self): # Record the traits of all living organisms at the end of the generation for i in range(0,SX): self.organism.append([]) for j in range(0,SY): org = self.organism[i][j] if org.predator: self.pred_live_outfile.write('%d,%f,%f,%f,%f,%d\n' % (self.T, org.camo, org.r, org.repo_period, org.fat, org.cycles_before_reproducing)) else: self.prey_live_outfile.write('%d,%f,%f,%f,%f,%d\n' % (self.T, org.camo, org.r, org.repo_period, org.fat, org.cycles_before_reproducing)) #-------------------------------------------- # predator_kills #-------------------------------------------- def predator_kills(self): # This checks all predators and randomly chooses which, # if any neighboring prey are killed for i in range(0,SX): for j in range(0,SY): org_pred = self.organism[i][j] if not org_pred.alive : continue if not org_pred.predator : continue # Loop over neighbors imin = max(i-1,0) imax = min(i+2,SX) jmin = max(j-1,0) jmax = min(j+2,SY) for ii in range(imin, imax): for jj in range(jmin, jmax): org_prey = self.organism[ii][jj] # Make sure prey is alive if not org_prey.alive: continue; # predators can't eat other predators if org_prey.predator : continue # predator must be bigger than prey if org_prey.r >= org_pred.r: continue # predator must not already be "full" if (org_pred.fat + org_prey.r/2.0) > org_pred.r: continue # prey's chance of survival depends on # camouflage and size differential survival_prob = 1.0 - (org_pred.r - org_prey.r)/R survival_prob *= org_prey.camo survival_prob *= 1.0 - org_pred.camo #survival_prob *= 0.0 # Roll the dice to see if prey lives if random() > survival_prob: # kill prey org_pred.fat += org_prey.r/2.0 self.KillOrganism(org_prey) #-------------------------------------------- # prey_feed #-------------------------------------------- def prey_feed(self): # This checks all prey and "feeds" them based on the total # size of all its neighbors. For this model, assume # in the 3x3 block around the organism there is enough food # for 1 full sized organism (or 9 organisms of 1/9 full size). # The organism will get a share of this food that is proportional # to the fraction of the total size it represents of these 9 # organisms. Dead organisms are ignored and a prey organism can # only consume enough food to sustain it for 1.5 rounds for i in range(0,SX): for j in range(0,SY): org = self.organism[i][j] if org.predator : continue if not org.alive : continue # Loop over neighbors imin = max(i-1,0) imax = min(i+2,SX) jmin = max(j-1,0) jmax = min(j+2,SY) tot_size = 0.0 for ii in range(imin, imax): for jj in range(jmin, jmax): org_herd = self.organism[ii][jj] if org_herd.alive and not org_herd.predator: tot_size += org_herd.r frac_size = org.r/tot_size food = min(R*0.10 * frac_size, org.r*0.15) org.fat += food #-------------------------------------------- # starve #-------------------------------------------- def starve(self): # Loop over all organisms reducing fat reserves and checking if they have starved for i in range(0,SX): for j in range(0,SY): org = self.organism[i][j] if not org.alive: continue org.fat -= org.r*0.10 if org.fat<0.0: self.KillOrganism(org) #-------------------------------------------- # breed #-------------------------------------------- def breed(self): for i in range(0,SX): for j in range(0,SY): org = self.organism[i][j] if not org.alive : continue # Check if this organism is ready to reproduce if org.cycles_before_reproducing > 0: org.cycles_before_reproducing -= 1 continue # Randomly select child's properties based on parent's child_r = gauss(org.r, 0.1) # random value with standard deviation of 10% child_camo = gauss(org.camo, 0.04) # random value with standard deviation of 1% child_repo_period = int(gauss(float(org.repo_period), 2)) # random value with stadard deviation of 2 cycles # Limit values to specific ranges child_r = max(min(child_r,R), 0.2*R) child_camo = max(min(child_camo,1.0), 0.0) child_repo_period = max(min(child_repo_period,10), 1) # Without this, the predators seem to die off since the prey # just grow large enough to never be eaten! if not org.predator: child_r *= 0.9 # This is an empirical factor tuned so that the grid is not always # filled or destined to be empty. Make it higher to fill the grid # more and lower to empty faster reproduction_prob = 1.9 # This tuning parameter makes predators less likely to reproduce than # prey. This helps balance things a bit so the predator doesn't always win if org.predator : reproduction_prob *= 0.7 # Camouflage can reduce chances of reproduction reproduction_prob *= (1.0 - org.camo)*0.3 + 0.7 # Number of babies depends slightly on sizes Nbabies = int(random()*reproduction_prob*org.r/child_r) # Loop over neighbors imin = max(i-1,0) imax = min(i+2,SX) jmin = max(j-1,0) jmax = min(j+2,SY) for ii in range(imin, imax): for jj in range(jmin, jmax): org_neighbor = self.organism[ii][jj] if org_neighbor.alive: continue # only breed into empty slots if Nbabies>0: org_neighbor.Tborn = self.T org_neighbor.alive = True org_neighbor.predator = org.predator org_neighbor.r = child_r org_neighbor.camo = child_camo org_neighbor.repo_period = child_repo_period org_neighbor.fat = 0.5*org_neighbor.r org_neighbor.cycles_before_reproducing = child_repo_period Nbabies -= 1 org.cycles_before_reproducing = org.repo_period #-------------------------------------------- # update_visual #-------------------------------------------- def update_visual(self): # Loop over all organisms and randomly tweak parameters to mimic evolution for i in range(0,SX): for j in range(0,SY): org = self.organism[i][j] org.UpdateColor() self.canvas.update() # <><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><> if __name__ == '__main__': top = Tk() app = MyApp(top) top.mainloop() print 'Program finished'