Пример #1
0
    async def initialize_first_step() -> Optional[Result]:
        nonlocal gs
        ai._initialize_variables()

        game_data = await client.get_game_data()
        game_info = await client.get_game_info()
        ping_response = await client.ping()

        # This game_data will become self.game_data in botAI
        ai._prepare_start(
            client, player_id, game_info, game_data, realtime=realtime, base_build=ping_response.ping.base_build
        )
        state = await client.observation()
        # check game result every time we get the observation
        if client._game_result:
            await ai.on_end(client._game_result[player_id])
            return client._game_result[player_id]
        gs = GameState(state.observation)
        proto_game_info = await client._execute(game_info=sc_pb.RequestGameInfo())
        try:
            ai._prepare_step(gs, proto_game_info)
            await ai.on_before_start()
            ai._prepare_first_step()
            await ai.on_start()
        # TODO Catching too general exception Exception (broad-except)
        # pylint: disable=W0703
        except Exception:
            logger.exception("AI on_start threw an error")
            logger.error("Resigning due to previous error")
            await ai.on_end(Result.Defeat)
            return Result.Defeat
Пример #2
0
    def __init__(
        self, raw_game_data: Any, raw_game_info: Any, raw_observation: Any
    ) -> None:
        """
        Set up variables for use within Creeper.

        Args:
            raw_game_data (Any): self.game_data from main instance
            raw_game_info (Any): self.game_info from main instance
            raw_observation (Any): self.game_state from main instance

        Returns:
            None
        """
        self.bot = BotAI()
        game_data = GameData(raw_game_data.data)
        game_info = GameInfo(raw_game_info.game_info)
        game_state = GameState(raw_observation)
        self.bot._initialize_variables()
        self.bot._prepare_start(
            client=None, player_id=1, game_info=game_info, game_data=game_data
        )
        self.bot._prepare_step(state=game_state, proto_game_info=raw_game_info)
        self.pathing = PathManager(raw_game_data, raw_game_info, raw_observation)
        self.pf = PathFind(self.pathing.map_grid)
Пример #3
0
def import_bot_instance(
    raw_game_data: Response,
    raw_game_info: Response,
    raw_observation: ResponseObservation,
) -> BotAI:
    """
    import_bot_instance DocString
    """
    bot = BotAI()
    game_data = GameData(raw_game_data.data)
    game_info = GameInfo(raw_game_info.game_info)
    game_state = GameState(raw_observation)
    # noinspection PyProtectedMember
    bot._initialize_variables()
    # noinspection PyProtectedMember
    bot._prepare_start(client=None,
                       player_id=1,
                       game_info=game_info,
                       game_data=game_data)
    # noinspection PyProtectedMember
    bot._prepare_first_step()
    # noinspection PyProtectedMember
    bot._prepare_step(state=game_state, proto_game_info=raw_game_info)
    # noinspection PyProtectedMember
    bot._find_expansion_locations()
    return bot
Пример #4
0
    def __init__(
        self, raw_game_data: Any, raw_game_info: Any, raw_observation: Any
    ) -> None:
        """
        Set up variables for use within PathMangager.

        Args:
            raw_game_data (Any): self.game_data from main instance
            raw_game_info (Any): self.game_info from main instance
            raw_observation (Any): self.game_state from main instance

        Returns:
            None
        """
        self.bot = BotAI()
        game_data = GameData(raw_game_data.data)
        game_info = GameInfo(raw_game_info.game_info)
        game_state = GameState(raw_observation)
        self.bot._initialize_variables()
        self.bot._prepare_start(
            client=None, player_id=1, game_info=game_info, game_data=game_data
        )
        self.bot._prepare_step(state=game_state, proto_game_info=raw_game_info)
        map_name = game_info.map_name
        self.pathing_dict: Dict[int, PathDict] = {}
        map_width = game_info.map_size.width
        map_height = game_info.map_size.height
        raw_grid = np.zeros((map_width, map_height))
        for x in range(map_width):
            for y in range(map_height):
                pos = Point2((x, y))
                raw_grid[x][y] = game_info.pathing_grid[pos]
        self.map_grid = np.rot90(raw_grid.astype(int))
        np.save(f"map_grids/{map_name}_grid", self.map_grid)
        self.pf = PathFind(self.map_grid)
