genetics code (untested)
This commit is contained in:
14
brain.py
14
brain.py
@@ -1,17 +1,25 @@
|
|||||||
import numpy as np
|
import numpy as np
|
||||||
|
import random
|
||||||
|
|
||||||
|
def mat_mult(A,B):
|
||||||
|
return [[sum([A[i][m]*B[m][j] for m in range(len(A[0]))]) for j in range(len(B[0]))] for i in range(len(A))]
|
||||||
|
|
||||||
class Neural_Network(object):
|
class Neural_Network(object):
|
||||||
# inspired from https://enlight.nyc/projects/neural-network/
|
# inspired from https://enlight.nyc/projects/neural-network/
|
||||||
def __init__(self):
|
def __init__(self, W1=None, W2=None):
|
||||||
#parameters
|
#parameters
|
||||||
self.inputSize = 3
|
self.inputSize = 3
|
||||||
self.outputSize = 2
|
self.outputSize = 2
|
||||||
self.hiddenSize = 3
|
self.hiddenSize = 3
|
||||||
|
self.fitness = 0
|
||||||
|
|
||||||
#weights
|
#weights
|
||||||
|
if not W1 :
|
||||||
self.W1 = np.random.randn(self.inputSize, self.hiddenSize) # weights from input to hidden layer
|
self.W1 = np.random.randn(self.inputSize, self.hiddenSize) # weights from input to hidden layer
|
||||||
|
if not W2 :
|
||||||
self.W2 = np.random.randn(self.hiddenSize, self.outputSize) # weights from hidden to output layer
|
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)]
|
||||||
|
|
||||||
def predict(self, X):
|
def predict(self, X):
|
||||||
#forward propagation through our network
|
#forward propagation through our network
|
||||||
@@ -19,6 +27,10 @@ class Neural_Network(object):
|
|||||||
self.z2 = self.sigmoid(self.z) # activation function
|
self.z2 = self.sigmoid(self.z) # activation function
|
||||||
self.z3 = np.dot(self.z2, self.W2) # dot product of hidden layer (z2) and second set of 3x1 weights
|
self.z3 = np.dot(self.z2, self.W2) # dot product of hidden layer (z2) and second set of 3x1 weights
|
||||||
o = self.sigmoid(self.z3) # final activation function
|
o = self.sigmoid(self.z3) # final activation function
|
||||||
|
# self.z = mat_mult(X, self.w1) # dot product of X (input) and first set of 3x2 weights
|
||||||
|
# self.z2 = self.sigmoid(self.z) # activation function
|
||||||
|
# self.z3 = mat_mult(self.z2, self.w2) # dot product of hidden layer (z2) and second set of 3x1 weights
|
||||||
|
# o = self.sigmoid(self.z3) # final activation function
|
||||||
return o
|
return o
|
||||||
|
|
||||||
def sigmoid(self, s):
|
def sigmoid(self, s):
|
||||||
|
|||||||
8
car.py
8
car.py
@@ -2,7 +2,7 @@ import numpy as np
|
|||||||
import pygame
|
import pygame
|
||||||
|
|
||||||
from brain import Neural_Network
|
from brain import Neural_Network
|
||||||
from params import GY, CAR_SIZE, VISION_LENGTH, VISION_SPAN, THROTTLE_POWER, screen
|
from params import GY, CAR_MAX_SPEED, CAR_SIZE, CAR_STEERING_FACTOR, VISION_LENGTH, VISION_SPAN, THROTTLE_POWER, screen
|
||||||
from trigo import angle_to_vector, get_line_feats, segments_intersection, distance
|
from trigo import angle_to_vector, get_line_feats, segments_intersection, distance
|
||||||
|
|
||||||
IMG = pygame.image.load("car20.png")#.convert()
|
IMG = pygame.image.load("car20.png")#.convert()
|
||||||
@@ -65,6 +65,7 @@ class Car(pygame.sprite.Sprite):
|
|||||||
old_center = self.rect.center
|
old_center = self.rect.center
|
||||||
self.rect.center = (self.speed * vec[0] / 2 + old_center[0], -self.speed * vec[1] / 2 + old_center[1])
|
self.rect.center = (self.speed * vec[0] / 2 + old_center[0], -self.speed * vec[1] / 2 + old_center[1])
|
||||||
self.update_sensors()
|
self.update_sensors()
|
||||||
|
self.brain.fitness += int(distance(old_center, self.rect.center))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -81,6 +82,7 @@ class Car(pygame.sprite.Sprite):
|
|||||||
self.probes[idx] = min(dist, self.probes[idx])
|
self.probes[idx] = min(dist, self.probes[idx])
|
||||||
if dist < 1.2 * self.speed or self.speed < 0.01 :
|
if dist < 1.2 * self.speed or self.speed < 0.01 :
|
||||||
self.run = False
|
self.run = False
|
||||||
|
self.speed = 0
|
||||||
print(f'Car {id(self)} crashed')
|
print(f'Car {id(self)} crashed')
|
||||||
|
|
||||||
# else :
|
# else :
|
||||||
@@ -113,7 +115,7 @@ class Car(pygame.sprite.Sprite):
|
|||||||
)
|
)
|
||||||
|
|
||||||
if self.speed :
|
if self.speed :
|
||||||
self.heading += self.heading_change * 10 / self.speed
|
self.heading += self.heading_change * CAR_STEERING_FACTOR / self.speed
|
||||||
self.heading = self.heading % 360
|
self.heading = self.heading % 360
|
||||||
|
|
||||||
self.speed += self.throttle #THROTTLE_POWER
|
self.speed += self.throttle #THROTTLE_POWER
|
||||||
@@ -123,7 +125,7 @@ class Car(pygame.sprite.Sprite):
|
|||||||
# self.speed -= self.throttle #THROTTLE_POWER
|
# self.speed -= self.throttle #THROTTLE_POWER
|
||||||
|
|
||||||
self.speed = max(0, self.speed)
|
self.speed = max(0, self.speed)
|
||||||
self.speed = min(self.speed, 7)
|
self.speed = min(self.speed, CAR_MAX_SPEED)
|
||||||
|
|
||||||
super().update()
|
super().update()
|
||||||
|
|
||||||
|
|||||||
56
genetics.py
Normal file
56
genetics.py
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
import numpy as np
|
||||||
|
import random
|
||||||
|
from brain import Neural_Network
|
||||||
|
|
||||||
|
def genetic_selection(brains):
|
||||||
|
# tot_fitness = sum ([int(b.fitness) for b in brains])
|
||||||
|
|
||||||
|
# does not seem very optimized... TBR
|
||||||
|
# constitute a list where every brain is represented
|
||||||
|
# proportionnally to its relative fitness
|
||||||
|
wheel = []
|
||||||
|
for b in brains :
|
||||||
|
wheel += [b] * b.brains
|
||||||
|
|
||||||
|
|
||||||
|
tot_fitness = len(wheel)
|
||||||
|
half_pop = int(len(brains)/2)
|
||||||
|
|
||||||
|
# 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)])
|
||||||
|
|
||||||
|
|
||||||
|
def cross_mutate_genes(p1_gene, p2_gene):
|
||||||
|
child = []
|
||||||
|
p1_gene = list(p1_gene)
|
||||||
|
p2_gene = list(p1_gene)
|
||||||
|
for idx,x in enumerate(p2_gene):
|
||||||
|
if random.random() > 0.5 :
|
||||||
|
choice = p1_gene
|
||||||
|
else :
|
||||||
|
choice = p2_gene
|
||||||
|
# Mutation
|
||||||
|
if random.random() < 0.005 :
|
||||||
|
choice[random.randint(0, len(choice - 1))] = random.random()
|
||||||
|
print("Mutation !")
|
||||||
|
child.append(np.array(choice))
|
||||||
|
return child
|
||||||
|
|
||||||
|
|
||||||
|
def genetic_reproduction(parents_pool):
|
||||||
|
# every pair of parents will produce a mixed child
|
||||||
|
new_pop = []
|
||||||
|
for [p1,p2] in parents_pool:
|
||||||
|
W1_kid = cross_mutate_genes(p1.W1, p2.W1)
|
||||||
|
W2_kid = cross_mutate_genes(p1.W2, p2.W2)
|
||||||
|
c_brain1 = Neural_Network(W1=W1_kid, W2=W2_kid)
|
||||||
|
c_brain2 = Neural_Network(W1=W1_kid, W2=W2_kid)
|
||||||
|
new_pop.append(c_brain1)
|
||||||
|
new_pop.append(c_brain2)
|
||||||
|
return new_pop
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
3
main.py
3
main.py
@@ -43,6 +43,9 @@ while running_cars :
|
|||||||
pygame.display.flip()
|
pygame.display.flip()
|
||||||
clock.tick(24)
|
clock.tick(24)
|
||||||
|
|
||||||
|
for c in all_cars :
|
||||||
|
print(f"Car {id(c)} Fitness : {c.brain.fitness})")
|
||||||
|
|
||||||
while True :
|
while True :
|
||||||
pygame.display.flip()
|
pygame.display.flip()
|
||||||
clock.tick(24)
|
clock.tick(24)
|
||||||
|
|||||||
@@ -6,11 +6,14 @@ FLAGS = HWSURFACE | DOUBLEBUF #| FULLSCREEN
|
|||||||
GX = 1000
|
GX = 1000
|
||||||
GY = 1000
|
GY = 1000
|
||||||
CELL_COLOR = (80,80,80)
|
CELL_COLOR = (80,80,80)
|
||||||
CAR_SIZE=20
|
CAR_SIZE = 20
|
||||||
|
CAR_MAX_SPEED = 7
|
||||||
|
CAR_STEERING_FACTOR = 10
|
||||||
VISION_LENGTH = 50
|
VISION_LENGTH = 50
|
||||||
VISION_SPAN = 25 # degrees
|
VISION_SPAN = 25 # degrees
|
||||||
THROTTLE_POWER = 3
|
THROTTLE_POWER = 3
|
||||||
|
|
||||||
|
|
||||||
pygame.init()
|
pygame.init()
|
||||||
screen = pygame.display.set_mode((GX, GY), FLAGS)
|
screen = pygame.display.set_mode((GX, GY), FLAGS)
|
||||||
screen.set_alpha(None)
|
screen.set_alpha(None)
|
||||||
|
|||||||
2
trigo.py
2
trigo.py
@@ -17,7 +17,6 @@ def get_line_feats(point1, point2):
|
|||||||
return a,b
|
return a,b
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def segments_intersection(line1, line2):
|
def segments_intersection(line1, line2):
|
||||||
p1,p2 = line1
|
p1,p2 = line1
|
||||||
p3,p4 = line2
|
p3,p4 = line2
|
||||||
@@ -42,6 +41,5 @@ def segments_intersection(line1, line2):
|
|||||||
return None # intersect is outside segments
|
return None # intersect is outside segments
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def distance(point1, point2):
|
def distance(point1, point2):
|
||||||
return math.hypot(point1[0] - point2[0], point1[1] - point2[1])
|
return math.hypot(point1[0] - point2[0], point1[1] - point2[1])
|
||||||
Reference in New Issue
Block a user