Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import pygame
- import random
- import sys
- import math
- import neat
- width = 1300
- height = 1100
- bg = (213,193,154,255)
- generation = 0
- class Car:
- # list of available cars, take random everytime
- car_sprites = ("Audi", "Black_viper", "Orange", "Police", "Taxi")
- def __init__(self):
- self.random_sprite()
- self.angle = 0
- self.speed = 5
- self.radars = []
- self.collision_points = []
- self.is_alive = True
- self.goal = False
- self.distance = 0
- self.time_spent = 0
- def random_sprite(self):
- self.car_sprite = pygame.image.load('sprites/' + random.choice(self.car_sprites) + '.png')
- self.car_sprite = pygame.transform.scale(self.car_sprite,
- (math.floor(self.car_sprite.get_size()[0]/2), math.floor(self.car_sprite.get_size()[1]/2)))
- self.car = self.car_sprite
- # recompute
- self.pos = [650, 930]
- self.compute_center()
- def compute_center(self):
- self.center = (self.pos[0] + (self.car.get_size()[0]/2), self.pos[1] + (self.car.get_size()[1] / 2))
- def draw(self, screen):
- screen.blit(self.car, self.pos)
- self.draw_radars(screen)
- def draw_center(self, screen):
- pygame.draw.circle(screen, (0,72,186), (math.floor(self.center[0]), math.floor(self.center[1])), 5)
- def draw_radars(self, screen):
- for r in self.radars:
- p, d = r
- pygame.draw.line(screen, (183,235,70), self.center, p, 1)
- pygame.draw.circle(screen, (183,235,70), p, 5)
- def compute_radars(self, degree, road):
- length = 0
- x = int(self.center[0] + math.cos(math.radians(360 - (self.angle + degree))) * length)
- y = int(self.center[1] + math.sin(math.radians(360 - (self.angle + degree))) * length)
- while not road.get_at((x, y)) == bg and length < 300:
- length = length + 1
- x = int(self.center[0] + math.cos(math.radians(360 - (self.angle + degree))) * length)
- y = int(self.center[1] + math.sin(math.radians(360 - (self.angle + degree))) * length)
- 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 compute_collision_points(self):
- self.compute_center()
- lw = 65
- lh = 65
- lt = [self.center[0] + math.cos(math.radians(360 - (self.angle + 20))) * lw, self.center[1] + math.sin(math.radians(360 - (self.angle + 20))) * lh]
- rt = [self.center[0] + math.cos(math.radians(360 - (self.angle + 160))) * lw, self.center[1] + math.sin(math.radians(360 - (self.angle + 160))) * lh]
- lb = [self.center[0] + math.cos(math.radians(360 - (self.angle + 200))) * lw, self.center[1] + math.sin(math.radians(360 - (self.angle + 200))) * lh]
- rb = [self.center[0] + math.cos(math.radians(360 - (self.angle + 340))) * lw, self.center[1] + math.sin(math.radians(360 - (self.angle + 340))) * lh]
- self.collision_points = [lt, rt, lb, rb]
- def draw_collision_points(self, road, screen):
- if not self.collision_points:
- self.compute_collision_points()
- for p in self.collision_points:
- if(road.get_at((int(p[0]), int(p[1]))) == bg):
- pygame.draw.circle(screen, (255,0,0), (int(p[0]), int(p[1])), 5)
- else:
- pygame.draw.circle(screen, (15,192,252), (int(p[0]), int(p[1])), 5)
- def check_collision(self, road):
- self.is_alive = True
- for p in self.collision_points:
- try:
- if road.get_at((int(p[0]), int(p[1]))) == bg:
- self.is_alive = False
- break
- except IndexError:
- self.is_alive = False
- def rotate(self, angle):
- orig_rect = self.car_sprite.get_rect()
- rot_image = pygame.transform.rotate(self.car_sprite, angle)
- rot_rect = orig_rect.copy()
- rot_rect.center = rot_image.get_rect().center
- rot_image = rot_image.subsurface(rot_rect).copy()
- self.car = rot_image
- def get_data(self):
- radars = self.radars
- data = [0, 0, 0, 0, 0]
- for i, r in enumerate(radars):
- data[i] = int(r[1] / 30)
- return data
- def get_reward(self):
- return self.distance / 50.0
- def update(self, road):
- # set some fixed speed
- self.speed = 5
- # rotate
- self.rotate(self.angle)
- # move
- 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] > width - 120:
- self.pos[0] = width - 120
- 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] > height - 120:
- self.pos[1] = height - 120
- # update distance & time spent
- self.distance += self.speed
- self.time_spent += 1 # aka turns
- # compute/check collision points & create radars
- self.compute_collision_points()
- self.check_collision(road)
- self.radars.clear()
- for d in range(-90, 120, 45):
- self.compute_radars(d, road)
- start = False
- def run_generation(genomes, config):
- nets = []
- cars = []
- # init genomes
- for i, g in genomes:
- net = neat.nn.FeedForwardNetwork.create(g, config)
- nets.append(net)
- g.fitness = 0 # every genome is not successful at the start
- # init cars
- cars.append(Car())
- # init the game
- pygame.init()
- screen = pygame.display.set_mode((width, height))
- clock = pygame.time.Clock()
- road = pygame.image.load('sprites/road.png')
- font = pygame.font.SysFont("Roboto", 40)
- heading_font = pygame.font.SysFont("Roboto", 80)
- # the LOOP
- global generation
- global start
- generation += 1
- while True:
- for event in pygame.event.get():
- if event.type == pygame.QUIT:
- sys.exit(0)
- elif event.type == pygame.KEYDOWN:
- if event.key == pygame.K_SPACE:
- start = True
- if not start:
- continue
- # input each car data
- for i, car in enumerate(cars):
- output = nets[i].activate(car.get_data())
- i = output.index(max(output))
- if i == 0:
- car.angle += 5
- elif i == 1:
- car.angle = car.angle
- elif i == 2:
- car.angle -= 5
- # now, update car and set fitness (for alive cars only)
- cars_left = 0
- for i, car in enumerate(cars):
- if car.is_alive:
- cars_left += 1
- car.update(road)
- genomes[i][1].fitness += car.get_reward() # new fitness (aka car instance success)
- # check if cars left
- if not cars_left:
- break
- # display stuff
- screen.blit(road, (0, 0))
- for car in cars:
- if car.is_alive:
- car.draw(screen)
- # car.draw_center(screen)
- # car.draw_collision_points(road, screen)
- label = heading_font.render("Поколение: " + str(generation), True, (73,168,70))
- label_rect = label.get_rect()
- label_rect.center = (width / 1.5, 300)
- screen.blit(label, label_rect)
- label = font.render("Машин осталось: " + str(cars_left), True, (51,59,70))
- label_rect = label.get_rect()
- label_rect.center = (width / 1.5, 375)
- screen.blit(label, label_rect)
- pygame.display.flip()
- clock.tick(30)
- if __name__ == "__main__":
- # setup config
- config_path = "./config-feedforward.txt"
- config = neat.config.Config(neat.DefaultGenome, neat.DefaultReproduction, neat.DefaultSpeciesSet, neat.DefaultStagnation, config_path)
- # init NEAT
- p = neat.Population(config)
- # run NEAT
- p.run(run_generation, 1000)
Advertisement
Add Comment
Please, Sign In to add comment