-
Notifications
You must be signed in to change notification settings - Fork 0
/
main.py
207 lines (142 loc) · 5.48 KB
/
main.py
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
202
203
204
205
206
207
#! python3
import time
from resources.cars import sideBoundaries, car, Player
import pygame
import pygame.mask
import random
# neat
import neat
import numpy as np
import os
# Initialize Pygame
pygame.init()
# Set up the display
SCREENWIDTH, SCREENHEIGHT = 500, 800
screen = pygame.display.set_mode((SCREENWIDTH, SCREENHEIGHT))
pygame.display.set_caption("Distance Sensor Demo")
background = pygame.image.load('./resources/road.png')
background = pygame.transform.scale(background, (600, 1000))
# Color definition
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
RED = (255, 0, 0)
GREEN = (0, 255, 0)
carWidth = 30
carHeight = 50
font = pygame.font.Font(None, 24)
def generate_wave(Ycoordinate = -40):
'''
returns a list containing 4 car objects the are on the same height and different Xs
the car objects are spaced out with a minimal space distance
'''
randomNum = random.randint(0,60)
waves = [20, 100, 180, 260, 340, 420, 500]
car_wave = []
for i in range(len(waves)): waves[i] += randomNum
for x_car_coordinate in waves:
car_ = car(x_car_coordinate, Ycoordinate)
car_wave.append(car_)
return car_wave
def obstacleUpdate(obstacles):
'''
removes obstacles that are out of view
'''
if(obstacles.sprites()[0].rect.y > 1050):
for i in obstacles.sprites()[:6]: i.kill()
return
def mainLoop(genomes, config):
maxDistances = [281, 331, 409, 409, 331, 281]
obstaclesAndBoundaries = pygame.sprite.Group()
cars = pygame.sprite.Group()
clock = pygame.time.Clock()
alive = []
nets = []
ge = []
running = True
progress = 0
main_rect_x = SCREENWIDTH // 1.95
main_rect_y = SCREENHEIGHT - 50
rightBoundary = sideBoundaries(height = 200, width =4, x = 502, y = 700)
leftBoundary = sideBoundaries(height = 200, width =4, x = -2, y = 700)
ObstacleList = pygame.sprite.Group()
ObstacleList.add(generate_wave(160))
ObstacleList.add(generate_wave(340))
ObstacleList.add(generate_wave(520))
for id, genome in genomes:
genome.fitness = 0 # start with fitness level of 0
net = neat.nn.FeedForwardNetwork.create(genome, config)
nets.append(net)
cars.add(Player(main_rect_x, main_rect_y))
ge.append(genome)
alive.append(True)
time.sleep(15)
# Game loop
while running:
screen.blit(background, (-50,0))
for event in pygame.event.get():
if event.type == pygame.QUIT: running = False
# generate new wave of obstacles
if ObstacleList.sprites()[-1].rect.y > 160: ObstacleList.add(generate_wave())
# move obstacle cars down
for obstacle in ObstacleList: obstacle.move_down()
progress += 0.001
ObstacleList.draw(screen)
obstaclesAndBoundaries.add(rightBoundary)
obstaclesAndBoundaries.add(leftBoundary)
obstaclesAndBoundaries.add(ObstacleList)
running = False
for x, car in enumerate(cars):
ge[x].fitness = progress
car.sensorData = car.get_collision(obstaclesAndBoundaries, screen)
values = list(car.sensorData)
# values normalization
for i, v in enumerate(values): values[i] = v/maxDistances[i]
# move car based on genome output
output = nets[x].activate(values)
movement = np.argmax(output)
if movement == 0: car.move_left()
elif movement == 2: car.move_right()
for obstacle in obstaclesAndBoundaries.sprites():
running = True
if car.rect.colliderect(obstacle.rect): alive[x] = False
# # single player mode
# car.sensorData = car.get_collision(obstaclesAndBoundaries.sprites(), screen)
# if event.type == pygame.KEYDOWN:
# if event.key == pygame.K_LEFT: car.move_left()
# if event.key == pygame.K_RIGHT: car.move_right()
# remove crashed cars
for x in reversed(range(0, len(alive))):
if not alive[x]:
del alive[x]
cars.sprites()[x].kill()
del ge[x]
del nets[x]
cars.draw(screen)
txt = "distance = %.3f alive = %.0f" %(progress, len(alive))
text_ = font.render(txt, True, WHITE)
screen.blit(text_, (10, 60))
obstacleUpdate(ObstacleList)
# Update the display
pygame.display.flip()
clock.tick(60)
return
def run_neat(config_file):
# Load configuration.
config = neat.config.Config(neat.DefaultGenome, neat.DefaultReproduction, neat.DefaultSpeciesSet, neat.DefaultStagnation, config_file)
# Create the population, which is the top-level object for a NEAT run.
p = neat.Population(config)
p = neat.Checkpointer.restore_checkpoint('./resources/neat-checkpoint-370')
# Add a stdout reporter to show progress in the terminal.
p.add_reporter(neat.StdOutReporter(True))
stats = neat.StatisticsReporter()
p.add_reporter(stats)
p.add_reporter(neat.Checkpointer(10))
winner = p.run(mainLoop, 100000)
# Display the winning genome.
print('\nBest genome:\n{!s}'.format(winner))
winner_net = neat.nn.FeedForwardNetwork.create(winner, config)
if __name__ == '__main__':
local_dir = os.path.dirname(__file__)
config_path = os.path.join(local_dir, './resources/config.txt')
run_neat(config_path)
pygame.quit()