예제 #1
0
class RunExperiment(SceneBase):
    """ Scene that shows the progress of an experiment with some summary stats
    """
    def __init__(self, experiment):
        SceneBase.__init__(self)
        # data to keep track of the experiment's progress
        self.experiment = experiment
        self.experiment_running = False
        self.total = experiment.iterations

        # constants defining where stuff can be drawn
        self.MARGIN = 96
        self.TITLE_SIZE = 56
        self.LABEL_SIZE = 48
        self.INFO_BOX = pygame.Rect(self.MARGIN, self.MARGIN * 1.5,
                                    1920 - self.MARGIN * 2,
                                    1080 * 0.66 - 2 * self.MARGIN)
        self.PROGRESS_BAR_WIDTH = 1920 - 2 * self.MARGIN
        self.PROGRESS_BAR_HEIGHT = 100
        self.PROGRESS_BAR_X = self.MARGIN
        self.PROGRESS_BAR_Y = self.INFO_BOX.y + self.INFO_BOX.height + 0.5 * self.PROGRESS_BAR_HEIGHT
        self.PROGRESS_BORDER = pygame.Rect(self.PROGRESS_BAR_X,
                                           self.PROGRESS_BAR_Y,
                                           self.PROGRESS_BAR_WIDTH,
                                           self.PROGRESS_BAR_HEIGHT)
        self.PROGRESS_BG = pygame.Rect(self.PROGRESS_BAR_X + 4,
                                       self.PROGRESS_BAR_Y + 4,
                                       self.PROGRESS_BAR_WIDTH - 8,
                                       self.PROGRESS_BAR_HEIGHT - 8)
        self.title_font = FontService.get_regular_font(self.TITLE_SIZE)
        self.label_font = FontService.get_regular_font(self.LABEL_SIZE)
        font_color = Settings.theme['font']

        self.heading_surface = self.title_font.render(
            "%s   vs   %s" %
            (self.experiment.p1.name, self.experiment.p2.name), False,
            font_color)
        self.heading_size = self.title_font.size(
            "%s   vs   %s" %
            (self.experiment.p1.name, self.experiment.p2.name))
        self.heading_location = (self.INFO_BOX.centerx -
                                 0.5 * self.heading_size[0],
                                 self.INFO_BOX.top -
                                 1.5 * self.heading_size[1])

        self.insertion_msg_surface = self.label_font.render(
            "Saving results...  (This may take some time)", False, font_color)
        self.insertion_msg_size = self.title_font.size(
            "Saving results...  (This may take some time)")
        self.insertion_msg_location = (self.INFO_BOX.centerx -
                                       0.5 * self.insertion_msg_size[0],
                                       self.PROGRESS_BG.bottom + 12)

        # "Done" button
        def back_to_mm():
            SceneManager.go_to_main_menu(self)

        self.done_btn = Button(1920 * 0.5 - 150, self.PROGRESS_BG.bottom + 24,
                               300, 100, "Done", back_to_mm)

        # unset SQLite objects from the main thread
        DB.close()

        # kick off the experiment in a separate thread
        def run_experiment():
            # Initialize SQLite objects in this thread
            DB.init()
            self.experiment.run()
            DB.close()

        experiment_thread = threading.Thread(target=run_experiment)
        experiment_thread.start()

        def run_experiment():
            # Initialize SQLite objects in this thread
            DB.init()
            self.experiment.run()
            DB.close()

            experiment_thread = threading.Thread(target=run_experiment)
            experiment_thread.start()

    def process_input(self, events, pressed_keys):
        for widget in self.widgets:
            widget.process_input(events, pressed_keys)

        if self.experiment.finished:
            self.done_btn.process_input(events, pressed_keys)

    def update(self):
        pass

    def render(self, screen):
        bg = ImageService.get_game_bg()
        screen.blit(bg, (0, 0))

        aa_border_rounded_rect(screen,
                               self.INFO_BOX,
                               Settings.theme['widget_background'],
                               Settings.theme['widget_highlight'],
                               radius=0.1)
        screen.blit(self.heading_surface, self.heading_location)

        # draw progress bar
        progress = self.experiment.completed_iterations / self.experiment.iterations
        pygame.draw.rect(screen, Settings.theme['widget_highlight'],
                         self.PROGRESS_BORDER)
        pygame.draw.rect(screen, Settings.theme['widget_background'],
                         self.PROGRESS_BG)
        progress_bar = self.PROGRESS_BG.copy()
        progress_bar.width = floor(self.PROGRESS_BG.width * progress)
        pygame.draw.rect(screen, Settings.theme['primary'], progress_bar)

        # draw labels for num wins/losses
        num_wins_surface = self.label_font.render(
            "Wins for X :   %s Games" % self.experiment.p1_wins, False,
            Settings.theme['font'])
        num_wins_size = self.label_font.size("X has won :   %s Games" %
                                             self.experiment.p1_wins)
        num_wins_location = (self.INFO_BOX.x + 48,
                             self.INFO_BOX.y + self.INFO_BOX.height * 0.25 -
                             num_wins_size[1] * 0.5)
        screen.blit(num_wins_surface, num_wins_location)

        num_ties_surface = self.label_font.render(
            "Number of Ties :   %s Games" % self.experiment.ties, False,
            Settings.theme['font'])
        num_ties_size = self.label_font.size("Number of Ties :   %s Games" %
                                             self.experiment.ties)
        num_ties_location = (self.INFO_BOX.x + 48,
                             self.INFO_BOX.y + self.INFO_BOX.height * 0.50 -
                             num_ties_size[1] * 0.5)
        screen.blit(num_ties_surface, num_ties_location)

        num_losses_surface = self.label_font.render(
            "Wins for O :   %s Games" % self.experiment.p2_wins, False,
            Settings.theme['font'])
        num_losses_size = self.label_font.size("Wins for O :   %s Games" %
                                               self.experiment.p2_wins)
        num_losses_location = (self.INFO_BOX.x + 48,
                               self.INFO_BOX.y + self.INFO_BOX.height * 0.75 -
                               num_losses_size[1] * 0.5)
        screen.blit(num_losses_surface, num_losses_location)

        # draw labels for win/tie/loss rates
        win_rate = round(self.experiment.get_p1_win_rate() * 100)
        loss_rate = round(self.experiment.get_p2_win_rate() * 100)
        tie_rate = round(self.experiment.get_tie_rate() * 100)
        num_wins_surface = self.label_font.render(
            "X Win Percentage :   %s %%" % win_rate, False,
            Settings.theme['font'])
        num_wins_size = self.label_font.size("X Win Percentage: %s %%" %
                                             win_rate)
        num_wins_location = (self.INFO_BOX.centerx + 48,
                             self.INFO_BOX.y + self.INFO_BOX.height * 0.25 -
                             num_wins_size[1] * 0.5)
        screen.blit(num_wins_surface, num_wins_location)

        num_ties_surface = self.label_font.render(
            "Tied Percentage :   %s %%" % tie_rate, False,
            Settings.theme['font'])
        num_ties_size = self.label_font.size("Tied Percentage: %s %%" %
                                             tie_rate)
        num_ties_location = (self.INFO_BOX.centerx + 48,
                             self.INFO_BOX.y + self.INFO_BOX.height * 0.50 -
                             num_ties_size[1] * 0.5)
        screen.blit(num_ties_surface, num_ties_location)

        num_losses_surface = self.label_font.render(
            "X Loss Percentage :   %s %%" % loss_rate, False,
            Settings.theme['font'])
        num_losses_size = self.label_font.size("X Loss Percentage: %s %%" %
                                               loss_rate)
        num_losses_location = (self.INFO_BOX.centerx + 48,
                               self.INFO_BOX.y + self.INFO_BOX.height * 0.75 -
                               num_losses_size[1] * 0.5)
        screen.blit(num_losses_surface, num_losses_location)

        progress_text = "%s %%" % round(progress * 100)
        progress_text_surface = self.label_font.render(progress_text, False,
                                                       Settings.theme['font'])
        progress_text_size = self.label_font.size(progress_text)
        progress_text_location = (progress_bar.centerx -
                                  0.5 * progress_text_size[0],
                                  progress_bar.centery -
                                  0.5 * progress_text_size[1])
        screen.blit(progress_text_surface, progress_text_location)

        if self.experiment.completed_iterations == self.experiment.iterations and not self.experiment.finished:
            screen.blit(self.insertion_msg_surface,
                        self.insertion_msg_location)

        if self.experiment.finished:
            self.done_btn.render(screen)

        for widget in self.widgets:
            widget.render(screen)