Пример #5
0
    def _ai_preparation(self, bot_ai, player_id, client):
        game_data = self._loop_run(client.get_game_data())
        game_info = self._loop_run(client.get_game_info())
        state = self._loop_run(client.observation())
        game_state = GameState(state.observation, game_data)

        bot_ai._prepare_start(client, player_id, game_info, game_data)
        bot_ai.on_start()
        bot_ai._prepare_step(game_state)
        bot_ai._prepare_first_step()
        return game_data, game_info, game_state
Пример #6
0
 async def _advance_steps(self, steps: int):
     """Advances the game loop by amount of 'steps'. This function is meant to be used as a debugging and testing tool only.
     If you are using this, please be aware of the consequences, e.g. 'self.units' will be filled with completely new data."""
     await self._after_step()
     # Advance simulation by exactly "steps" frames
     await self.client.step(steps)
     state = await self.client.observation()
     gs = GameState(state.observation)
     proto_game_info = await self.client._execute(
         game_info=sc_pb.RequestGameInfo())
     self._prepare_step(gs, proto_game_info)
     await self.issue_events()
Пример #7
0
def get_map_specific_bot(map_path: Path) -> BotAI:
    assert map_path in MAPS
    with lzma.open(str(map_path.absolute()), "rb") as f:
        raw_game_data, raw_game_info, raw_observation = pickle.load(f)

    # Build fresh bot object, and load the pickle'd data into the bot object
    bot = BotAI()
    game_data = GameData(raw_game_data.data)
    game_info = GameInfo(raw_game_info.game_info)
    game_state = GameState(raw_observation)
    bot._initialize_variables()
    bot._prepare_start(client=None, player_id=1, game_info=game_info, game_data=game_data)
    bot._prepare_step(state=game_state, proto_game_info=raw_game_info)

    return bot
    async def store_data_to_file(self, file_path: str):
        # Grab all raw data from observation
        raw_game_data = await self._client._execute(
            data=sc_pb.RequestData(ability_id=True, unit_type_id=True, upgrade_id=True, buff_id=True, effect_id=True)
        )

        raw_game_info = await self._client._execute(game_info=sc_pb.RequestGameInfo())

        raw_observation = self.state.response_observation

        # To test if this data is convertable in the first place
        game_data = GameData(raw_game_data.data)
        game_info = GameInfo(raw_game_info.game_info)
        game_state = GameState(raw_observation)

        os.makedirs(os.path.dirname(file_path), exist_ok=True)
        with lzma.open(file_path, "wb") as f:
            pickle.dump([raw_game_data, raw_game_info, raw_observation], f)
Пример #9
0
def get_map_specific_bots() -> Iterable[BotAI]:
    folder = os.path.dirname(__file__)
    subfolder_name = "pickle_data"
    pickle_folder_path = os.path.join(folder, subfolder_name)
    files = os.listdir(pickle_folder_path)
    for file in (f for f in files if f.endswith(".xz")):
        with lzma.open(os.path.join(folder, subfolder_name, file), "rb") as f:
            raw_game_data, raw_game_info, raw_observation = pickle.load(f)

        # Build fresh bot object, and load the pickle'd data into the bot object
        bot = BotAI()
        game_data = GameData(raw_game_data.data)
        game_info = GameInfo(raw_game_info.game_info)
        game_state = GameState(raw_observation)
        bot._initialize_variables()
        bot._prepare_start(client=None, player_id=1, game_info=game_info, game_data=game_data)
        bot._prepare_step(state=game_state, proto_game_info=raw_game_info)

        yield bot
    async def on_start_async(self):
        raw_game_data = await self._client._execute(
            data=sc_pb.RequestData(ability_id=True, unit_type_id=True, upgrade_id=True, buff_id=True, effect_id=True)
        )

        raw_game_info = await self._client._execute(game_info=sc_pb.RequestGameInfo())

        raw_observation = self.state.response_observation

        # To test if this data is convertable in the first place
        game_data = GameData(raw_game_data.data)
        game_info = GameInfo(raw_game_info.game_info)
        game_state = GameState(raw_observation)

        print(f"Saving file to {self.map_name}.xz")
        file_path = self.get_pickle_file_path()
        os.makedirs(os.path.dirname(file_path), exist_ok=True)
        with lzma.open(file_path, "wb") as f:
            pickle.dump([raw_game_data, raw_game_info, raw_observation], f)

        await self._client.leave()
