def main(): """The application's entry point. If someone executes this module (instead of importing it, for example), this function is called. """ pygame.init() display_surface = pygame.display.set_mode((WIN_WIDTH, WIN_HEIGHT)) pygame.display.set_caption('Pygame Flappy Bird') clock = pygame.time.Clock() score_font = pygame.font.SysFont(None, 32, bold=True) # default font images = load_images() stop = False agent = FlappyLearner() loops = 0 high = -1 scores = [] while not stop: stop, score = game_logic(clock, display_surface, images, score_font, agent=agent) scores.append(score) loops += 1 if len(scores) > 100: del scores[0] r_mean = sum(scores) / float(len(scores)) high = max(high, score) print 'Score:', score, '-----', 'High:', high, '-----', 'Rolling Mean:', r_mean if loops == 100 or stop: print 'Saving...' loops = 0 agent.save() pygame.quit()
def game_logic(clock, display_surface, images, score_font, agent=None): # the bird stays in the same x position, so bird.x is a constant # center bird on screen bird = Bird(50, int(WIN_HEIGHT / 2 - Bird.HEIGHT / 2), 2, (images['bird-wingup'], images['bird-wingdown'])) pipes = deque() frame_clock = 0 # this counter is only incremented if the game isn't paused score = 0 done = paused = False stop_loop = False agent = FlappyLearner() if agent is None else agent loops = 0 bin_width = bird.WIDTH / 2 bin_height = bird.HEIGHT / 2 def get_current_state(): x_delta = int((pipes[0].x - bird.x) / bin_width) y_delta = int((bird.y - pipes[0].bottom_height_px) / bin_height) ascending = bird.msec_to_climb > 0 y_value = int(bird.y / bin_height) return State(x_delta, y_delta, ascending, y_value) old_state = None old_score = 0 while not done: clock.tick(FPS) # Handle this 'manually'. If we used pygame.time.set_timer(), # pipe addition would be messed up when paused. if not (paused or frame_clock % msec_to_frames(PipePair.ADD_INTERVAL)): pp = PipePair(images['pipe-end'], images['pipe-body']) pipes.append(pp) if not old_state: old_state = get_current_state() old_action = True flap = False # should we flap? based on key AND agent's decision action_state = loops == 15 if action_state: loops = 0 current_state = get_current_state() flap = agent.flap(current_state) if score > old_score: reward = 1000.0 # for jumping a pipe old_score = score else: reward = 0.0 # for staying alive without scoring agent.train(old_state, current_state, old_action, reward) old_state = current_state old_action = flap loops += 1 for e in pygame.event.get(): if e.type == QUIT or (e.type == KEYUP and e.key == K_ESCAPE): done = True stop_loop = True break elif e.type == KEYUP and e.key == K_q: stop_loop = True elif e.type == KEYUP and e.key in (K_PAUSE, K_p): paused = not paused elif e.type == MOUSEBUTTONUP or (e.type == KEYUP and e.key in (K_UP, K_RETURN, K_SPACE)): flap = True # bird.msec_to_climb = Bird.CLIMB_DURATION if paused: continue # don't draw anything if flap: bird.msec_to_climb = Bird.CLIMB_DURATION # check for collisions pipe_collision = any(p.collides_with(bird) for p in pipes) if pipe_collision or 0 >= bird.y or bird.y >= WIN_HEIGHT - Bird.HEIGHT: done = True for x in (0, WIN_WIDTH / 2): display_surface.blit(images['background'], (x, 0)) while pipes and not pipes[0].visible: pipes.popleft() for p in pipes: p.update() display_surface.blit(p.image, p.rect) bird.update() display_surface.blit(bird.image, bird.rect) # update and display score for p in pipes: if p.x + PipePair.WIDTH < bird.x and not p.score_counted: score += 1 p.score_counted = True score_surface = score_font.render(str(score), True, (255, 255, 255)) score_x = WIN_WIDTH / 2 - score_surface.get_width() / 2 display_surface.blit(score_surface, (score_x, PipePair.PIECE_HEIGHT)) pygame.display.flip() frame_clock += 1 agent.train(old_state, get_current_state(), old_action, -1000.0) # we lost return stop_loop, score