Repository: Baekalfen/PyBoy
File: pyboy/plugins/game_wrapper_tetris.py (Python)

Code before:
        if self.game_has_started:
            self.fitness = self.score

    def start_game(self, timer_div=None, randomize_div=True):
        """
        Call this function right after initializing PyBoy. This will navigate through menus to start the game at the
        first playable state.

        The state of the emulator is saved, and using `reset_game`, you can get back to this point of the game
        instantly.

        Args:
            timer_div (int): Replace timer's DIV register with this value
            randomize_div (bool): Whether to randomize the DIV register or not
        """
        # Boot screen
        while True:
            self.pyboy.tick()
            self.tilemap_background.refresh_lcdc()
            if self.tilemap_background[2:9, 14] == [89, 25, 21, 10, 34, 14, 27]: # '1PLAYER' on the first screen
                break

        # Start game. Just press Start when the game allows us.
        for i in range(3):
            if i == 2:
                PyBoyGameWrapper._set_timer_div(self, timer_div, randomize_div)
                self.saved_state.seek(0)
                self.pyboy.save_state(self.saved_state)
            self.pyboy.send_input(WindowEvent.PRESS_BUTTON_START)
            self.pyboy.tick()
            self.pyboy.send_input(WindowEvent.RELEASE_BUTTON_START)

            for _ in range(6):
                self.pyboy.tick()

        self.game_has_started = True

    def reset_game(self, timer_div=None, randomize_div=True):
        """
        After calling `start_game`, you can call this method at any time to reset the game.

        Args:
            timer_div (int): Replace timer's DIV register with this value
            randomize_div (bool): Whether to randomize the DIV register or not
        """
        PyBoyGameWrapper.reset_game(self, timer_div=timer_div, randomize_div=randomize_div)

        self.pyboy.send_input(WindowEvent.PRESS_BUTTON_START)
        self.pyboy.tick()
        self.pyboy.send_input(WindowEvent.RELEASE_BUTTON_START)


Review comment (suggestion):
This could be called earlier. For example from `PyBoyGameWrapper.start_game(self, timer_div=timer_div, randomize_div=randomize_div)`, as that's what `reset_game` does.

It just need to be set at some point before `save_state`.

Code after:
        super().__init__(*args, game_area_section=(2, 0) + self.shape, game_area_wrap_around=True, **kwargs)

    def _game_area_tiles(self):
        if self._tile_cache_invalid:
            self._cached_game_area_tiles = np.asarray(self.tilemap_background[2:12, :18], dtype=np.uint32)
            self._tile_cache_invalid = False
        return self._cached_game_area_tiles

    def post_tick(self):
        self._tile_cache_invalid = True
        self._sprite_cache_invalid = True

        blank = 47
        self.tilemap_background.refresh_lcdc()
        self.score = self._sum_number_on_screen(13, 3, 6, blank, 0)
        self.level = self._sum_number_on_screen(14, 7, 4, blank, 0)
        self.lines = self._sum_number_on_screen(14, 10, 4, blank, 0)

        if self.game_has_started:
            self.fitness = self.score

    def start_game(self, timer_div=None):
        """
        Call this function right after initializing PyBoy. This will navigate through menus to start the game at the
        first playable state.

        The state of the emulator is saved, and using `reset_game`, you can get back to this point of the game
        instantly.

        Kwargs:
            timer_div (int): Replace timer's DIV register with this value. Use `None` to randomize.
        """
        # We don't supply the timer_div arg here, as it won't have the desired effect
        PyBoyGameWrapper.start_game(self)

        # Boot screen
        while True:
            self.pyboy.tick()
            self.tilemap_background.refresh_lcdc()
            if self.tilemap_background[2:9, 14] == [89, 25, 21, 10, 34, 14, 27]: # '1PLAYER' on the first screen
                break

        # Start game. Just press Start when the game allows us.
        for i in range(3):
            if i == 2:
                PyBoyGameWrapper._set_timer_div(self, timer_div)
                self.saved_state.seek(0)
                self.pyboy.save_state(self.saved_state)
            self.pyboy.send_input(WindowEvent.PRESS_BUTTON_START)
            self.pyboy.tick()
            self.pyboy.send_input(WindowEvent.RELEASE_BUTTON_START)