- Max Clark

# Genetic Algorithms: Physics - Part 2

This next part in the genetic algorithm series will go through the programming of the physics behind the genetic algorithm introduced in part 1. If you have not already seen part 1, you can find it __here__; it contains an overall explanation of the algorithm.

First lets import some libraries, initiate pygame and setup the window.

import pygame import time import math from math import radians, sin, cos import random from random import randint as ri

pygame.init()

xSize, ySize = 600, 600 screen = pygame.display.set_mode((xSize, ySize)) pygame.display.set_caption("Learn to Fly")

Next we create a function which will set the coordinates of the hands and elbows of the bird to the correct position. It calculates the coordinates of a point given the arm length; angle between the desired point, given point and an imaginary north-south line; and the given point coordinates.

def get_end(length,angle,px0,py0): py = length*cos(radians(angle)) + py0 px = length*sin(radians(angle)) + px0 return int(px),int(py)

The variables include 'length' which is the distance between each dot on the bird. Then, 'ox' and 'oy' are the coordinates of the starting position of the body (show in green) of the bird. The position of the body is given by 'px1' and 'py1' while 'px2' is for the hands (red) and 'px3' is for the elbows (blue) - don't ask why I numbered them that way around! The coordinates of the hands and elbows don't need to be given values because they are calculated in the function above. Because the bird is mirrored, we only need one coordinate for each of the hands and elbows. Finally, 't1' and 't2' are the angles shown in the image above. Through trial and error, I discovered that 't1' needs to be a negative value so that each wing stays on the correct side.

length = 100 ox, oy = 300,ySize-200 px1, py1 = ox, oy px2, py2 = 0,0 px3, py3 = 0,0

t1 = -150

t2 = 90

Next, we start our familiar main loop.

#----------------------Main Loop----------------------# clock = pygame.time.Clock() frameCount = 0 done = False while not done: frameCount += 1 screen.fill([255,255,255])

Every frame, we calculate the positions of the hands and elbows. We use '180-t2+t1' instead of 't2' because that gives us the angle between an imaginary north-south line which is what the 'get_end' function is designed for.

px3,py3 = get_end(length,t1,px1,py1) px2,py2 = get_end(length,180-t2+t1,px3,py3)

Now we calculate the upward/downward movement of bird. This is calculated by multiplying the distance the hands move downwards, '(py2 - ppy)', by the distance the hands are from the body, '(px2 - px1)'. The variable 'ppy' is the previous y value of the body. In the first frame, it hasn't been defined, hence the need for the if statement. The number '200' is a constant which effectively determines the air resistance. A smaller constant will increase the air resistance and therefore increase the amount of movement the flapping generates. Next, we add gravity, shown by the '+ 1'; this value adjusts the strength of gravity. We want the bird to not fall beneath the window and have the bottom of the window acting as the ground, hence if any of the points are below the window, we decrease the value of 'py1' by the distance the furthest point from the bottom is from the bottom. Then we set 'ppy' to the current body position for use in the next frame.

if frameCount > 1: diff = (py2 - ppy)*(px2 - px1)/200 if py1 < ySize and py2 < ySize and py3 < ySize: py1 += diff + 1 else: py1 += diff - max(py1,py2,py3) + ySize ppy = py2

Now we draw the circles and lines to create the bird. The first set creates the wing on the right while the second set creates the wing on the left.

#Draw pygame.draw.line(screen, [0,0,0], (px1,int(py1)), (px3,py3),1) pygame.draw.line(screen, [0,0,0], (px3,py3), (px2,py2),1) pygame.draw.circle(screen, [0,0,255], (px3,py3), 4) pygame.draw.circle(screen, [255,0,0], (px2,py2), 4)

pygame.draw.line(screen, [0,0,0], (2*ox-px1,int(py1)), (2*ox-px3,py3),1) pygame.draw.line(screen, [0,0,0], (2*ox-px3,py3), (2*ox-px2,py2),1) pygame.draw.circle(screen, [0,0,255], (2*ox-px3,py3), 4) pygame.draw.circle(screen, [255,0,0], (2*ox-px1,int(py1)), 4) pygame.draw.circle(screen, [255,0,0], (2*ox-px2,py2), 4)

pygame.display.flip() clock.tick(60)

pygame.quit()

That is all of the physics required. The next part in the series will involve programming the movement and evolution of the birds. Here is the whole code:

import pygame import time import math from math import radians, sin, cos import random from random import randint as ri

pygame.init()

xSize, ySize = 600, 600 screen = pygame.display.set_mode((xSize, ySize)) pygame.display.set_caption("Learn to Fly")

def get_end(length,angle,px0,py0): py = length*cos(radians(angle)) + py0 px = length*sin(radians(angle)) + px0 return int(px),int(py)

length = 100 ox, oy = 300,ySize-200 px1, py1 = ox, oy px2, py2 = 500,200 px3, py3 = 0,0

#----------------------Main Loop----------------------# clock = pygame.time.Clock() frameCount = 0 mouseHold = False done = False #t = 1.333 #t2 = -170 while not done: frameCount += 1 screen.fill([255,255,255])

t1 = -150 t2 = 90 px3,py3 = get_end(length,t1,px1,py1) px2,py2 = get_end(length,180-t2+t1,px3,py3)

if frameCount > 1: diff = (py2 - ppy)*(px2 - px1)/200 if py1 < ySize and py2 < ySize and py3 < ySize: py1 += diff + 1 else: py1 += diff - max(py1,py2,py3) + ySize ppy = py2

#Draw pygame.draw.line(screen, [0,0,0], (px1,int(py1)), (px3,py3),1) pygame.draw.line(screen, [0,0,0], (px3,py3), (px2,py2),1) pygame.draw.circle(screen, [0,0,255], (px3,py3), 4) pygame.draw.circle(screen, [255,0,0], (px2,py2), 4)

pygame.draw.line(screen, [0,0,0], (2*ox-px1,int(py1)), (2*ox-px3,py3),1) pygame.draw.line(screen, [0,0,0], (2*ox-px3,py3), (2*ox-px2,py2),1) pygame.draw.circle(screen, [0,0,255], (2*ox-px3,py3), 4) pygame.draw.circle(screen, [255,0,0], (2*ox-px1,int(py1)), 4) pygame.draw.circle(screen, [255,0,0], (2*ox-px2,py2), 4)

pygame.display.flip() clock.tick(60)

pygame.quit()