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