import sys, pygame, random, time
def random_color():
  color = random.randrange(0,255)
  return color,color,color

class Creature:
    "A simple creature"
    def __init__(self):        
      self.skin_color = random_color()
    def fitness(self,background_color):
        fitness = background_color[0]-self.skin_color[0] 
        if fitness < 0 : fitness += 255 
        return fitness
    def mate(self,creature):
      new_color = (self.skin_color[0] + creature.skin_color[0] ) / 2
      child = Creature()
      child.skin_color= new_color,new_color,new_color
      return child
    def mutate(self):
      new_color = (self.skin_color[0] - random.randrange(-20,20)) % 255
      self.skin_color = new_color,new_color,new_color    

def create_new_population(population,background_color):
  new_population = []
  population_size = len(population)
  population.sort(lambda x, y: cmp(x.fitness(background_color), y.fitness(background_color)))
  
  #the least fit die:
  population = population[0:len(population)-len(population)/4]
  
  #survival of the fittest:
  for i in range(len(new_population),len(new_population)+population_size*5/10):
    new_population.append(population[i])  
  
  #some fornicate:
  for i in range(len(new_population),len(new_population)+population_size*4/10):
      parent1 = population[random.randrange(0,len(population)/3)]
      parent2 = population[random.randrange(0,len(population)/3)]
      child = parent1.mate(parent2)
      new_population.append(child) 
  
  #others mutate
  for i in range(len(new_population),population_size):
    mutant = population[random.randrange(0,len(population))]
    mutant.mutate()
    new_population.append(mutant) 
  
  random.shuffle(new_population)  
  return new_population 
  
def population_fitness(population,background_color):
  total_fitness = 0
  for i in range(0,len(population)):
    total_fitness += population[i].fitness(background_color)
  #print total_fitness
  return total_fitness;
 
size = width, height = 640, 480
population_size=20000
spacing = 2
creature_size = ( width * height / population_size - 4) ** 0.5 
population = []
background = random_color() 

pygame.init()
screen = pygame.display.set_mode(size)
screen.fill(background)

for x in range(0,population_size):
    creature = Creature()
    population.append(creature)

pygame.display.flip()

while 1:
  screen.fill(background)
  population = create_new_population(population,background)
  population_fitness(population,background)
  y = 0
  x = 0
  
  for i in range(0,len(population)):    
    creature = population[i]
    pygame.draw.rect(screen,creature.skin_color, (x,y, creature_size, creature_size))
    x +=  spacing + creature_size
    if x + creature_size + spacing> width : 
      x = 0
      y += creature_size + spacing
  pygame.display.flip()    
  
  for event in pygame.event.get():
    if event.type == pygame.QUIT: sys.exit()
    elif event.type == pygame.MOUSEBUTTONDOWN : background = random_color() 
  
  new_background = (background[0] + 2) % 255
  background = new_background,new_background,new_background
  time.sleep(0.1)
  
 
  
  
  

