Advertisement
Szizzle

genetic_stuff.py

Feb 13th, 2020
166
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 11.08 KB | None | 0 0
  1. import pygame
  2. import random
  3. import threading
  4. import math
  5. import time
  6. from pygame import gfxdraw
  7.  
  8. GREY = (54, 57, 63)
  9. RED = (255, 0, 0)
  10. DARK_RED = (165, 42, 42)
  11. GREEN = (124,252,0)
  12. DARK_GREEN = (0,128,0)
  13. BLUE = (0,0,128)
  14. PINK = (211, 54, 130)
  15.  
  16. class Main:
  17.     window_width = 700
  18.     window_height = 700
  19.     running = True
  20.     exit_flag = False
  21.    
  22.     def __init__(self):
  23.         pygame.init()
  24.         self.counter = 0
  25.         self.finished = 0
  26.         self.pop_size = 200
  27.         self.lifespan = 400
  28.         self.fps = 60
  29.         self.window_width = Main.window_width
  30.         self.window_height = Main.window_height
  31.         self.target = (300, 100)
  32.         self.reached_goal = False
  33.         self.clock = pygame.time.Clock()
  34.         self.gen_count = 0
  35.         self.display = pygame.display.set_mode((self.window_width, self.window_height))
  36.         self.font = pygame.font.SysFont('Segoe UI', 20)
  37.         rect_width = 200
  38.         self.obstacle = pygame.Rect((int(self.window_width/2-rect_width/2), int(self.window_height*0.4)) , (rect_width, 50))
  39.         self.rocket_pop = Population()
  40.  
  41.     def constructor(self):
  42.         self.counter = 0
  43.         self.finished = 0
  44.         self.pop_size = 200
  45.         self.lifespan = 400
  46.         self.fps = 60
  47.         self.window_width = Main.window_width
  48.         self.window_height = Main.window_height
  49.         self.target = (300, 100)
  50.         self.reached_goal = False
  51.         self.display = pygame.display.set_mode((self.window_width, self.window_height))
  52.         self.clock = pygame.time.Clock()
  53.         self.gen_count = 0
  54.         self.font = pygame.font.SysFont('Segoe UI', 20)
  55.         rect_width = 200
  56.         self.obstacle = pygame.Rect((int(self.window_width/2-rect_width/2), int(self.window_height*0.4)) , (rect_width, 50))
  57.  
  58.     def draw_text(self):
  59.         gen_count_text = self.font.render("generation: "+str(self.gen_count), True, (255, 255, 255))
  60.         finished_text = self.font.render("reached the goal: "+str(self.finished), True, (255, 255, 255))
  61.         lifespan_text = self.font.render("lifespan: "+str(self.counter+1)+"/"+str(self.lifespan), True, (255, 255, 255))
  62.         self.display.blit(gen_count_text, (50, 50))
  63.         self.display.blit(finished_text, (50, 90))
  64.         self.display.blit(lifespan_text, (50, 130))
  65.  
  66.     def draw_obstacles(self):
  67.         pygame.draw.rect(self.display, (0,0,0), self.obstacle)
  68.  
  69.     @staticmethod
  70.     def pause_simulation():
  71.         if Main.running:
  72.             Main.running = False
  73.         else:
  74.             Main.resume_simulation()
  75.     @staticmethod
  76.     def resume_simulation():
  77.         Main.running = True
  78.     @staticmethod
  79.     def pygame_event_check():
  80.         for event in pygame.event.get():
  81.             if event.type == pygame.QUIT:
  82.                 pygame.quit()
  83.                 quit()
  84.  
  85.     def run(self):
  86.         while not self.exit_flag:
  87.             self.display.fill(GREY)
  88.             self.draw_text()
  89.             self.draw_obstacles()
  90.            
  91.             self.pygame_event_check()
  92.  
  93.             if self.running:
  94.                 if self.counter >= self.lifespan:
  95.                     self.counter = 0
  96.                     new_generation, finished = self.rocket_pop.selection()
  97.                     self.rocket_pop = Population(new_generation)
  98.                     time.sleep(1)
  99.                     self.gen_count += 1
  100.                    
  101.                     if finished > 0 and self.reached_goal == False:
  102.                         print(f"Reached the goal in {self.gen_count} generations")
  103.                         self.reached_goal = True
  104.                    
  105.  
  106.                 for rocket in self.rocket_pop.population:
  107.                     rocket.update(self.counter)
  108.  
  109.                 self.counter += 1
  110.  
  111.                 self.clock.tick(self.fps)
  112.                 pygame.draw.circle(self.display, PINK, self.target, 20)
  113.                 pygame.display.update()
  114.  
  115.         while not self.exit_flag:
  116.             self.pygame_event_check()
  117.         print("exit")
  118. class DNA():
  119.     def __init__(self, lifespan, max_vel, genes=[]):
  120.         self.max_vel = max_vel
  121.         self.mutation_chance = 0.05
  122.  
  123.         if genes == []:
  124.             self.genes = [(random.uniform(-self.max_vel, self.max_vel), random.uniform(-self.max_vel, self.max_vel)) for i in range(lifespan)]
  125.         else:
  126.             self.genes = genes
  127.  
  128.     def crossover(self, partner):
  129.         new_genes = []
  130.         mid = random.randint(1, len(self.genes))
  131.         for i in range(len(self.genes)):
  132.             if i < mid:
  133.                 new_genes.append(self.genes[i])
  134.             else:
  135.                 new_genes.append(partner.dna.genes[i])
  136.         return new_genes
  137.  
  138.     def mutate(self):
  139.         for gene in self.genes:
  140.             chance_to_mutate = random.random()
  141.             if chance_to_mutate < self.mutation_chance:
  142.                 gene = (random.uniform(-self.max_vel, self.max_vel), random.uniform(-self.max_vel, self.max_vel))
  143.  
  144. class Rocket(Main):
  145.     def __init__(self, starting_pos, genes=[]):
  146.         Main.constructor(self)
  147.         self.path = []
  148.         self.position = starting_pos
  149.         self.starting_pos = starting_pos
  150.         self.arrow_size = 5
  151.         Rocket.max_vel = 0.2
  152.         self.acceleration = (0,0)
  153.         self.velocity = (0,0)
  154.         self.crashed = False
  155.         self.finished = False
  156.         self.dna = DNA(self.lifespan, self.max_vel, genes)
  157.  
  158.     def update(self, counter):
  159.         #self.acceleration = self.normalise(self.dna.genes[counter])*max_vel
  160.         if not self.crashed and not self.finished:
  161.             self.acceleration = self.dna.genes[counter]
  162.             self.velocity = (self.velocity[0]+self.acceleration[0], self.velocity[1]+self.acceleration[1])
  163.             self.position = (self.velocity[0]+self.position[0], self.velocity[1]+self.position[1])
  164.             self.acceleration *= 0
  165.         self.check_pos()
  166.         self.draw(counter)
  167.  
  168.     def draw(self, counter):
  169.         arrow_x = self.normalise(self.velocity)[0]*self.arrow_size
  170.         arrow_y = self.normalise(self.velocity)[1]*self.arrow_size
  171.        
  172.         pygame.gfxdraw.aatrigon(self.display,int(self.position[0]+arrow_x*self.arrow_size), int(self.position[1]+arrow_y*self.arrow_size),
  173.                                         int(self.position[0]-arrow_y*self.arrow_size/3), int(self.position[1]+arrow_x*self.arrow_size/3),
  174.                                         int(self.position[0]+arrow_y*self.arrow_size/3), int(self.position[1]-arrow_x*self.arrow_size/3),
  175.                                         (GREEN))
  176.         #if counter % 10 == 0:
  177.         #    self.path.append((int(self.position[0]), int(self.position[1])))
  178.         #for marker in self.path:
  179.             #pygame.draw.circle(display, GREEN, marker, 2)
  180.        
  181.         distance = self.get_distance(self.starting_pos, self.position)
  182.        
  183.         #if distance > 710:
  184.         #    index = 710
  185.         #else:
  186.         #    index = int(distance)
  187.         #marker = {"colour": colour, "pos":(int(self.position[0]), int(self.position[1]))}
  188.         #colour = hex_to_rgb(rb_gradient[index].hex)
  189.         #noise_val = math.sqrt(n.world[int(self.position[0])][int(self.position[1])]**2)
  190.  
  191.     def check_pos(self):
  192.         arrow_x = self.normalise(self.velocity)[0]*self.arrow_size
  193.         arrow_y = self.normalise(self.velocity)[1]*self.arrow_size
  194.         d = self.get_distance(self.position, self.target)
  195.  
  196.         if self.position[0]+arrow_x*self.arrow_size > self.window_width:
  197.             self.crashed = True
  198.         elif self.position[0]+arrow_x*self.arrow_size < 0:
  199.             self.crashed = True
  200.         elif self.position[1]+arrow_y*self.arrow_size > self.window_height:
  201.             self.crashed = True
  202.         elif self.position[1]+arrow_y*self.arrow_size < 0:
  203.             self.crashed = True
  204.         if self.obstacle.collidepoint((self.position[0]+arrow_x*self.arrow_size, self.position[1]+arrow_y*self.arrow_size)):
  205.             self.crashed = True
  206.         if d < 20:
  207.             self.finished = True
  208.  
  209.     @staticmethod
  210.     def normalise(vector):
  211.         magnitude = math.sqrt(vector[0]**2+vector[1]**2)
  212.         if magnitude != 0:
  213.             return (vector[0]/magnitude, vector[1]/magnitude)
  214.         return (0,0)
  215.     @staticmethod
  216.     def get_distance(coord1, coord2):
  217.         return math.sqrt(((coord2[1]-coord1[1])**2)+((coord2[0]-coord1[0])**2))
  218.     @staticmethod
  219.     def round_to_1(x):
  220.        return round(x, -int(math.floor(math.log10(abs(x)))))
  221.  
  222. class Population(Main):
  223.     def __init__(self, population=[]):
  224.         Main.constructor(self)
  225.         self.finished = 0
  226.         self.starting_pos = (int(self.window_width/2), self.window_height)
  227.         self.calulate_min_mates()
  228.  
  229.         if population == []:
  230.             self.population = [Rocket(self.starting_pos) for i in range(self.pop_size)]
  231.         else:
  232.             self.population = population
  233.            
  234.  
  235.     def selection(self):
  236.         max_fitness = 0
  237.         total_fitness = 0
  238.         list_of_fitnesses = []
  239.         new_population = []
  240.         mating_pool = []
  241.         mates = []
  242.         d_target = Rocket.get_distance(self.starting_pos, self.target)
  243.  
  244.         for rocket in self.population:
  245.             d = Rocket.get_distance(rocket.position, self.target)
  246.             rocket.fitness = 100/d
  247.             if rocket.crashed:
  248.                 rocket.fitness *= 0.5
  249.             if rocket.finished:
  250.                 self.finished += 1
  251.                 rocket.fitness *= 2
  252.             list_of_fitnesses.append(rocket.fitness)
  253.  
  254.         while len(mating_pool) < self.min_mates-1:
  255.             mate = random.choices(self.population, list_of_fitnesses, k=1)
  256.             self.diversity_update(mate[0])
  257.             mating_pool.append(mate[0])
  258.  
  259.         while len(new_population) < self.pop_size:
  260.             for rocket in mating_pool:
  261.                 if len(new_population) > self.pop_size:
  262.                     break
  263.                 mate = random.choice(mating_pool)
  264.                 if (rocket, mate) not in mates:
  265.                     child_dna = rocket.dna.crossover(mate)
  266.                     child_dna = DNA(self.lifespan, Rocket.max_vel, child_dna)
  267.                     child_dna.mutate()
  268.                     new_population.append(Rocket(self.starting_pos, child_dna.genes))
  269.                     mates.append((rocket, mate))
  270.         return new_population, self.finished
  271.  
  272.     def diversity_update(self, mate):
  273.         max_distance = 0
  274.         mate_with_max = mate
  275.         for rocket in self.population:
  276.             if rocket is mate:
  277.                 continue
  278.             d = Rocket.get_distance(rocket.position, mate.position)
  279.             if d > max_distance:
  280.                 max_distance = d
  281.                 mate_with_max = rocket
  282.         mate_with_max.fitness *= 2
  283.  
  284.     def calulate_min_mates(self):
  285.         self.min_mates = 2
  286.         no_children = 1
  287.         while no_children < self.pop_size:
  288.             no_children = int(math.factorial(self.min_mates)/(2*(math.factorial(self.min_mates-2))))
  289.             self.min_mates += 1
  290.  
  291.  
  292.  
  293. def run():
  294.     main = Main()
  295.     mThread = threading.Thread(target=main.run)
  296.     threads.append(mThread)
  297.     mThread.start()
  298.     mThread.join()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement