def get_fitness(dna): # reset position e.solids[1].pos = [x, y] g = gene_functions.Gaps2(x, y) # set velocity based on input functions and weights from DNA for i in range(2): e.solids[1].velocity[i] = g.input0()[i] * dna[0] + \ g.input3()[i] * dna[1] + \ g.input4()[i] * dna[2] initial_velocity = e.solids[1].velocity # run the physics engine until either the termination condition is reached (termination function has to be put into the physics_engine.py runtime = pe.run_physics_engine(tick_length, e, time_limit) # if the simulation exceeds the time limit before the termination condition is reached, or way too quickly, the organism's fitness will be virtually 0 if runtime >= time_limit or runtime <= tick_length * 10: return .00001 # can't be 0 bc that would cause division by 0 later on # fitness function, tries to minimize velocity while maximizing time spent before crashing back down to planet, uses normalized quantities velocity_magnitude = pe.distance(initial_velocity, [0, 0]) norm_runtime = (runtime - tick_length * 10) / (time_limit - tick_length * 10) norm_velocity = velocity_magnitude / 5 return (norm_runtime - norm_velocity) ** 2
def get_fitness(dna): # create unique object of gene function class for each iteration g = gene_functions.Gatd1() # set velocity based on input functions and weights from DNA for i in range(2): e.solids[0].velocity[i] = g.input0()[i] * dna[0] + \ g.input1()[i] * dna[1] end_pos = pe.run_physics_engine(tick_length, e, time_limit) return 1 / (pe.distance([0, 0], end_pos)**.5)
def get_fitness(organism): # reset position, set velocity to what its DNA dictates e.solids[1].pos = [0, 11.001] e.solids[1].velocity = [0] + organism.dna # run the physics engine until either the termination condition is reached (termination function has to be put into the physics_engine.py runtime = pe.run_physics_engine(tick_length, e, time_limit) # if the simulation exceeds the time limit before the termination condition is reached, or way too quickly, the organism's fitness will be virtually 0 if runtime >= time_limit or runtime <= tick_length * 10: return .001 # fitness function, tries to minimize velocity while maximizing time spent before crashing back down to planet, uses normalized quantities velocity_magnitude = pe.distance([0] + organism.dna, [0, 0]) norm_runtime = runtime / time_limit norm_velocity = velocity_magnitude / 5 return (norm_runtime - norm_velocity)**2
def get_fitness(dna, destination): # create unique object of gene function class for each iteration g = gene_functions.Gasv1(e.g_strength[1], destination) # make sure to reset pos before starting again!!!!!!!!!! e.solids[0].pos = [-100, .001] # set velocity based on input functions and weights from DNA for i in range(2): e.solids[0].velocity[i] = g.input0()[i] * dna[0] + \ g.input1()[i] * dna[1] + \ g.input2()[i] * dna[2] + \ g.input3()[i] * dna[3] if abs(e.solids[0].velocity[i]) >= 100: return 10 ** -10 end_pos = pe.run_physics_engine(tick_length, e, time_limit) return 1 / (pe.distance(destination, end_pos) ** 2)
velocity[j] = g.input0()[j] * dna[0] # g.input1()[j] * dna[1] + \ # g.input4()[j] * dna[2] print(velocity) # print('velocity', velocity) e = environments.Environment(solids=[pe.Circle(static=True), pe.Circle(radius=1, pos=i, velocity=velocity)], g_type='nonuniform', g_strength=10) # run the physics engine until either the termination condition is reached (termination function has to be put into the physics_engine.py runtime = pe.run_physics_engine(.2, e, 100) # print('runtime', runtime) # if the simulation exceeds the time limit before the termination condition is reached, or way too quickly, the organism's fitness will be virtually 0 if runtime >= 100 or runtime <= .2 * 10: print('fitness', 0) else: # fitness function, tries to minimize velocity while maximizing time spent before crashing back down to planet, uses normalized quantities velocity_magnitude = pe.distance(velocity, [0, 0]) norm_runtime = (runtime - .2 * 10) / (100 - .2 * 10) norm_velocity = velocity_magnitude / 5 print('fitness', (norm_runtime - norm_velocity) ** 2) print()
import physics_engine as pe from environments import Environment import gene_functions g = gene_functions.Gatd1() velocity = [0, 0] dna = [1.0493179215779653, 0.26432598219944303] for j in range(2): velocity[j] = g.input0()[j] * dna[0] + \ g.input1()[j] * dna[1] e = Environment(solids=[pe.Circle(pos=[-100, -100], velocity=velocity), pe.Rect(static=True, pos=[-155, 0], height=300), pe.Rect(static=True, pos=[155, 0], height=300), pe.Rect(static=True, pos=[0, -155], width=300), pe.Rect(static=True, pos=[0, 155], width=300)], g_type='downward', g_strength=.2) print(e.solids[0].velocity) # run the physics engine until the termination condition is reached (termination function has to be put into the physics_engine.py and return statement corrected) # time_limit is set to be virtually infinite because we are not worried about this environment running indefinitely, the ball will always eventually slow down to stop end_pos = pe.run_physics_engine(.2, e, 10 ** 10) print('fitness', 1 / pe.distance([0, 0], end_pos))
import gene_functions from environments import Environment import physics_engine as pe dna = [-0.4782179829546539, 0.07012079426483595, 2.7799442290567735, 0.4543957971535216] destination = [100, 100] g = gene_functions.Gasv1(-9.81, destination) velocity = [0, 0] for i in range(2): velocity[i] = g.input0()[i] * dna[0] + \ g.input1()[i] * dna[1] + \ g.input2()[i] * dna[2] + \ g.input3()[i] * dna[3] print('velocity', velocity) e = Environment(solids=[pe.Circle(pos=[-100, .001], velocity=velocity)], g_type='uniform', g_strength=[0, -9.81]) end_pos = pe.run_physics_engine(.2, e, 10 ** 2) print('end_pos', end_pos) print('dist', pe.distance(end_pos, destination))
if not solid.static: for i in range(2): solid.velocity[i] += e.g_strength[i] * tick_length # update velocities of non-static solids based on nonuniform gravity elif e.g_type == 'nonuniform': if not solid.static: for other in e.solids: # don't let it apply gravity upon itself if solid.pos == other.pos: continue # normalize velocity vector x_diff = other.pos[0] - solid.pos[0] y_diff = other.pos[1] - solid.pos[1] dist = pe.distance(solid.pos, other.pos) norm_dist_v = [x_diff / dist, y_diff / dist] # formula for acceleration derived from Newton's formula for universal gravitation g = (e.g_strength * other.mass) / ((solid.pos[0] - other.pos[0]) ** 2 + (solid.pos[1] - other.pos[1]) ** 2) # use normalized vector, acceleration, and tick length to adjust velocity in either direction for i in range(2): solid.velocity[i] += norm_dist_v[i] * g * tick_length # downward gravity for top-down environments in which moving objects have friction with the background, which in this case is the floor elif e.g_type == 'downward': if not solid.static: lost_v = e.g_strength * solid.mass * tick_length vel_mag = pe.distance([0, 0], solid.velocity)
g.input5()[i] * dna[5] # print('destination', destination) # print('barrier_x', barrier_x) # print('velocity', velocity) if stahp: sys.exit() e = Environment(solids=[ pe.Circle(pos=[-100, -100], velocity=velocity), pe.Rect(static=True, width=100, pos=[barrier_x, 0]), pe.Rect(static=True, pos=[-155, 0], height=300), pe.Rect(static=True, pos=[155, 0], height=300), pe.Rect(static=True, pos=[0, -155], width=300), pe.Rect(static=True, pos=[0, 155], width=300) ], g_type='downward', g_strength=.2) # run the physics engine until the termination condition is reached (termination function has to be put into the physics_engine.py and return statement corrected) # time_limit is set to be virtually infinite because we are not worried about this environment running indefinitely, the ball will always eventually slow down to stop end_pos = pe.run_physics_engine(.1, e, 10**10) total_distance += pe.distance(destination, end_pos) # print('end_pos', end_pos) # print('distance', pe.distance(destination, end_pos)) # print() print(total_distance) print('total_distance', total_distance**.001)
# iterates through all generations for generation in range(gen_count): # print percent progress if (generation * 100) / gen_count % 1 == 0: print((generation * 100) / gen_count) # calculate fitness of each organism for organism in p.organisms: organism.fitness = get_fitness(organism) # do natural selection and mutation p.natural_selection() p.reproduce('unweighted breeding') for organism in p.organisms: organism.mutate(mutate_chance, standard_deviations) for organism in p.organisms: print(organism.dna, pe.distance([0] + organism.dna, [0, 0]), organism.fitness) print('time elapsed:', time() - start_time) # termination function needs to be copied into physics_engine.py above the run_physics_engine() function # it is kept here to save it, because the copy of it in physics_engine.py has to be changed for each distinct algorithm used # def termination(environ, tick_length): # next_pos = [0, environ.solids[1].pos[1] + (environ.solids[1].velocity[1] * tick_length)] # if distance([0, 0], next_pos) <= 11: # return True # return False