Пример #11
0
    def _step(self, action_args):
        # if self.env.allies_client._status

        self.t += 1
        allies_game_state = self.allies_game_state

        # current game_state
        self._loop_run(self.allies.ai.issue_events())
        self._loop_run(self.allies.ai.on_step(action_args))
        for _ in range(self.frame_skip_rate):
            self._loop_run(self.allies_client.step())

        allies_state = self._loop_run(self.allies_client.observation())
        next_game_state = GameState(allies_state.observation,
                                    self.allies_game_data)
        self.allies_game_state = next_game_state
        self.allies.ai._prepare_step(allies_game_state)

        game_result = self.allies_client._game_result
        done = True if game_result else False

        return next_game_state, done
Пример #12
0
async def _play_game_ai(client,
                        player_id,
                        ai,
                        realtime,
                        step_time_limit,
                        game_time_limit,
                        log_queue=None):
    if realtime:
        assert step_time_limit is None

    # step_time_limit works like this:
    # * If None, then step time is not limited
    # * If given integer or float, the bot will simpy resign if any step takes longer than that
    # * Otherwise step_time_limit must be an object, with following settings:
    #
    # Key         | Value      | Description
    # ------------|------------|-------------
    # penalty     | None       | No penalty, the bot can continue on next step
    # penalty     | N: int     | Cooldown penalty, BotAI.on_step will not be called for N steps
    # penalty     | "resign"   | Bot resigns when going over time limit
    # time_limit  | int/float  | Time limit for a single step
    # window_size | N: int     | The time limit will be used for last N steps, instad of 1
    #
    # Cooldown is a harsh penalty. The both loses the ability to act, but even worse,
    # the observation data from skipped steps is also lost. It's like falling asleep in
    # a middle of the game.
    time_penalty_cooldown = 0
    if step_time_limit is None:
        time_limit = None
        time_window = None
        time_penalty = None
    elif isinstance(step_time_limit, (int, float)):
        time_limit = float(step_time_limit)
        time_window = SlidingTimeWindow(1)
        time_penalty = "resign"
    else:
        assert isinstance(step_time_limit, dict)
        time_penalty = step_time_limit.get("penalty", None)
        time_window = SlidingTimeWindow(
            int(step_time_limit.get("window_size", 1)))
        time_limit = float(step_time_limit.get("time_limit", None))

    game_data = await client.get_game_data()
    game_info = await client.get_game_info()

    ai._prepare_start(client, player_id, game_info, game_data)
    try:
        ai.on_start()
    except Exception as e:
        logger.exception(f"AI on_start threw an error")
        logger.error(f"resigning due to previous error")
        ai.on_end(Result.Defeat)
        return Result.Defeat

    iteration = 0
    while True:
        state = await client.observation()
        logger.debug(f"Score: {state.observation.observation.score.score}")

        if client._game_result:
            ai.on_end(client._game_result[player_id])
            return client._game_result[player_id]

        gs = GameState(state.observation, game_data)

        if game_time_limit and (gs.game_loop * 0.725 *
                                (1 / 16)) > game_time_limit:
            ai.on_end(Result.Tie)
            return Result.Tie

        ai._prepare_step(gs)

        if iteration == 0:
            ai._prepare_first_step()

        logger.debug(
            f"Running AI step, it={iteration} {gs.game_loop * 0.725 * (1 / 16):.2f}s"
        )

        try:
            await ai.issue_events()
            if realtime:
                await ai.on_step(iteration)
            else:
                if time_penalty_cooldown > 0:
                    time_penalty_cooldown -= 1
                    logger.warning(
                        f"Running AI step: penalty cooldown: {time_penalty_cooldown}"
                    )
                    iteration -= 1  # Do not increment the iteration on this round
                elif time_limit is None:
                    await ai.on_step(iteration)
                else:
                    out_of_budget = False
                    budget = time_limit - time_window.available

                    # Tell the bot how much time it has left attribute
                    ai.time_budget_available = budget

                    if budget < 0:
                        logger.warning(
                            f"Running AI step: out of budget before step")
                        step_time = 0.0
                        out_of_budget = True
                    else:
                        step_start = time.monotonic()
                        try:
                            async with async_timeout.timeout(budget):
                                await ai.on_step(iteration)
                        except asyncio.TimeoutError:
                            step_time = time.monotonic() - step_start
                            logger.warning(
                                f"Running AI step: out of budget; " +
                                f"budget={budget:.2f}, steptime={step_time:.2f}, "
                                + f"window={time_window.available_fmt}")
                            out_of_budget = True
                        step_time = time.monotonic() - step_start

                    time_window.push(step_time)

                    if out_of_budget and time_penalty != None:
                        if time_penalty == "resign":
                            raise RuntimeError("Out of time")
                        else:
                            time_penalty_cooldown = int(time_penalty)
                            time_window.clear()
        except Exception as e:
            if isinstance(e, ProtocolError) and e.is_game_over_error:
                if realtime:
                    return None
                result = client._game_result[player_id]
                if result is None:
                    log.error("Game over, but no results gathered")
                    raise
                return result

            # NOTE: this message is caught by pytest suite
            logger.exception(f"AI step threw an error")  # DO NOT EDIT!
            logger.error(f"resigning due to previous error")
            # hspark8312: begin
            if log_queue is not None:
                from time import gmtime, strftime
                import traceback
                tb = traceback.format_exc()
                log_queue.put(f"AI step threw an error")
                log_queue.put(f'{e} -> {tb}')
            # hspark8312: end
            ai.on_end(Result.Defeat)
            return Result.Defeat

        logger.debug(f"Running AI step: done")

        if not realtime:
            if not client.in_game:  # Client left (resigned) the game
                ai.on_end(client._game_result[player_id])
                return client._game_result[player_id]

            await client.step()

        iteration += 1
