Пример #1
0
    def ai_turn(self, board, nb_moves_this_turn, nb_transfers_this_turn,
                nb_turns_this_game, time_left):
        """AI agent's turn

        This agent estimates probability to win the game from the feature vector associated
        with the outcome of the move and chooses such that has highest improvement in the
        probability.
        """
        self.board = board
        self.logger.debug("Looking for possible turns.")
        turns = self.possible_turns()
        if turns and turns[0][0] != 'end':
            turn = turns[0]
            area_name = turn[0]
            self.logger.debug("Possible turn: {}".format(turn))
            atk_area = self.board.get_area(turn[0])
            atk_power = atk_area.get_dice()

            if turn[2] >= -0.05 or atk_power == 8:
                return BattleCommand(turn[0], turn[1])

        if turns and turns[0][0] == 'end':
            for i in range(1, len(turns)):
                area_name = turns[i][0]
                atk_area = self.board.get_area(area_name)
                atk_power = atk_area.get_dice()
                if atk_power == 8:
                    return BattleCommand(area_name, turns[i][1])

        self.logger.debug("Don't want to attack anymore.")
        return EndTurnCommand()
Пример #2
0
    def ai_turn(self, board, nb_moves_this_turn, nb_transfers_this_turn,
                nb_turns_this_game, time_left):
        """AI agent's turn

        Creates a list with all possible moves along with associated strength
        difference. The list is then sorted in descending order with respect to
        the SD. A move with the highest SD is then made unless the highest
        SD is lower than zero - in this case, the agent ends its turn.
        """

        attacks = []
        for source, target in possible_attacks(board, self.player_name):
            area_dice = source.get_dice()
            strength_difference = area_dice - target.get_dice()
            attack = [
                source.get_name(),
                target.get_name(), strength_difference
            ]
            attacks.append(attack)

        attacks = sorted(attacks, key=lambda attack: attack[2], reverse=True)

        if attacks and attacks[0][2] >= 0:
            return BattleCommand(attacks[0][0], attacks[0][1])

        return EndTurnCommand()
Пример #3
0
    def ai_turn(self, board, nb_moves_this_turn, nb_transfers_this_turn, nb_turns_this_game, time_left):
        """AI agent's turn

        Creates a list with all possible moves along with associated strength
        difference. The list is then sorted in descending order with respect to
        the SD. A move with the highest SD is then made unless the highest
        SD is lower than zero - in this case, the agent ends its turn.
        """

        if self.stage == 'attack':
            attack = get_sdc_attack(board, self.player_name)
            if attack:
                return BattleCommand(attack[0], attack[1])
            else:
                self.stage = 'transfer'

        if self.stage == 'transfer':
            if nb_transfers_this_turn < self.max_transfers:
                transfer = get_transfer_from_endangered(board, self.player_name)
                if transfer:
                    return TransferCommand(transfer[0], transfer[1])
            else:
                self.logger.debug(f'Already did {nb_transfers_this_turn}/{self.max_transfers} transfers, skipping further')

        self.stage = 'attack'
        return EndTurnCommand()
Пример #4
0
 def ai_turn_impl_3(self, board, depth=1):
     turn = self.players_order.index(self.player_name)
     n = len(self.players_order)
     _, act = expectimax_n(board, depth, turn, n, self.heuristics)
     if act is None:
         return EndTurnCommand()
     source, target = act
     return BattleCommand(source.get_name(), target.get_name())
Пример #5
0
 def ai_turn_impl_1(self, board):
     attacks = possible_attacks(board, self.player_name)
     attacks = [(s, t, p) for s, t, p in attacks if s.get_dice() >= t.get_dice()]
     if len(attacks) == 0:
         return EndTurnCommand()
     attacks = sorted(attacks, key=lambda x: x[2], reverse=True)
     source, target, _ = attacks[0]
     return BattleCommand(source.get_name(), target.get_name())
Пример #6
0
    def ai_turn(self, board, nb_moves_this_turn, nb_turns_this_game,
                time_left):
        """
        AI agent's turn
        """
        if time_left < 0.3:
            return EndTurnCommand()

        self.board = board
        self.playersCount = self.board.nb_players_alive()

        # self.logger.critical(time_left)

        if self.playersCount == 2:
            best_turn = self.expectiMinMax()
            if best_turn[0] is not None:
                return BattleCommand(best_turn[0], best_turn[1])
        else:
            turns = self.best_turn()

            if turns:
                turn = turns[0]
                area_name = turn[0]
                self.logger.debug("Possible turn: {}".format(turn))
                hold_prob = turn[2]
                self.logger.debug(
                    "{0}->{1} attack and hold probabiliy {2}".format(
                        area_name, turn[1], hold_prob))

                return BattleCommand(area_name, turn[1])

            if turns:
                turn = turns[0]
                area_name = turn[0]
                self.logger.debug("Possible turn: {}".format(turn))
                hold_prob = turn[2]
                self.logger.debug(
                    "{0}->{1} attack and hold probabiliy {2}".format(
                        area_name, turn[1], hold_prob))

                return BattleCommand(area_name, turn[1])

        self.logger.debug("No more plays.")
        return EndTurnCommand()
Пример #7
0
    def ai_turn(self, board: Board, nb_moves_this_turn: int,
                nb_turns_this_game: int,
                time_left: float) -> Union[BattleCommand, EndTurnCommand]:
        """
        A single turn of the AI agent.

        :param board: A copy of the game board.
        :param nb_moves_this_turn: A number of attacks made in this turn.
        :param nb_turns_this_game: A number of turns ended in this game.
        :param time_left: A time (in seconds) left after last turn.
        :return: Either 'BattleCommand(a, b)' for atacking an enemy area 'b'
                 from an area 'a' or 'EndTurnCommand()' for ending this turn.
        """
        self.__board = board
        self.__loger.debug(
            f'Looking for suitable turns.'
            f' nb_moves_this_turn: {nb_moves_this_turn};'
            f' nb_turns_this_game: {nb_turns_this_game}; time_left: {time_left}'
        )

        # use the Max^n algorithm if possible
        if time_left >= self.__MAXN_TIME_THRESHOLD \
                and nb_moves_this_turn < self.__MAXN_TURNS_LIMIT \
                and nb_turns_this_game < self.__MAXN_TOTAL_TURNS_LIMIT:
            turn = self.__maxn(self.__player_name, board)
            if turn is None:
                return EndTurnCommand()

            a, b = turn
            self.__loger.debug(f'Max^n turn: {a} -> {b}.')

            return BattleCommand(a, b)

        # use the single turn expectiminimax if there are feasible turns
        turns = self.__possible_turns(self.__player_name, board)
        if turns:
            a, b = turns[0]
            self.__loger.debug(f'Possible turn: {a} -> {b}.')

            return BattleCommand(a, b)

        self.__loger.debug('No more suitable turns.')

        return EndTurnCommand()
Пример #8
0
 def ai_turn_impl_2(self, board):
     attacks = possible_attacks(board, self.player_name)
     attacks = [(s, t, p) for s, t, p in attacks if s.get_dice() >= t.get_dice()]
     if len(attacks) == 0:
         return EndTurnCommand()
     probs = self.eval_attacks(board, attacks) * np.asarray([p for _, _, p in attacks])
     best = int(np.argmax(probs))
     if probs[best] > 0.10:
         source, target, _ = attacks[best]
         return BattleCommand(source.get_name(), target.get_name())
     return EndTurnCommand()
Пример #9
0
    def ai_turn(self, board, nb_moves_this_turn, nb_turns_this_game, time_left):
        """AI agent's turn

        Get a random area. If it has a possible move, the agent will do it.
        If there are no more moves, the agent ends its turn.
        """
        attacks = list(possible_attacks(board, self.player_name))
        shuffle(attacks)
        for source, target in attacks:
            return BattleCommand(source.get_name(), target.get_name())

        self.logger.debug("No more possible turns.")
        return EndTurnCommand()
Пример #10
0
    def ai_turn(self, board, nb_moves_this_turn, nb_turns_this_game,
                time_left):
        """AI agent's turn

        Get a random area. If it has a possible move, the agent will do it.
        If there are no more moves, the agent ends its turn.
        """
        if nb_moves_this_turn == 2:
            self.logger.debug("I'm too well behaved. Let others play now.")
            return EndTurnCommand()

        source = random.choice(list(range(25)))
        target = random.choice(list(range(25)))
        return BattleCommand(source, target)
Пример #11
0
    def ai_turn(self, board, nb_moves_this_turn, nb_turns_this_game,
                time_left):
        """AI agent's turn
        Get a random area. If it has a possible move, the agent will do it.
        If there are no more moves, the agent ends its turn.
        """
        if nb_moves_this_turn == 2:
            self.logger.debug("I'm too well behaved. Let others play now.")
            return EndTurnCommand()

        attacks = list(possible_attacks(board, self.player_name))
        if attacks:
            source, target = random.choice(attacks)
            return BattleCommand(source.get_name(), target.get_name())
        else:
            self.logger.debug("No more possible turns.")
            return EndTurnCommand()
Пример #12
0
    def ai_turn(self, board, nb_moves_this_turn, nb_turns_this_game, time_left):
        """AI agent's turn

        AI gets list of preferred moves and plays the best, or if the list is empty,
        ends turn

        """
        self.board = board
        turns = self.possible_turns(self.board, self.player_name)

        if turns:
            turn = turns[0]
            self.logger.debug("Possible turn: {}".format(turn))
            self.logger.debug("{0}->{1} attack".format(turn[0], turn[1]))

            return BattleCommand(turn[0], turn[1])

        return EndTurnCommand()
Пример #13
0
    def ai_turn(self, board, nb_moves_this_turn, nb_transfers_this_turn,
                nb_turns_this_game, time_left):
        """AI agent's turn

        Get a random area. If it has a possible move, the agent will do it.
        If there are no more moves, the agent ends its turn.
        """
        if nb_turns_this_game < 3:
            self.logger.debug("Doing a random move")
            attack_filter = lambda x: x
            attack_selector = random.choice
            attack_acceptor = lambda x: True

            with open('debug.save', 'wb') as f:
                save_state(f, board, self.player_name, self.players_order)

        else:
            self.logger.debug("Doing a serious move")
            attack_filter = lambda x: self.from_largest_region(board, x)
            attack_selector = best_sdc_attack
            attack_acceptor = lambda x: is_acceptable_sdc_attack(x)

            with open('debug.save', 'wb') as f:
                save_state(f, board, self.player_name, self.players_order)

        all_moves = list(possible_attacks(board, self.player_name))
        if not all_moves:
            self.logger.debug("There are no moves possible at all")
            return EndTurnCommand()

        moves_of_interest = attack_filter(all_moves)
        if not moves_of_interest:
            self.logger.debug("There are no moves of interest")
            return EndTurnCommand()

        the_move = attack_selector(moves_of_interest)

        if attack_acceptor(the_move):
            return BattleCommand(the_move[0].get_name(),
                                 the_move[1].get_name())
        else:
            self.logger.debug(
                "The move {} is not acceptable, ending turn".format(the_move))
            return EndTurnCommand()
Пример #14
0
    def ai_turn(self, board, nb_moves_this_turn, nb_turns_this_game, time_left):

        self.board = board
        print("START OF AI {name} TURN".format(name=self.player_name))
        attacks = list(possible_attacks(board, self.player_name))
        if attacks and nb_moves_this_turn == 0:
              self.bestMoveStack = []
              print("STARTING UCS")
              self.UniformCostSearch(attacks)

        if self.bestMoveStack:
            print("ATTACK MOVE")
            print("BEST MOVE STACK CONTENTS")
            print(self.bestMoveStack)
            source, target = self.bestMoveStack.pop()
            print(str(source) + "  NODE attacks NODE " + str(target))
            return BattleCommand(source, target)
        else:
            self.logger.debug("No more possible turns.")
            print(self.player_name)
            print("END OF AI TURN")
            return EndTurnCommand()
Пример #15
0
    def ai_turn(self, board, nb_moves_this_turn, nb_turns_this_game,
                time_left):
        attacks = list((self.model(
            torch.tensor(
                get_features_client(board, attack[0].get_name(),
                                    attack[1].get_name())[0])), attack)
                       for attack in possible_attacks(board, self.player_name))
        # for a in attacks:
        #     print(a[0], get_features_client(board, a[1][0].get_name(), a[1][1].get_name())[0])
        # P(hold source) > 50%
        attacks = filter(lambda x: x[0][0] > .4, attacks)
        # sort by P(hold target)
        attacks = sorted(attacks,
                         key=lambda x: x[0][0] * x[0][1],
                         reverse=True)

        if attacks:
            attack = attacks[0]
            # print('Win', attack)
            return BattleCommand(attack[1][0].get_name(),
                                 attack[1][1].get_name())
        return EndTurnCommand()
Пример #16
0
    def ai_turn(self, board, nb_moves_this_turn, nb_turns_this_game, time_left):
        """AI agent's turn

        Agent gets a list preferred moves and makes such move that has the
        highest estimated hold probability, prefering moves initiated from within
        the largest region. If there is no such move, the agent ends it's turn.
        """
        self.board = board
        self.logger.debug("Looking for possible turns.")
        self.get_largest_region()
        turns = self.possible_turns()

        if turns:
            turn = turns[0]
            self.logger.debug("Possible turn: {}".format(turn))
            hold_prob = turn[3]
            self.logger.debug("{0}->{1} attack and hold probabiliy {2}".format(turn[0], turn[1], hold_prob))

            return BattleCommand(turn[0], turn[1])

        self.logger.debug("No more plays.")
        return EndTurnCommand()
Пример #17
0
    def ai_turn(self, board, nb_moves_this_turn, nb_turns_this_game, time_left):
        """AI agent's turn

        This agent estimates probability to win the game from the feature vector associated
        with the outcome of the move and chooses such that has highest improvement in the
        probability.
        """
        self.board = board
        self.logger.debug("Looking for possible turns.")
        turns = self.possible_turns()

        if turns:
            turn = turns[0]
            self.logger.debug("Possible turn: {}".format(turn))
            atk_area = self.board.get_area(turn[0])
            atk_power = atk_area.get_dice()

            if turn[2] >= -0.05 or atk_power == 8:
                return BattleCommand(turn[0], turn[1])

        self.logger.debug("No more plays.")
        return EndTurnCommand()
Пример #18
0
    def ai_turn(self, board: Board, nb_moves_this_turn: int,
                nb_turns_this_game: int, time_left: float):
        """Provede jeden tah podle vyhodnocení algoritmem MaxN. Pokud algoritmus
        nenalezne výhodnější stav po bitvě než je ten současný, ukončuje kolo.
        """

        # Ochrana proti vypršení času. V případě velkého poklesu zbývajícího času
        # se provede omezení hloubky prohledávání.
        if time_left > 8:
            self.max_n.depth_limit = 8
        elif time_left > 5:
            self.max_n.depth_limit = 4
            self.logger.info(
                "Limiting depth to 4, time left: {}".format(time_left))
        else:
            self.max_n.depth_limit = 1
            self.logger.info(
                "Limiting depth to 1, time left: {}".format(time_left))

        move = self.max_n.get_best_move(board, self.player_name)
        if move == None:
            return EndTurnCommand()
        return BattleCommand(move[0].get_name(), move[1].get_name())
Пример #19
0
    def ai_turn(self, board, nb_moves_this_turn, nb_transfers_this_turn,
                nb_turns_this_game, time_left):
        """AI agent's turn

        Get a random area. If it has a possible move, the agent will do it.
        If there are no more moves, the agent ends its turn.
        """
        sleep_len = random.uniform(0.1, 0.3)
        self.logger.debug("Having {:.3f}s, taking sleep of len {:.3f}".format(
            time_left, sleep_len))
        time.sleep(sleep_len)

        if nb_moves_this_turn == 2:
            self.logger.debug("I'm too well behaved. Let others play now.")
            return EndTurnCommand()

        attacks = list(possible_attacks(board, self.player_name))
        if attacks:
            source, target = random.choice(attacks)
            return BattleCommand(source.get_name(), target.get_name())
        else:
            self.logger.debug("No more possible turns.")
            return EndTurnCommand()
Пример #20
0
    def ai_turn(self, board, nb_moves_this_turn, nb_transfers_this_turn,
                nb_turns_this_game, time_left):
        """AI agent's turn

        Agent gets a list preferred moves and makes such move that has the
        highest estimated hold probability. If there is no such move, the agent
        ends it's turn.
        """
        self.logger.debug("Looking for possible turns.")
        self.board = board
        turns = self.possible_turns()

        if turns:
            turn = turns[0]
            area_name = turn[0]
            self.logger.debug("Possible turn: {}".format(turn))
            hold_prob = turn[2]
            self.logger.debug("{0}->{1} attack and hold probabiliy {2}".format(
                area_name, turn[1], hold_prob))

            return BattleCommand(area_name, turn[1])

        self.logger.debug("No more plays.")
        return EndTurnCommand()
Пример #21
0
    def get_command(self, board):
        alive_players = self.get_alive_players(board)

        ATTACK_HOLD_THRESHOLD = random.uniform(
            self.ATTACK_HOLD_THRESHOLD_MEAN[alive_players] - 0.025,
            self.ATTACK_HOLD_THRESHOLD_MEAN[alive_players] + 0.025)
        DIFF_EVAL_THRESHOLD = random.uniform(
            self.DIFF_WIN_THRESHOLD_MEAN - 0.0005,
            self.DIFF_WIN_THRESHOLD_MEAN + 0.0005)
        WIN_COEFF_THRESHOLD = random.uniform(
            self.ATTACK_HOLD_THRESHOLD_MEAN[alive_players] - 0.025,
            self.ATTACK_HOLD_THRESHOLD_MEAN[alive_players] + 0.025)
        HOLD_SOURCE_WEIGHT = 1 / 3 * (1 - self.ATTACK_WEIGHT[alive_players])
        HOLD_TARGET_WEIGHT = 2 / 3 * (1 - self.ATTACK_WEIGHT[alive_players])

        # ATTACK_HOLD_WEIGHT in (0.5, 0.75)
        ATTACK_HOLD_WEIGHT = 0.75 - self.get_aggresivity(alive_players) * 0.25
        DIFF_WIN_WEIGHT = (1 - ATTACK_HOLD_WEIGHT) / 2
        DIFF_LOSE_WEIGHT = (1 - ATTACK_HOLD_WEIGHT) / 4
        LOSE_HOLD_WEIGHT = (1 - ATTACK_HOLD_WEIGHT) / 4

        attack_hold_prob = []
        diff_eval_win = []
        diff_eval_lose = []
        lose_hold_prob = []

        current_eval = self.evaluate(board, self.player_name)

        for source, target in possible_attacks(board, self.player_name):
            win_board = copy.deepcopy(board)
            lose_board = copy.deepcopy(board)

            target_name_str = str(target.get_name())
            target_name_int = target.get_name()
            source_name_str = str(source.get_name())
            source_name_int = source.get_name()

            win_board.areas[target_name_str].set_owner(self.player_name)
            win_board.areas[target_name_str].set_dice(
                win_board.areas[source_name_str].get_dice() - 1)
            win_board.areas[source_name_str].set_dice(1)
            lose_board.areas[source_name_str].set_dice(1)

            # 1) attack_hold_prob
            attack_prob = probability_of_successful_attack(
                board, source_name_int, target_name_int)

            # We don't want to consider attacks with chance of successful under 20%
            if attack_prob < 0.2:
                continue

            hold_target_prob = probability_of_holding_area(
                win_board, target_name_int,
                win_board.areas[target_name_str].get_dice(), self.player_name)
            hold_source_prob = probability_of_holding_area(
                win_board, source_name_int,
                win_board.areas[source_name_str].get_dice(), self.player_name)
            attack_hold_coeff = (
                self.ATTACK_WEIGHT[alive_players] * attack_prob +
                HOLD_TARGET_WEIGHT * hold_target_prob +
                HOLD_SOURCE_WEIGHT * hold_source_prob) / 3

            # 2) diff_eval_win
            win_eval = self.evaluate(win_board, self.player_name)
            diff_eval_win_coeff = win_eval - current_eval

            good_action = False

            # The treshhold of good / not good attacks
            if alive_players == 2:
                if attack_hold_coeff > WIN_COEFF_THRESHOLD or attack_prob > 0.95:
                    good_action = True
            else:
                if (attack_hold_coeff > ATTACK_HOLD_THRESHOLD / 2 and diff_eval_win_coeff > 2 * DIFF_EVAL_THRESHOLD)\
                   or (attack_hold_coeff > ATTACK_HOLD_THRESHOLD and diff_eval_win_coeff > DIFF_EVAL_THRESHOLD)\
                   or attack_prob > 0.975\
                   or self.check_next_turn(win_board, target, hold_target_prob):
                    good_action = True

            if good_action:
                rank = 0
                if self.check_next_turn(win_board, target, hold_target_prob):
                    rank = 2

                attack_hold_prob.append((source_name_int, target_name_int,
                                         attack_hold_coeff * rank))
                diff_eval_win.append((source_name_int, target_name_int,
                                      diff_eval_win_coeff * rank))

                # 3) diff_eval_lose
                lose_eval = self.evaluate(lose_board, self.player_name)
                diff_eval_lose_coeff = lose_eval - current_eval
                diff_eval_lose.append((source_name_int, target_name_int,
                                       diff_eval_lose_coeff * rank))

                # 4) lose_hold_prob
                lose_hold_prob_coeff = probability_of_holding_area(
                    lose_board, source_name_int,
                    lose_board.areas[source_name_str].get_dice(),
                    self.player_name)
                lose_hold_prob.append((source_name_int, target_name_int,
                                       lose_hold_prob_coeff * rank))

        # # Sorting lists
        # attack_hold_prob.sort(key=lambda tup: tup[2])
        # diff_eval_win.sort(key=lambda tup: tup[2])
        # diff_eval_lose.sort(key=lambda tup: tup[2])
        # lose_hold_prob.sort(key=lambda tup: tup[2])

        # List with possible actions
        possible_actions = []

        for source, target, attack_hold_coeff in attack_hold_prob:
            diff_win_coeff = [
                tup for tup in diff_eval_win
                if tup[0] == source and tup[1] == target
            ][0][2]
            diff_lose_coeff = [
                tup for tup in diff_eval_lose
                if tup[0] == source and tup[1] == target
            ][0][2]
            lose_hold_coeff = [
                tup for tup in lose_hold_prob
                if tup[0] == source and tup[1] == target
            ][0][2]
            action_coeff = (ATTACK_HOLD_WEIGHT * attack_hold_coeff +
                            DIFF_WIN_WEIGHT * diff_win_coeff +
                            DIFF_LOSE_WEIGHT * diff_lose_coeff +
                            LOSE_HOLD_WEIGHT * lose_hold_coeff) / 4
            possible_actions.append((source, target, action_coeff))

        possible_actions.sort(key=lambda tup: tup[2])

        if possible_actions:
            return BattleCommand(possible_actions[0][0],
                                 possible_actions[0][1])
        else:
            return EndTurnCommand()