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()
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()
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()
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())
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())
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()
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()
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()
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()
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)
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()
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()
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()
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()
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()
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()
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()
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())
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()
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()
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()