diff --git a/brain.py b/brain.py index 5cddd03..4b98296 100644 --- a/brain.py +++ b/brain.py @@ -14,9 +14,14 @@ class Neural_Network(object): self.fitness = 0 #weights - if not W1 : + if W1 is not None: + self.W1=W1 + else : self.W1 = np.random.randn(self.inputSize, self.hiddenSize) # weights from input to hidden layer - if not W2 : + + if W2 is not None: + self.W2=W2 + else : self.W2 = np.random.randn(self.hiddenSize, self.outputSize) # weights from hidden to output layer # self.w1 = [[random.random() for i in range(self.hiddenSize)] for i in range(self.inputSize)] # self.w2 = [[random.random() for i in range(self.outputSize)] for i in range(self.hiddenSize)] diff --git a/car.py b/car.py index 684a51c..68b2079 100644 --- a/car.py +++ b/car.py @@ -1,4 +1,5 @@ import numpy as np +import random import pygame from brain import Neural_Network @@ -9,7 +10,7 @@ IMG = pygame.image.load("car20.png")#.convert() class Car(pygame.sprite.Sprite): - def __init__(self): + def __init__(self, brain=None): pygame.sprite.Sprite.__init__(self) self.top_surface = pygame.Surface((CAR_SIZE, CAR_SIZE)) self.original_image = IMG @@ -21,9 +22,6 @@ class Car(pygame.sprite.Sprite): self.rect = self.image.get_rect() self.rect.center = (75, GY -50) - self.speed = 1 - self.heading = 0 - self.heading_change = 0 self.vision_length = VISION_LENGTH # line liength self.vision_span = VISION_SPAN # degrees self.draw_sensors = True @@ -41,12 +39,20 @@ class Car(pygame.sprite.Sprite): self.sensors = [self.left_sensor, self.center_sensor, self.right_sensor] self.probes = [self.vision_length] *3 - self.brain = Neural_Network() - + if brain : + self.brain = brain + else : + self.brain = Neural_Network() + + self.reset_car_pos() self.update_sensors() self.probe_brain() self.run = True + def reset_car_pos(self): + self.speed = 1 + self.heading = 0 + self.heading_change = random.random() * 30 def update_sensors(self): center = self.rect.center @@ -83,7 +89,8 @@ class Car(pygame.sprite.Sprite): if dist < 1.2 * self.speed or self.speed < 0.01 : self.run = False self.speed = 0 - print(f'Car {id(self)} crashed') + # print(f'Car {id(self)} crashed') + return # else : # self.probes[idx] = self.vision_length * 2 @@ -106,13 +113,13 @@ class Car(pygame.sprite.Sprite): if self.speed < 0.01 : self.run = False print(f'Car {id(self)} crashed') - print( - 'id', id(self), - 'Speed', self.speed, - 'heading', self.heading, - 'throttle', self.throttle, - 'heading change', self.heading_change, - ) + # print( + # 'id', id(self), + # 'Speed', self.speed, + # 'heading', self.heading, + # 'throttle', self.throttle, + # 'heading change', self.heading_change, + # ) if self.speed : self.heading += self.heading_change * CAR_STEERING_FACTOR / self.speed diff --git a/genetics.py b/genetics.py index 90b29c5..6fde45b 100644 --- a/genetics.py +++ b/genetics.py @@ -10,7 +10,7 @@ def genetic_selection(brains): # proportionnally to its relative fitness wheel = [] for b in brains : - wheel += [b] * b.brains + wheel += [b] * b.fitness tot_fitness = len(wheel) @@ -19,7 +19,11 @@ def genetic_selection(brains): # selection of pool/2 pair of parents to reproduce parents_pool = [] for _ in range(half_pop): - parents_pool.append([round(random.random()*tot_fitness), round(random.random()*tot_fitness)]) + parents_pool.append([ + wheel[round(random.random()*tot_fitness)], + wheel[round(random.random()*tot_fitness)] + ]) + return parents_pool def cross_mutate_genes(p1_gene, p2_gene): @@ -28,15 +32,15 @@ def cross_mutate_genes(p1_gene, p2_gene): p2_gene = list(p1_gene) for idx,x in enumerate(p2_gene): if random.random() > 0.5 : - choice = p1_gene + choice = p1_gene[idx] else : - choice = p2_gene + choice = p2_gene[idx] # Mutation if random.random() < 0.005 : - choice[random.randint(0, len(choice - 1))] = random.random() + choice[random.randint(0, len(choice) - 1)] = random.random() print("Mutation !") - child.append(np.array(choice)) - return child + child.append(choice) + return np.array(child) def genetic_reproduction(parents_pool): diff --git a/main.py b/main.py index 7ffd982..7c65fa7 100755 --- a/main.py +++ b/main.py @@ -2,13 +2,17 @@ import math import pygame import random +import time from car import Car +from genetics import genetic_selection, genetic_reproduction from maps import map1 from params import CELL_COLOR, screen + #https://medium.com/intel-student-ambassadors/demystifying-genetic-algorithms-to-enhance-neural-networks-cde902384b6e +clock = pygame.time.Clock() map_lines = map1 @@ -19,33 +23,52 @@ all_cars = pygame.sprite.Group() for x in range(100): car = Car() - car.heading = x * 30 + 35 all_cars.add(car) -clock = pygame.time.Clock() -running_cars = True -while running_cars : - running_cars = False - screen.fill(CELL_COLOR) - all_cars.draw(screen) - for c in all_cars : - c.show_features() - if c.run : - running_cars = True - c.probe_lines_proximity(map_lines) - c.probe_brain() - c.update() - for line in map_lines : - pygame.draw.line(screen, (255,255,255), line[0], line[1]) +def run_round(all_cars): + running_cars = True + while running_cars : + running_cars = False + screen.fill(CELL_COLOR) + all_cars.draw(screen) + for c in all_cars : + c.show_features() + if c.run : + running_cars = True + c.probe_lines_proximity(map_lines) + c.probe_brain() + c.update() + for line in map_lines : + pygame.draw.line(screen, (255,255,255), line[0], line[1]) - pygame.display.flip() - clock.tick(24) + pygame.display.flip() + clock.tick(48) + + # for c in all_cars : + # print(f"Car {id(c)} Fitness : {c.brain.fitness})") + + print('Collecting brains') + brains = [c.brain for c in all_cars] + print(f"Max fitness = {max([b.fitness for b in brains])}" ) + print(f"Avg fitness = {sum([b.fitness for b in brains])/len(brains)}" ) + print('selecting') + parents_pool = genetic_selection(brains) + # import ipdb; ipdb.set_trace() + print("breeding") + new_brains = genetic_reproduction(parents_pool) + print(f'building {len(new_brains)} cars with new brains') + all_cars.empty() + for b in new_brains : + all_cars.add(Car(brain=b)) + print("Waiting 5 secs before new run") + for x in range(10) : + time.sleep(0.5) + pygame.display.flip() -for c in all_cars : - print(f"Car {id(c)} Fitness : {c.brain.fitness})") while True : + run_round(all_cars) pygame.display.flip() clock.tick(24) diff --git a/params.py b/params.py index 371d197..e977ae4 100644 --- a/params.py +++ b/params.py @@ -10,7 +10,7 @@ CAR_SIZE = 20 CAR_MAX_SPEED = 7 CAR_STEERING_FACTOR = 10 VISION_LENGTH = 50 -VISION_SPAN = 25 # degrees +VISION_SPAN = 35 # degrees THROTTLE_POWER = 3