Skip to content

Instantly share code, notes, and snippets.

@bened-h
Last active November 9, 2021 19:16
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save bened-h/854f7b69c63dd8f7571ed7896566d518 to your computer and use it in GitHub Desktop.
Save bened-h/854f7b69c63dd8f7571ed7896566d518 to your computer and use it in GitHub Desktop.
Simple "genetic" algorithm for Processing (Python mode) showing a random point polpulation evolving to become a circle
"""
This demonstration evolves a random point
population (parent) to order its points into a
circular arrangement (target).
The fitness is computed by measuring each point's
distance to its destination.
Read an introduction to genetic algorithms with python here:
https://www.codeproject.com/articles/1104747/introduction-to-genetic-algorithms-with-python-hel
"""
from random import random, randrange
from math import pi
def generate_parent(leng):
genes = []
while len(genes) < leng:
genes.append((random()*sx, random()*sy))
return genes
def get_fitness(guess):
d = 0
# add all the distances:
for i, t in enumerate(target):
d+= dist(t[0], t[1], guess[i][0], guess[i][1])
return 1/d
def mutate_node(parent, fitness):
mutation_size = 20/fitness/sx/sy # as fintess gets larger, mut gets smaller
index = randrange(0, len(parent)) # get random index
x = (random()*2-1)* sx * mutation_size
y = (random()*2-1)* sx * mutation_size
# print("{}\t{}\t{}".format(mutation_size, x, y))
child = parent[:] # make a copy of parent
# modify node at index:
child[index] = (child[index][0]+x, child[index][1]+y)
return child
def display(guess, shade = 0, radius = 4):
fill(shade)
for i, n in enumerate(guess):
x, y = n
# grey lines inbetween: very slow for large numbers (<10)
for x2, y2 in guess[::num_of_points/5]:
stroke(0, 20)
line(x,y,x2,y2)
fill(shade)
ellipse(x,y,radius,radius)
stroke(shade)
# line to last node -> circle outline:
line(x,y,guess[i-1][0], guess[i-1][1])
# screen size:
sx, sy = 800, 800
num_of_points = 10 #
# construct target population:
target = []
for i in range(num_of_points):
angle = pi*2/num_of_points*i
# polar to cartesian coords:
x, y = 800/2 + sin(angle)*250, 800/2 + cos(angle)*250
target.append((x,y))
best_parent = generate_parent(len(target))
def setup():
size(sx,sy)
frameRate(50)
def draw():
background(200)
global best_parent # get the global variable
best_fintess = get_fitness(best_parent)
fill(0)
# text("Fitness: " + str(best_fintess), 0,10)
# stroke(150)
# display(target, 200, 8)
# stroke(0)
display(best_parent)
# look for fitter child:
attempts = 0
while True:
child = mutate_node(best_parent, best_fintess)
childFitness = get_fitness(child)
if best_fintess <= childFitness:
best_fintess = childFitness
best_parent = child
break
attempts += 1
if attempts >200:break #draw even if no better child found
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment