- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
- 132
- 133
- 134
- 135
- 136
- 137
- 138
- 139
- 140
- 141
- 142
- 143
- 144
- 145
- 146
- 147
- 148
- 149
- 150
- 151
- 152
- 153
- 154
- 155
- 156
- 157
- 158
- 159
- 160
- 161
- 162
- 163
- 164
- 165
- 166
- 167
- 168
- 169
- 170
- 171
- 172
- 173
- 174
- 175
- 176
- 177
- 178
- 179
- 180
- 181
- 182
- 183
- 184
- 185
- 186
- 187
- 188
- 189
- 190
- 191
- 192
- 193
- 194
- 195
- 196
- 197
- 198
- 199
- 200
- 201
import pygame
import os
import math
import sys
import random
import neat
screen_width = 1500
screen_height = 800
generation = 0
class Car:
def __init__(self):
self.surface = pygame.image.load("car.png")
self.surface = pygame.transform.scale(self.surface, (100, 100))
self.rotate_surface = self.surface
self.pos = [700, 650]
self.angle = 0
self.speed = 0
self.center = [self.pos[0] + 50, self.pos[1] + 50]
self.radars = []
self.radars_for_draw = []
self.is_alive = True
self.goal = False
self.distance = 0
self.time_spent = 0
def draw(self, screen):
screen.blit(self.rotate_surface, self.pos)
self.draw_radar(screen)
def draw_radar(self, screen):
for r in self.radars:
pos, dist = r
pygame.draw.line(screen, (0, 255, 0), self.center, pos, 1)
pygame.draw.circle(screen, (0, 255, 0), pos, 5)
def check_collision(self, map):
self.is_alive = True
for p in self.four_points:
if map.get_at((int(p[0]), int(p[1]))) == (255, 255, 255, 255):
self.is_alive = False
break
def check_radar(self, degree, map):
len = 0
x = int(self.center[0] + math.cos(math.radians(360 - (self.angle + degree))) * len)
y = int(self.center[1] + math.sin(math.radians(360 - (self.angle + degree))) * len)
while not map.get_at((x, y)) == (255, 255, 255, 255) and len < 300:
len = len + 1
x = int(self.center[0] + math.cos(math.radians(360 - (self.angle + degree))) * len)
y = int(self.center[1] + math.sin(math.radians(360 - (self.angle + degree))) * len)
dist = int(math.sqrt(math.pow(x - self.center[0], 2) + math.pow(y - self.center[1], 2)))
self.radars.append([(x, y), dist])
def update(self, map):
#check speed
self.speed = 15
#check position
self.rotate_surface = self.rot_center(self.surface, self.angle)
self.pos[0] += math.cos(math.radians(360 - self.angle)) * self.speed
if self.pos[0] < 20:
self.pos[0] = 20
elif self.pos[0] > screen_width - 120:
self.pos[0] = screen_width - 120
self.distance += self.speed
self.time_spent += 1
self.pos[1] += math.sin(math.radians(360 - self.angle)) * self.speed
if self.pos[1] < 20:
self.pos[1] = 20
elif self.pos[1] > screen_height - 120:
self.pos[1] = screen_height - 120
# caculate 4 collision points
self.center = [int(self.pos[0]) + 50, int(self.pos[1]) + 50]
len = 40
left_top = [self.center[0] + math.cos(math.radians(360 - (self.angle + 30))) * len, self.center[1] + math.sin(math.radians(360 - (self.angle + 30))) * len]
right_top = [self.center[0] + math.cos(math.radians(360 - (self.angle + 150))) * len, self.center[1] + math.sin(math.radians(360 - (self.angle + 150))) * len]
left_bottom = [self.center[0] + math.cos(math.radians(360 - (self.angle + 210))) * len, self.center[1] + math.sin(math.radians(360 - (self.angle + 210))) * len]
right_bottom = [self.center[0] + math.cos(math.radians(360 - (self.angle + 330))) * len, self.center[1] + math.sin(math.radians(360 - (self.angle + 330))) * len]
self.four_points = [left_top, right_top, left_bottom, right_bottom]
self.check_collision(map)
self.radars.clear()
for d in range(-90, 120, 45):
self.check_radar(d, map)
def get_data(self):
radars = self.radars
ret = [0, 0, 0, 0, 0]
for i, r in enumerate(radars):
ret[i] = int(r[1] / 30)
return ret
def get_alive(self):
return self.is_alive
def get_reward(self):
return self.distance / 50.0
def rot_center(self, image, angle):
orig_rect = image.get_rect()
rot_image = pygame.transform.rotate(image, angle)
rot_rect = orig_rect.copy()
rot_rect.center = rot_image.get_rect().center
rot_image = rot_image.subsurface(rot_rect).copy()
return rot_image
def run_car(genomes, config):
# Init NEAT
nets = []
cars = []
for id, g in genomes:
net = neat.nn.FeedForwardNetwork.create(g, config)
nets.append(net)
g.fitness = 0
# Init my cars
cars.append(Car())
# Init my game
pygame.init()
screen = pygame.display.set_mode((screen_width, screen_height))
clock = pygame.time.Clock()
generation_font = pygame.font.SysFont("Arial", 70)
font = pygame.font.SysFont("Arial", 30)
map = pygame.image.load('map.png')
# Main loop
global generation
generation += 1
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit(0)
# Input my data and get result from network
for index, car in enumerate(cars):
output = nets[index].activate(car.get_data())
i = output.index(max(output))
if i == 0:
car.angle += 10
else:
car.angle -= 10
# Update car and fitness
remain_cars = 0
for i, car in enumerate(cars):
if car.get_alive():
remain_cars += 1
car.update(map)
genomes[i][1].fitness += car.get_reward()
# check
if remain_cars == 0:
break
# Drawing
screen.blit(map, (0, 0))
for car in cars:
if car.get_alive():
car.draw(screen)
text = generation_font.render("Generation : " + str(generation), True, (255, 255, 0))
text_rect = text.get_rect()
text_rect.center = (screen_width/2, 100)
screen.blit(text, text_rect)
text = font.render("remain cars : " + str(remain_cars), True, (0, 0, 0))
text_rect = text.get_rect()
text_rect.center = (screen_width/2, 200)
screen.blit(text, text_rect)
pygame.display.flip()
clock.tick(0)
if __name__ == "__main__":
# Set configuration file
config_path = "./config-feedforward.txt"
config = neat.config.Config(neat.DefaultGenome, neat.DefaultReproduction,
neat.DefaultSpeciesSet, neat.DefaultStagnation, config_path)
# Create core evolution algorithm class
p = neat.Population(config)
# Add reporter for fancy statistical result
p.add_reporter(neat.StdOutReporter(True))
stats = neat.StatisticsReporter()
p.add_reporter(stats)
# Run NEAT
p.run(run_car, 1000)