Ai Code + Ss
Ai Code + Ss
Ai Code + Ss
import random
import os
import time
import neat
import visualize
import pickle
pygame.font.init() # init font
WIN_WIDTH = 600
WIN_HEIGHT = 800
FLOOR = 730
STAT_FONT = pygame.font.SysFont("comicsans", 50)
END_FONT = pygame.font.SysFont("comicsans", 70)
DRAW_LINES = False
pipe_img = pygame.transform.scale2x(pygame.image.load(os.path.join("imgs","pipe.png")).convert_alpha())
bg_img = pygame.transform.scale(pygame.image.load(os.path.join("imgs","bg.png")).convert_alpha(), (600, 900))
bird_images = [pygame.transform.scale2x(pygame.image.load(os.path.join("imgs","bird" + str(x) + ".png"))) for x in
range(1,4)]
base_img = pygame.transform.scale2x(pygame.image.load(os.path.join("imgs","base.png")).convert_alpha())
gen = 0
class Bird:
"""
Bird class representing the flappy bird
"""
MAX_ROTATION = 25
IMGS = bird_images
ROT_VEL = 20
ANIMATION_TIME = 5
def jump(self):
"""
make the bird jump
:return: None
"""
self.vel = -10.5
self.tick_count = 0
self.height = self.y
def move(self):
"""
make the bird move
:return: None
"""
self.tick_count += 1
# terminal velocity
if displacement >= 16:
displacement = (displacement/abs(displacement)) * 16
if displacement < 0:
displacement -= 2
def get_mask(self):
"""
gets the mask for the current image of the bird
:return: None
"""
return pygame.mask.from_surface(self.img)
class Pipe():
"""
represents a pipe object
"""
GAP = 200
VEL = 5
self.passed = False
self.set_height()
def set_height(self):
"""
set the height of the pipe, from the top of the screen
:return: None
"""
self.height = random.randrange(50, 450)
self.top = self.height - self.PIPE_TOP.get_height()
self.bottom = self.height + self.GAP
def move(self):
"""
move pipe based on vel
:return: None
"""
self.x -= self.VEL
if b_point or t_point:
return True
return False
class Base:
"""
Represnts the moving floor of the game
"""
VEL = 5
WIDTH = base_img.get_width()
IMG = base_img
def move(self):
"""
move floor so it looks like its scrolling
:return: None
"""
self.x1 -= self.VEL
self.x2 -= self.VEL
if self.x1 + self.WIDTH < 0:
self.x1 = self.x2 + self.WIDTH
surf.blit(rotated_image, new_rect.topleft)
base.draw(win)
for bird in birds:
# draw lines from bird to pipe
if DRAW_LINES:
try:
pygame.draw.line(win, (255,0,0), (bird.x+bird.img.get_width()/2, bird.y + bird.img.get_height()/2),
(pipes[pipe_ind].x + pipes[pipe_ind].PIPE_TOP.get_width()/2, pipes[pipe_ind].height), 5)
pygame.draw.line(win, (255,0,0), (bird.x+bird.img.get_width()/2, bird.y + bird.img.get_height()/2),
(pipes[pipe_ind].x + pipes[pipe_ind].PIPE_BOTTOM.get_width()/2, pipes[pipe_ind].bottom), 5)
except:
pass
# draw bird
bird.draw(win)
# score
score_label = STAT_FONT.render("Score: " + str(score),1,(255,255,255))
win.blit(score_label, (WIN_WIDTH - score_label.get_width() - 15, 10))
# generations
score_label = STAT_FONT.render("Gens: " + str(gen-1),1,(255,255,255))
win.blit(score_label, (10, 10))
# alive
score_label = STAT_FONT.render("Alive: " + str(len(birds)),1,(255,255,255))
win.blit(score_label, (10, 50))
pygame.display.update()
base = Base(FLOOR)
pipes = [Pipe(700)]
score = 0
clock = pygame.time.Clock()
run = True
while run and len(birds) > 0:
clock.tick(30)
pipe_ind = 0
if len(birds) > 0:
if len(pipes) > 1 and birds[0].x > pipes[0].x + pipes[0].PIPE_TOP.get_width(): # determine whether to use the
first or second
pipe_ind = 1 # pipe on the screen for neural network input
for x, bird in enumerate(birds): # give each bird a fitness of 0.1 for each frame it stays alive
ge[x].fitness += 0.1
bird.move()
# send bird location, top pipe location and bottom pipe location and determine from network whether to jump
or not
output = nets[birds.index(bird)].activate((bird.y, abs(bird.y - pipes[pipe_ind].height), abs(bird.y -
pipes[pipe_ind].bottom)))
if output[0] > 0.5: # we use a tanh activation function so result will be between -1 and 1. if over 0.5 jump
bird.jump()
base.move()
rem = []
add_pipe = False
for pipe in pipes:
pipe.move()
# check for collision
for bird in birds:
if pipe.collide(bird, win):
ge[birds.index(bird)].fitness -= 1
nets.pop(birds.index(bird))
ge.pop(birds.index(bird))
birds.pop(birds.index(bird))
if add_pipe:
score += 1
# can add this line to give more reward for passing through a pipe (not required)
for genome in ge:
genome.fitness += 5
pipes.append(Pipe(WIN_WIDTH))
for r in rem:
pipes.remove(r)
def run(config_file):
"""
runs the NEAT algorithm to train a neural network to play flappy bird.
:param config_file: location of config file
:return: None
"""
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)
# 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(5))
if _name_ == '_main_':
# Determine path to configuration file. This path manipulation is
# here so that the script will run successfully regardless of the
# current working directory.
local_dir = os.path.dirname(_file_)
config_path = os.path.join(local_dir, 'config-feedforward.txt')
run(config_path)