Пример #13
0
async def _play_replay(client, ai, realtime=False, player_id=0):
    ai._initialize_variables()

    game_data = await client.get_game_data()
    game_info = await client.get_game_info()
    ping_response = await client.ping()

    client.game_step = 1
    # This game_data will become self._game_data in botAI
    ai._prepare_start(
        client, player_id, game_info, game_data, realtime=realtime, base_build=ping_response.ping.base_build
    )
    state = await client.observation()
    # Check game result every time we get the observation
    if client._game_result:
        await ai.on_end(client._game_result[player_id])
        return client._game_result[player_id]
    gs = GameState(state.observation)
    proto_game_info = await client._execute(game_info=sc_pb.RequestGameInfo())
    ai._prepare_step(gs, proto_game_info)
    ai._prepare_first_step()
    try:
        await ai.on_start()
    # TODO Catching too general exception Exception (broad-except)
    # pylint: disable=W0703
    except Exception:
        logger.exception("AI on_start threw an error")
        logger.error("resigning due to previous error")
        await ai.on_end(Result.Defeat)
        return Result.Defeat

    iteration = 0
    while True:
        if iteration != 0:
            if realtime:
                # TODO: check what happens if a bot takes too long to respond, so that the requested
                #  game_loop might already be in the past
                state = await client.observation(gs.game_loop + client.game_step)
            else:
                state = await client.observation()
            # check game result every time we get the observation
            if client._game_result:
                try:
                    await ai.on_end(client._game_result[player_id])
                except TypeError:
                    return client._game_result[player_id]
                return client._game_result[player_id]
            gs = GameState(state.observation)
            logger.debug(f"Score: {gs.score.score}")

            proto_game_info = await client._execute(game_info=sc_pb.RequestGameInfo())
            ai._prepare_step(gs, proto_game_info)

        logger.debug(f"Running AI step, it={iteration} {gs.game_loop * 0.725 * (1 / 16):.2f}s")

        try:
            # Issue event like unit created or unit destroyed
            await ai.issue_events()
            await ai.on_step(iteration)
            await ai._after_step()

        # pylint: disable=W0703
        # TODO Catching too general exception Exception (broad-except)
        except Exception as e:
            if isinstance(e, ProtocolError) and e.is_game_over_error:
                if realtime:
                    return None
                await ai.on_end(Result.Victory)
                return None
            # NOTE: this message is caught by pytest suite
            logger.exception("AI step threw an error")  # DO NOT EDIT!
            logger.error(f"Error: {e}")
            logger.error("Resigning due to previous error")
            try:
                await ai.on_end(Result.Defeat)
            except TypeError:
                return Result.Defeat
            return Result.Defeat

        logger.debug("Running AI step: done")

        if not realtime:
            if not client.in_game:  # Client left (resigned) the game
                await ai.on_end(Result.Victory)
                return Result.Victory

        await client.step()  # unindent one line to work in realtime

        iteration += 1
