Example #1
0
def game_descriptor(board: Board, player_name: int, players: list):
    areas = board.get_player_areas(player_name)
    regions = board.get_players_regions(player_name)
    border = board.get_player_border(player_name)
    max_region_size = max(len(r) for r in regions)
    rel_border_size_1 = len(border) / sum(
        len(board.get_player_border(name)) for name in players)
    rel_border_size_2 = sum(a.get_dice() for a in border) / sum(a.get_dice()
                                                                for a in areas)
    rel_area_size = len(areas) / sum(
        len(board.get_player_areas(name)) for name in players)

    best_border = []
    for r in regions:
        if len(r) == max_region_size:
            for area in map(lambda a: board.get_area(a), r):
                if board.is_at_border(area):
                    best_border.append(area)

    feature_vector = [
        max_region_size / len(board.areas), rel_border_size_1,
        rel_border_size_2, rel_area_size,
        np.mean([survival_prob(a, board) for a in best_border]),
        np.mean([rel_area_power(a, board) for a in areas])
    ]
    return np.asarray(feature_vector, dtype=np.float32)
Example #2
0
def add_dice_to_player(board: Board, player_name: int):
    """Vytvoří dočasné herní pole s náhodně přidělenými kostkami pro vybraného
    hráče. Základní logika předělování kostek je převzatá z implemenetace hry
    viz dicewars/server/game.py line:230.

    Funkce se používá stejně jako funkce simulate_battle.

    Args
    ----
        board (Board): Aktuální stav herního pole
        player_name (int): Jméno hráče, kterému se mají přiřadit kostky
    """

    affected_areas: Dict[int, int] = {}
    dice = 0
    regions = board.get_players_regions(player_name)
    for region in regions:
        dice = max(dice, len(region))

    areas: List[Area] = []
    for area in board.get_player_areas(player_name):
        areas.append(area)

    if dice > 64:
        dice = 64

    while dice and areas:
        area = random.choice(areas)
        if area.dice >= 8:
            areas.remove(area)
        else:
            if area.name not in affected_areas:
                affected_areas[area.name] = area.dice
            area.dice += 1
            dice -= 1

    try:
        yield
    finally:
        # Vrátit herní pole do původního stavu
        for name in affected_areas:
            board.get_area(name).dice = affected_areas[name]
Example #3
0
def add_dice_to_player_worst_case(board: Board, player_name: int, is_yourself: bool, logger):
    affected_areas: Dict[int, int] = {}
    dice = 0
    regions = board.get_players_regions(player_name)
    for region in regions:
        dice = max(dice, len(region))

    if is_yourself:
        areas = board.get_player_areas(player_name)
        b_a = board.get_player_border(player_name)
        areas = list(set(areas)-set(b_a))
        if areas is None:
            areas = b_a
    else:
        areas =  board.get_player_border(player_name)

    arr = [a.get_name() for a in areas]
    logger.info("PLayer: {} with areas: {}".format(player_name, arr))

    if dice > 64:
        dice = 64

    while dice and areas:
        if is_yourself:
            area = random.choice(areas)
            while area.dice < 8:
                area.dice += 1
                dice -= 1
        else:
            area = areas.pop(0)
            areas.append(area)

        if area.dice >= 8:
            areas.remove(area)
        elif not is_yourself:
            if area.name not in affected_areas:
                affected_areas[area.name] = area.dice
            area.dice += 1
            dice -= 1

    if dice > 0:
        if is_yourself:
            areas = board.get_player_border(player_name)
        else:
            areas = board.get_player_areas(player_name)
        while dice and areas:
            area = random.choice(areas)

            if area.dice >= 8:
                areas.remove(area)
            else:
                if area.name not in affected_areas:
                    affected_areas[area.name] = area.dice
                area.dice += 1
                dice -= 1

    try:
        yield
    finally:
        # Vrátit herní pole do původního stavu
        for name in affected_areas:
            board.get_area(name).dice = affected_areas[name]
Example #4
0
    def __maxn_rec(
        self,
        board: Board,
        players_names: Deque[int],
        depth: int,
    ) -> Tuple[Union[Tuple[int, int], None], Dict[int, float]]:
        """
        The Max^n recursive algorithm. It uses the single turn expectiminimax
        for the computation of the best moves in the individual turns.

        :param board: A copy of the game board.
        :param players_names: A queue of players (names of players, i.e., IDs)
               to be considered in this algorithm. The player on the top of the
               queue is a currently associated player. After a player is
               processed, he is removed from the queue.
        :param depth: A depth of the algorithm. It declinines with recursive
               calls of this method.
        :return: A tuple where the first item is a tuple (atacker area,
                 defender area) with the best turn, or None in case there is
                 no suitable turn. And the second item of the tuple is
                 a dictionary where keys are names of players and values
                 are values of the heuristic function for these players in
                 a current game board.
        """
        # there are no more players
        if not players_names:
            # just evaluate the heuristic function for the AI's player
            return None, self._heuristic([self.__player_name], board)

        player_name = players_names[-1]
        # current player is not alive => skip him
        if not board.get_player_areas(player_name):
            players_names.pop()

            return self.__maxn_rec(deepcopy(board), players_names, depth)

        # depth is not 0 => expand lower nodes
        if depth:
            # expand some lower suitable nodes, according to the single turn
            # expectiminimax, the number of nodes to be expanded is decreasing
            # with a depth
            turns = self.__possible_turns(player_name, board)[:depth]
            if not turns:
                # no further moves possible => return just the heuristic
                # in a leaf node
                _, h = self.__maxn_rec(deepcopy(board), players_names, 0)

                return None, h

            h = {}
            turn = 0, 0
            for a, b in turns:
                board_copy = deepcopy(board)
                self.__perform_atack(board_copy, a, b)  # simulate an atack
                _, new_h = self.__maxn_rec(board_copy, players_names,
                                           depth - 1)

                # maximise the heuristic for a current player
                if player_name in new_h:
                    if player_name not in h \
                            or new_h[player_name] > h[player_name]:
                        h = deepcopy(new_h)
                        turn = a, b

            return turn if h else None, h

        # depth is 0 => advance to further players or compute the heuristic

        players_names.pop()
        # there are furthe players
        if players_names:
            return self.__maxn_rec(deepcopy(board), players_names,
                                   self.__MAXN_DEPTH)

        # compute the heuristic function for all living players
        living_players = set(a.get_owner_name() for a in board.areas.values())
        h = self._heuristic(list(living_players), board)

        return None, h