Example #1
0
class Game:
    def __init__(self,
                 obstacle_pos=None,
                 auto_mode=False,
                 screen_width=640,
                 screen_height=400):
        self._done = False
        self.auto_mode = auto_mode
        self.SCREEN_WIDTH = screen_width
        self.SCREEN_HEIGHT = screen_height

        # init pygame
        pygame.init()
        pygame.display.set_caption("Game")
        self.screen = pygame.display.set_mode(
            (self.SCREEN_WIDTH, self.SCREEN_HEIGHT))

        self.FRAME_RATE = 60
        self.clock = pygame.time.Clock()

        pygame.font.init()
        self.default_font = pygame.font.SysFont(pygame.font.get_default_font(),
                                                23)
        self.info_font = self.default_font

        self.enable_display = True

        # position for displaying history chart
        self.CHART_POS = (30, 220)

        # field and player objects for each game
        self.obstacle_pos = obstacle_pos
        self.field = None
        self.info = None
        self.history_chart = None

        self.setup_game()

    def _draw_field(self):
        shapes = self.field.get_shapes()
        for shape in shapes:
            self._draw_shape(shape)

    def _draw_info_panel(self):
        x, y = 30, 30
        font_height = self.default_font.get_height()

        # By default, display scores only
        score = self.field.get_score()
        text = self.info_font.render("Score: {:.1f}".format(score), True,
                                     colors.WHITE)
        self.screen.blit(text, (x, y))

        # display information
        if self.info:
            for key, val in self.info:
                y += font_height
                info_text = self.info_font.render("{}: {}".format(key, val),
                                                  True, colors.WHITE)
                self.screen.blit(info_text, (x, y))

    def _draw_history_panel(self):
        if self.history_chart:
            shapes = self.history_chart.get_shapes()
            for shape in shapes:
                self._draw_shape(shape)

    def _draw_shape(self, shape):
        if isinstance(shape, Line):
            pygame.draw.aaline(self.screen, shape.color, shape.start_pos,
                               shape.end_pos, shape.width)
        elif isinstance(shape, Rectangle):
            pygame.draw.rect(self.screen, shape.color,
                             (shape.x, shape.y, shape.width, shape.height))
        elif isinstance(shape, Circle):
            pygame.draw.circle(self.screen, shape.color, shape.pos,
                               shape.radius, shape.width)
        elif isinstance(shape, DashLine):
            for line in shape.lines:
                self._draw_shape(line)
        elif isinstance(shape, Text):
            self.screen.blit(shape.text_surface, shape.pos)
        else:
            print "[ERROR] Unknown shape type {}!".format(
                shape.__class__.__name__)

    def setup_game(self):
        self.field = Field(self.SCREEN_WIDTH,
                           self.SCREEN_HEIGHT,
                           obstacle_pos=self.obstacle_pos)

    def is_over(self):
        return self.field.check_is_over()

    def handle_events(self):
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                self._done = True
            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_d:
                    # toggle display
                    self.enable_display = not self.enable_display
                    print "Display Mode: {}".format(self.enable_display)
                if event.key == pygame.K_r and self.is_over():
                    # restart game
                    self.setup_game()

        pressed = pygame.key.get_pressed()
        if pressed[pygame.K_q] or pressed[pygame.K_ESCAPE]:
            # quit game
            self._done = True
        if not self.auto_mode:
            if pressed[pygame.K_SPACE] or pressed[pygame.K_UP]:
                # jump
                self.field.jump()
            if pressed[pygame.K_LEFT]:
                # move left
                self.field.move("left")
            if pressed[pygame.K_RIGHT]:
                # move right
                self.field.move("right")

    def update_screen(self):
        self.screen.fill(colors.BLACK)

        self._draw_field()
        self._draw_info_panel()
        if self.history_chart:
            self._draw_history_panel()

        pygame.display.flip()
        self.clock.tick(self.FRAME_RATE)

    def on_update(self):
        """Things to do when frame get updated"""
        self.field.update()

    def start(self):
        while not self._done:
            self.handle_events()

            if not self.is_over():
                self.update_screen()
                self.on_update()

    def show(self, actions, info=None, history=None):
        self.field = Field(self.SCREEN_WIDTH,
                           self.SCREEN_HEIGHT,
                           obstacle_pos=self.obstacle_pos,
                           player_actions=actions)
        self.info = info

        if history:
            x_values = [float(gen_info['Generation']) for gen_info in history]
            y_values = [
                float(gen_info['Highest Fitness']) for gen_info in history
            ]
            highest_fitness = y_values[-1]
            avg_values = [
                float(gen_info['Average Fitness']) for gen_info in history
            ]
            avg_fitness = avg_values[-1]
            self.history_chart = Chart(caption="Generation History",
                                       width=280,
                                       height=180,
                                       margin=20,
                                       pos=self.CHART_POS,
                                       x_label="Generation",
                                       y_label="Fitness")
            self.history_chart.add_curve(x_values, y_values)
            self.history_chart.add_curve(x_values,
                                         avg_values,
                                         color=colors.BLUE)
            self.history_chart.add_constant(
                highest_fitness,
                label="Highest Fitness {}".format(highest_fitness),
                color=colors.WHITE)
            self.history_chart.add_constant(
                avg_fitness,
                label="Average Fitness {}".format(avg_fitness),
                color=colors.BLUE)

        while not self.is_over():
            self.handle_events()

            if self.enable_display:
                self.update_screen()

            self.on_update()