Пример #14
0
async def _play_game_ai(
    client: Client, player_id: int, ai: BotAI, realtime: bool, game_time_limit: Optional[int]
) -> Result:
    gs: GameState = None

    async def initialize_first_step() -> Optional[Result]:
        nonlocal gs
        ai._initialize_variables()

        game_data = await client.get_game_data()
        game_info = await client.get_game_info()
        ping_response = await client.ping()

        # This game_data will become self.game_data in botAI
        ai._prepare_start(
            client, player_id, game_info, game_data, realtime=realtime, base_build=ping_response.ping.base_build
        )
        state = await client.observation()
        # check game result every time we get the observation
        if client._game_result:
            await ai.on_end(client._game_result[player_id])
            return client._game_result[player_id]
        gs = GameState(state.observation)
        proto_game_info = await client._execute(game_info=sc_pb.RequestGameInfo())
        try:
            ai._prepare_step(gs, proto_game_info)
            await ai.on_before_start()
            ai._prepare_first_step()
            await ai.on_start()
        # TODO Catching too general exception Exception (broad-except)
        # pylint: disable=W0703
        except Exception:
            logger.exception("AI on_start threw an error")
            logger.error("Resigning due to previous error")
            await ai.on_end(Result.Defeat)
            return Result.Defeat

    result = await initialize_first_step()
    if result is not None:
        return result

    async def run_bot_iteration(iteration: int):
        nonlocal gs
        logger.debug(f"Running AI step, it={iteration} {gs.game_loop / 22.4:.2f}s")
        # Issue event like unit created or unit destroyed
        await ai.issue_events()
        await ai.on_step(iteration)
        await ai._after_step()
        logger.debug("Running AI step: done")

    # Only used in realtime=True
    previous_state_observation = None
    for iteration in range(10**10):
        if realtime and gs:
            # On realtime=True, might get an error here: sc2.protocol.ProtocolError: ['Not in a game']
            with suppress(ProtocolError):
                requested_step = gs.game_loop + client.game_step
                state = await client.observation(requested_step)
                # If the bot took too long in the previous observation, request another observation one frame after
                if state.observation.observation.game_loop > requested_step:
                    logger.debug("Skipped a step in realtime=True")
                    previous_state_observation = state.observation
                    state = await client.observation(state.observation.observation.game_loop + 1)
        else:
            state = await client.observation()

        # check game result every time we get the observation
        if client._game_result:
            await ai.on_end(client._game_result[player_id])
            return client._game_result[player_id]
        gs = GameState(state.observation, previous_state_observation)
        previous_state_observation = None
        logger.debug(f"Score: {gs.score.score}")

        if game_time_limit and gs.game_loop / 22.4 > game_time_limit:
            await ai.on_end(Result.Tie)
            return Result.Tie
        proto_game_info = await client._execute(game_info=sc_pb.RequestGameInfo())
        ai._prepare_step(gs, proto_game_info)

        await run_bot_iteration(iteration)  # Main bot loop

        if not realtime:
            if not client.in_game:  # Client left (resigned) the game
                await ai.on_end(client._game_result[player_id])
                return client._game_result[player_id]

            # TODO: In bot vs bot, if the other bot ends the game, this bot gets stuck in requesting an observation when using main.py:run_multiple_games
            await client.step()
    return Result.Undecided