예제 #2
0
class SettingsScreen(Screen):
    def __init__(self, render_surface, surface_size):
        Screen.__init__(self, render_surface, surface_size)

        self.checkboxes = {
            "randomize_kana": {
                "checkbox": Checkbox(
                    self.render_surface,
                    (600, 450, 720, 100),
                    "Randomize Kana",
                ).set_themed(),
                "setting": "randomize_kana",
            },
        }

        self.kana_widgets = {
            "hiragana": {
                "checkbox": Checkbox(
                    self.render_surface,
                    (200, 600, 700, 100),
                    "Learn Hiragana",
                ).set_themed(),
                "button": Button(
                    self.render_surface,
                    (1000, 600, 700, 100),
                    "Select which kana",
                ).set_themed(),
                "setting": "learn_hiragana",
            },
            "katakana": {
                "checkbox": Checkbox(
                    self.render_surface,
                    (200, 750, 700, 100),
                    "Learn Katakana",
                ).set_themed(),
                "button": Button(
                    self.render_surface,
                    (1000, 750, 700, 100),
                    "Select which kana",
                ).set_themed(),
                "setting": "learn_katakana",
            },
            "kanji": {
                "checkbox": Checkbox(
                    self.render_surface,
                    (200, 900, 700, 100),
                    "Learn Kanji",
                ).set_themed(),
                "button": Button(
                    self.render_surface,
                    (1000, 900, 700, 100),
                    "Kanji options",
                ).set_themed(),
                "setting": "learn_kanji",
            },
        }

        # set the 'selected' property of the checkboxes and kana_widgets
        for checkbox_widget_id, checkbox_widget in self.checkboxes.items():
            checkbox = checkbox_widget["checkbox"]
            checkbox.selected = Settings.get(checkbox_widget["setting"])
        for kana_widget_id, kana_widget in self.kana_widgets.items():
            checkbox = kana_widget["checkbox"]
            checkbox.selected = Settings.get(kana_widget["setting"])

        theme = Settings.get("theme")
        themes = Settings.get("themes")
        self.widgets = {
            "heading_settings": Heading(
                self.render_surface, (0, 0, 1920, 100), "Settings"
            ).set_themed(),
            "button_menu": Button(
                self.render_surface, (10, 10, 230, 80), "Menu"
            ).set_themed(),
            "theme_text": Text(
                self.render_surface,
                (500, 150, 920, 100),
                f"Current theme: '{theme}'",
            ).set_themed(),
        }

        # get the theme index of the current theme
        if theme in themes:
            self.theme_index = list(themes.keys()).index(theme)
        else:
            # somehow the theme in the settings file isn't available, reset
            print(f"theme {theme} is invalid! resetting to default")
            self.theme_index = 0
            Settings.set("theme", next(iter(themes)))
            Collections.reapply_theme()

        # theme related widgets
        theme_name = list(themes.keys())[self.theme_index]
        apply_theme_text = f"Apply theme: {theme_name}"
        self.theme_left = Button(
            self.render_surface, (300, 275, 100, 100), "<"
        ).set_themed()
        self.theme_apply = Button(
            self.render_surface, (500, 275, 920, 100), apply_theme_text
        ).set_themed()
        self.theme_right = Button(
            self.render_surface, (1520, 275, 100, 100), ">"
        ).set_themed()

    def update(self, delta_time):
        Screen.update(self, delta_time)

    def key_press(self, event):
        Screen.key_press(self, event)

    def mouse_event(self, event):
        Screen.mouse_event(self, event)
        if event.type == pygame.MOUSEBUTTONUP:
            if self.widgets["button_menu"].rect_hit(event.pos):
                return {"screen_id": "menuscreen"}

            for kana_widget_id, kana_widget in self.kana_widgets.items():
                checkbox = kana_widget["checkbox"]
                # check whether the kana checkboxes are hit
                checkbox.on_mouse_release(event.pos)
                if checkbox.rect_hit(event.pos):
                    # checkbox is hit, save the new setting
                    Settings.set(kana_widget["setting"], checkbox.selected)
                # check whether the buttons are hit
                if kana_widget["button"].rect_hit(event.pos):
                    return {"screen_id": f"optionsfor{kana_widget_id}"}

            for checkbox_widget_id, checkbox_widget in self.checkboxes.items():
                checkbox = checkbox_widget["checkbox"]
                checkbox.on_mouse_release(event.pos)
                if checkbox.rect_hit(event.pos):
                    # checkbox is hit, save the new setting
                    Settings.set(checkbox_widget["setting"], checkbox.selected)

            # theme switcher related buttons
            if self.theme_left.rect_hit(event.pos):
                self.update_theme_index(-1)

            if self.theme_right.rect_hit(event.pos):
                self.update_theme_index(1)

            if self.theme_apply.rect_hit(event.pos):
                # get the theme from the index and save the new theme
                theme = list(Settings.get("themes").keys())[self.theme_index]
                Settings.set("theme", theme)
                # update the text on the current theme widget
                self.widgets["theme_text"].set_text(
                    f"Current theme: '{theme}'"
                )
                # reapply the (new) theme to the GUI
                Collections.reapply_theme()

    def draw(self):
        Screen.draw(self)
        for widget_id, widget in self.widgets.items():
            widget.render()

        for kana_widget_id, kana_widget in self.kana_widgets.items():
            kana_widget["checkbox"].render()
            if kana_widget["checkbox"].selected:
                kana_widget["button"].render()

        for checkbox_widget_id, checkbox_widget in self.checkboxes.items():
            checkbox_widget["checkbox"].render()

        self.theme_left.render()
        self.theme_apply.render()
        self.theme_right.render()

    def update_theme_index(self, change):
        themes = Settings.get("themes")
        last_theme_index = len(themes) - 1
        # update and bounds check the theme index
        index = self.theme_index + change
        index = last_theme_index if index < 0 else index
        index = 0 if index > last_theme_index else index
        # update the class' theme index and the text
        self.theme_index = index
        apply_theme_text = f"Apply theme: {list(themes.keys())[index]}"
        self.theme_apply.set_text(apply_theme_text)