Beispiel #1
0
 def keep_away_from(state_info, hero_info, rival_hero_info, action_ratios,
                    danger_pos, danger_radius):
     changed = False
     maxQ = max(action_ratios)
     selected = action_ratios.index(maxQ)
     if maxQ == -1:
         return action_ratios
     for selected in range(len(action_ratios)):
         if action_ratios[selected] == -1:
             continue
         if selected < 8:
             fwd = StateUtil.mov(selected)
             tgtpos = PosStateInfo(hero_info.pos.x + fwd.x * 0.5,
                                   hero_info.pos.y + fwd.y * 0.5,
                                   hero_info.pos.z + fwd.z * 0.5)
             if StateUtil.cal_distance(tgtpos, danger_pos) <= danger_radius:
                 print('策略选择', state_info.battleid, hero_info.hero_name,
                       '移动方向会进入危险区域', hero_info.pos.to_string(),
                       tgtpos.to_string())
                 action_ratios[selected] = -1
         elif selected < 18:  # 对敌英雄,塔,敌小兵1~8使用普攻, 针对近战英雄的检测
             if selected == 8:  # 敌方塔
                 print('策略选择', state_info.battleid, hero_info.hero_name,
                       '不要去攻击塔')
                 action_ratios[selected] = -1
             elif selected == 9:  # 敌方英雄
                 if StateUtil.cal_distance(rival_hero_info.pos,
                                           danger_pos) <= danger_radius:
                     print('策略选择', state_info.battleid, hero_info.hero_name,
                           '不要去近身攻击塔范围内的英雄')
                     action_ratios[selected] = -1
             else:  # 小兵
                 creeps = StateUtil.get_nearby_enemy_units(
                     state_info, hero_info.hero_name)
                 n = selected - 10
                 tgt = creeps[n]
                 if StateUtil.cal_distance(tgt.pos,
                                           danger_pos) <= danger_radius:
                     print('策略选择', state_info.battleid, hero_info.hero_name,
                           '不要去近身攻击塔范围内的小兵')
                     action_ratios[selected] = -1
         elif hero_info.cfg_id == '101' and 28 <= selected < 38:  # 专门针对查尔斯的跳跃技能
             skillid = int((selected - 18) / 10 + 1)
             [tgtid, tgtpos] = LineModel.choose_skill_target(
                 selected - 18 - (skillid - 1) * 10, state_info, skillid,
                 hero_info.hero_name, hero_info.pos,
                 rival_hero_info.hero_name)
             if tgtpos is not None:
                 if StateUtil.cal_distance(tgtpos,
                                           danger_pos) <= danger_radius:
                     print('策略选择', state_info.battleid, hero_info.hero_name,
                           '跳跃技能在朝着塔下的目标')
                     action_ratios[selected] = -1
     return action_ratios
Beispiel #2
0
    def play_unit_action(state_info, unit, hero_info, hero_action,
                         near_enemy_units):
        #TODO 需要界定攻击英雄的小兵的范围
        # 最高优先级:如果英雄攻击了对方英雄,周围小兵会优先攻击英雄
        # 考虑攻击范围,当前默认都使用塔的攻击范围
        if PlayEngine.if_hero_attack_opponent(hero_action) \
                and StateUtil.cal_distance(hero_info.pos, unit.pos) <= StateUtil.TOWER_ATTACK_RADIUS:
            state_info = PlayEngine.play_attack(state_info, unit.unit_name,
                                                hero_action.hero_name)

        # 根据attack info来执行动作
        else:
            find_new_tgt = False
            att = state_info.get_attack_info(unit.unit_name)
            if att is not None:
                # 判断被攻击对象是否已经挂了
                defender = state_info.get_unit(att.defer)
                if defender is None or defender.hp <= 0:
                    find_new_tgt = True
                else:
                    state_info = PlayEngine.play_attack(
                        state_info, unit.unit_name, att.defer)

            # 如果丢失对象,攻击最近的敌人
            # 为了节省计算量,我们只从英雄附近的小兵中寻找被攻击者,或者是英雄
            if att is None or find_new_tgt:
                tgt = PlayEngine.find_next_tgt(state_info, unit,
                                               near_enemy_units)
                if tgt is not None:
                    state_info = PlayEngine.play_attack(
                        state_info, unit.unit_name, tgt)
        return state_info
Beispiel #3
0
 def units_in_tower_range(units, target_pos):
     num = 0
     for unit in units:
         if StateUtil.cal_distance(
                 unit.pos, target_pos) <= StateUtil.TOWER_ATTACK_RADIUS:
             num += 1
     return num
Beispiel #4
0
 def choose_skill_target(selected,
                         state_info,
                         skill_info,
                         hero_name,
                         pos,
                         tgt_hero_name,
                         debug=False):
     hero_info = state_info.get_hero(hero_name)
     if selected == 0:
         # 施法目标为自己
         # 首先判断施法目标是不是只限于敌方英雄
         if skill_info.cast_target == SkillTargetEnum.self and hero_name != str(
                 tgt_hero_name):
             if debug: print("施法目标为self,但是对象不是自己")
             return [-1, None]
         tgtid = hero_name
         # TODO 这里有点问题,如果是目标是自己的技能,是不是要区分下目的,否则fwd计算会出现问题
         tgtpos = None
     if selected <= 4:
         # 攻击对方英雄
         tgt_hero = state_info.get_hero(tgt_hero_name)
         if tgt_hero.team != hero_info.team and not tgt_hero.is_enemy_visible(
         ):
             if debug: print("敌方英雄不可见")
             tgtid = -1
             tgtpos = None
         elif StateUtil.cal_distance(tgt_hero.pos,
                                     pos) > skill_info.cast_distance:
             if debug:
                 print("技能攻击不到对方 %s %s %s" %
                       (tgt_hero_name,
                        StateUtil.cal_distance(
                            tgt_hero.pos, pos), skill_info.cast_distance))
             tgtid = 0
             tgtpos = None
         # 对方英雄死亡时候忽略这个目标
         elif tgt_hero.hp <= 0:
             if debug: print("技能攻击不了对方,对方已经死亡")
             tgtid = -1
             tgtpos = None
         else:
             tgtid = tgt_hero_name
             tgtpos = tgt_hero.pos
     return tgtid, tgtpos
Beispiel #5
0
 def use_skill3_correctly(state_info, hero_info, rival_hero_info,
                          rival_near_units, action_ratios):
     if hero_info.cfg_id == '101':
         rival_hero_dis = StateUtil.cal_distance(hero_info.pos,
                                                 rival_hero_info.pos)
         if rival_hero_dis > LineTrainerPolicy.SKILL_RANGE_CHAERSI_SKILL3:
             if LineTrainerPolicy.units_in_range(
                     rival_near_units, hero_info.pos,
                     LineTrainerPolicy.SKILL_RANGE_CHAERSI_SKILL3) == 0:
                 print('策略选择', state_info.battleid, hero_info.hero_name,
                       '查尔斯大招不应该在没人的时候使用')
                 for i in range(38, 48):
                     action_ratios[i] = -1
     return action_ratios
Beispiel #6
0
 def get_attack_tower_action(hero_name, hero_info, tower_unit):
     # 因为目前模型中侦测塔的范围较大,可能出现攻击不到塔的情况
     # 所以需要先接近塔
     # 使用tgtpos,而不是fwd。move命令中fwd坐标系比较奇怪
     if StateUtil.cal_distance(
             hero_info.pos, tower_unit.pos) > StateUtil.ATTACK_UNIT_RADIUS:
         fwd = tower_unit.pos.fwd(hero_info.pos)
         [fwd, output_index] = Replayer.get_closest_fwd(fwd)
         tgtpos = PosStateInfo(hero_info.pos.x + fwd.x * 15,
                               hero_info.pos.y + fwd.y * 15,
                               hero_info.pos.z + fwd.z * 15)
         print("朝塔移动,", hero_name, "hero_pos", hero_info.pos.to_string(),
               "tower_pos", tower_unit.pos.to_string(), "fwd",
               fwd.to_string(), "output_index", output_index)
         action = CmdAction(hero_name, CmdActionEnum.MOVE, None, None,
                            tgtpos, None, None, output_index, None)
     else:
         action_idx = 11
         action = CmdAction(hero_name, CmdActionEnum.ATTACK, 0,
                            tower_unit.unit_name, None, None, None,
                            action_idx, None)
     return action
Beispiel #7
0
    def policy_attack_rival_unit(hero_info, rival_hero_info, state_info,
                                 hero_name, rival_near_units, rival_near_tower,
                                 near_friend_units):
        # 如果附近没有敌方英雄,而且不在塔下,且有己方小兵
        # 攻击敌方小兵
        if (rival_hero_info.hp <= 0 or StateUtil.cal_distance(hero_info.pos, rival_hero_info.pos) >= LineTrainerPolicy.SAFE_RIVAL_HERO_DISTANCE) and \
                        rival_near_tower is None and len(near_friend_units) > 0:
            # 优先攻击快没有血的
            for unit in rival_near_units:
                if unit.hp <= hero_info.att - 20:
                    action = LineTrainerPolicy.get_attack_unit_action(
                        state_info, hero_name, unit.unit_name, 0)
                    print("启动策略 如果附近没有敌方英雄,而且不在塔下,补兵 " + hero_name)
                    return action

            # 如果敌方小兵在攻击自己,后撤到己方的小兵后面
            for unit in rival_near_units:
                att = state_info.if_unit_attack_hero(unit.unit_name, hero_name)
                if att is not None:
                    # 优先物理攻击
                    retreat = LineTrainerPolicy.policy_move_retreat(hero_info)
                    print("启动策略 被小兵攻击的情况下后撤 " + hero_name)
                    return retreat

            # 物理攻击,不攻击血量较少的,留给补刀
            # 选择距离较近的(离己方塔)
            rival_near_units_sorted = list(rival_near_units)
            basement_pos = StateUtil.get_basement(hero_info)
            rival_near_units_sorted.sort(
                key=lambda u: math.fabs(basement_pos.x - u.pos.x),
                reverse=False)
            for unit in rival_near_units_sorted:
                if unit.hp > hero_info.att * 3:
                    action = LineTrainerPolicy.get_attack_unit_action(
                        state_info, hero_name, unit.unit_name, 0)
                    print("启动策略 如果附近没有敌方英雄,而且不在塔下,攻击敌方小兵 " + hero_name)
                    return action
        return None
Beispiel #8
0
    def choose_action(state_info, action_ratios, hero_name, rival_hero,
                      rival_near_units, near_friend_units):
        hero_info = state_info.get_hero(hero_name)
        rival_hero_info = state_info.get_hero(rival_hero)

        original_max_q = max(action_ratios)
        original_selected = action_ratios.index(original_max_q)

        #TODO 注意这里的逻辑是只限于第一个塔的
        rival_near_tower = StateUtil.get_first_tower(state_info,
                                                     rival_hero_info)
        rival_tower_distance = StateUtil.cal_distance(hero_info.pos,
                                                      rival_near_tower.pos)

        # 如果附近没有敌方英雄,而且不在塔下
        # 攻击敌方小兵
        action = LineTrainerPolicy.policy_attack_rival_unit(
            hero_info, rival_hero_info, state_info, hero_name,
            rival_near_units, rival_near_tower, near_friend_units)
        if action is not None:
            return action

        # 如果在塔附近,且周围没有友军,也没有敌方英雄,则直接撤退
        # 如果友方只剩下一个小兵,有一点点血,也开始撤退
        if rival_tower_distance <= LineTrainerPolicy.RIVAL_TOWER_NEARBY_RADIUS:
            if len(near_friend_units) == 0 or (
                    len(near_friend_units) == 1 and near_friend_units[0].hp /
                    float(near_friend_units[0].maxhp) <= 0.5):
                if rival_hero_info.hp <= 0 or StateUtil.cal_distance(
                        hero_info.pos, rival_hero_info.pos
                ) >= LineTrainerPolicy.SAFE_RIVAL_HERO_DISTANCE:
                    print("启动策略 有敌方塔且己方掩护不足时候撤退 " + hero_name)
                    return LineTrainerPolicy.policy_move_retreat(hero_info)

        # 如果附近没有敌方英雄,在敌方塔下,且有小兵掩护
        if rival_tower_distance <= LineTrainerPolicy.RIVAL_TOWER_NEARBY_RADIUS and len(
                near_friend_units) > 0:
            units_in_tower_range = LineTrainerPolicy.units_in_tower_range(
                near_friend_units, rival_near_tower.pos)
            if (rival_hero_info.hp <= 0 or StateUtil.cal_distance(hero_info.pos, rival_hero_info.pos) >= LineTrainerPolicy.SAFE_RIVAL_HERO_DISTANCE) and \
                    rival_near_tower is not None and \
                    units_in_tower_range > 0:
                # 被塔攻击的情况下后撤
                if state_info.if_unit_attack_hero(rival_near_tower.unit_name,
                                                  hero_name):
                    print("启动策略 被塔攻击的情况下后撤 " + hero_name)
                    return LineTrainerPolicy.policy_move_retreat(hero_info)

                # 有敌方小兵先打小兵
                if len(rival_near_units) > 0:
                    action = LineTrainerPolicy.policy_attack_rival_unit(
                        hero_info, rival_hero_info, state_info, hero_name,
                        rival_near_units, rival_near_tower, near_friend_units)
                    if action is not None:
                        print("启动策略 如果附近没有地方英雄,在敌方塔下,且有小兵掩护,有敌方小兵先打小兵 " +
                              hero_name)
                        return action

                # 掩护充足的情况下攻击对方塔
                if units_in_tower_range >= 2:
                    print("启动策略 如果附近没有地方英雄,在敌方塔下,且有小兵掩护,掩护充足的情况下攻击对方塔 " +
                          hero_name)
                    return LineTrainerPolicy.get_attack_tower_action(
                        hero_name, hero_info, rival_near_tower)

                # 不足的情况下后撤(如果在塔的攻击范围内)
                if units_in_tower_range <= 2 and StateUtil.cal_distance(
                        hero_info.pos,
                        rival_near_tower.pos) <= StateUtil.TOWER_ATTACK_RADIUS:
                    print(
                        "启动策略 如果附近没有地方英雄,在敌方塔下,且有小兵掩护,不足的情况下后撤(如果在塔的攻击范围内) " +
                        hero_name)
                    return LineTrainerPolicy.policy_move_retreat(hero_info)

        #TODO 超低血量下撤退

        # 如果对方英雄血量高,且差距明显,不要接近对方英雄
        if hero_info.hp/float(hero_info.maxhp) <= 0.3 and \
           rival_hero_info.hp/float(rival_hero_info.maxhp) >= hero_info.hp/float(hero_info.maxhp) + 0.2:
            # 另外一个条件是双方应该目前有一定的距离
            heros_distance = StateUtil.cal_distance(hero_info.pos,
                                                    rival_hero_info.pos)
            if heros_distance >= LineTrainerPolicy.KEEP_AWAY_FROM_HERO_START_DISTANCE:
                print('策略选择', state_info.battleid, hero_name,
                      '差距明显情况下不要接近对方英雄')
                action_ratios = LineTrainerPolicy.keep_away_from(
                    state_info, hero_info, rival_hero_info, action_ratios,
                    rival_hero_info.pos, heros_distance)

        # 不应该贸然进入对方的塔下
        # 在一个扩大的范围下进行侦查
        if rival_tower_distance <= LineTrainerPolicy.RIVAL_TOWER_NEARBY_RADIUS + 4:
            units_in_tower_range = LineTrainerPolicy.units_in_tower_range(
                near_friend_units, rival_near_tower.pos)
            if units_in_tower_range <= 2:
                print('策略选择', state_info.battleid, hero_name, '检测会不会贸然进入对方的塔下')
                action_ratios = LineTrainerPolicy.keep_away_from(
                    state_info, hero_info, rival_hero_info, action_ratios,
                    rival_near_tower.pos, StateUtil.TOWER_ATTACK_RADIUS)

        # 大招的使用
        # 对于查尔斯,如果周围没有敌人则不应该使用大招
        action_ratios = LineTrainerPolicy.use_skill3_correctly(
            state_info, hero_info, rival_hero_info, rival_near_units,
            action_ratios)

        # 如果对方英雄血量很低,且不在塔下,且我方英雄血量较高
        if rival_hero_info.hp > 0 and rival_hero_info.hp / float(rival_hero_info.maxhp) <= 0.3 and \
           hero_info.hp / float(hero_info.maxhp) >= rival_hero_info.hp / float(
           rival_hero_info.maxhp) + 0.1 and \
           rival_tower_distance > LineTrainerPolicy.RIVAL_TOWER_NEARBY_RADIUS:
            # 选择模型分数较高的行为
            selected_skill = -1
            skill_score = -1
            print('启动策略, 如果对方英雄血量很低,且不在塔下,且我方英雄血量较高, ', state_info.battleid,
                  hero_name, rival_tower_distance)
            for i in range(4):
                action_id = 10 * i + 9
                if action_ratios[action_id] > skill_score:
                    skill_score = action_ratios[action_id]
                    selected_skill = i
            if selected_skill >= 0:
                print("启动策略 如果对方英雄血量很低,且不在塔下,且我方英雄血量较高, 从技能中选择 ", hero_name,
                      selected_skill, skill_score)
                return LineTrainerPolicy.get_attack_hero_action(
                    state_info, hero_name, rival_hero, selected_skill)

        current_max_q = max(action_ratios)
        current_selected = action_ratios.index(current_max_q)
        if original_max_q != current_max_q:
            print('策略选择', state_info.battleid, hero_name, '策略改变',
                  original_selected, current_selected)
            if current_max_q == -1:
                return LineTrainerPolicy.policy_move_retreat(hero_info)
            else:
                return LineModel.select_actions(action_ratios, state_info,
                                                hero_name, rival_hero)
        return None
Beispiel #9
0
 def units_in_range(units, pos, distance):
     num = 0
     for unit in units:
         if StateUtil.cal_distance(unit.pos, pos) <= distance:
             num += 1
     return num
Beispiel #10
0
    def list_unaval_actions(act_size,
                            state_info,
                            hero_name,
                            team_battle_heros,
                            battle_range,
                            debug=False):
        friends, opponents = TeamBattleUtil.get_friend_opponent_heros(
            team_battle_heros, hero_name)
        avail_list = [-1] * act_size
        for i in range(act_size):
            hero = state_info.get_hero(hero_name)
            selected = i
            if selected < 8:  # move
                # 不再检查movelock,因为攻击硬直也会造成这个值变成false(false表示不能移动)
                # 屏蔽会离开战圈的移动
                fwd = StateUtil.mov(selected)
                move_pos = TeamBattleUtil.play_move(hero, fwd)
                in_range = TeamBattleTrainer.in_battle_range(
                    move_pos, battle_range)
                if in_range != -1:
                    avail_list[selected] = -1
                else:
                    avail_list[selected] = 1
                continue
            elif selected < 13:  # 物理攻击:五个攻击目标
                target_index = selected - 8
                target_hero = TeamBattleUtil.get_target_hero(
                    hero_name, friends, opponents, target_index)
                if target_hero is None:
                    avail_list[selected] = -1
                    if debug: print("找不到对应目标英雄")
                    continue
                rival_info = state_info.get_hero(target_hero)
                dist = StateUtil.cal_distance(hero.pos, rival_info.pos)
                # 英雄不可见
                if not rival_info.is_enemy_visible():
                    avail_list[selected] = -1
                    if debug: print("英雄不可见")
                    continue
                # 英雄太远,放弃普攻
                # if dist > self.att_dist:
                if dist > StateUtil.ATTACK_HERO_RADIUS:
                    avail_list[selected] = 0
                    if debug: print("英雄太远,放弃普攻")
                    continue
                # 对方英雄死亡时候忽略这个目标
                elif rival_info.hp <= 0:
                    avail_list[selected] = -1
                    if debug: print("对方英雄死亡")
                    continue
                avail_list[selected] = 1
            elif selected < 28:  # skill1
                # TODO 处理持续施法,目前似乎暂时还不需要
                skillid = int((selected - 13) / 5 + 1)
                if hero.skills[skillid].canuse != True:
                    # 被沉默,被控制住(击晕击飞冻结等)或者未学会技能
                    avail_list[selected] = -1
                    if debug:
                        print("技能受限,放弃施法" + str(skillid) +
                              " hero.skills[x].canuse=" +
                              str(hero.skills[skillid].canuse) + " tick=" +
                              str(state_info.tick))
                    continue
                if hero.skills[skillid].cost is not None and hero.skills[
                        skillid].cost > hero.mp:
                    # mp不足
                    # 特殊情况,德古拉1,2技能是扣除血量
                    if not (hero.cfg_id == '103' and
                            (skillid == 1 or skillid == 2)):
                        avail_list[selected] = -1
                        if debug: print("mp不足,放弃施法" + str(skillid))
                        continue
                if hero.skills[skillid].cd > 0:
                    # 技能未冷却
                    avail_list[selected] = -1
                    if debug: print("技能cd中,放弃施法" + str(skillid))
                    continue
                tgt_index = selected - 13 - (skillid - 1) * 5
                skill_info = SkillUtil.get_skill_info(hero.cfg_id, skillid)
                # TODO 这个buff逻辑还没有测试对应的英雄
                is_buff = True if skill_info.cast_target == SkillTargetEnum.buff else False
                is_self = True if skill_info.cast_target == SkillTargetEnum.self else False
                tgt_hero = TeamBattleUtil.get_target_hero(
                    hero.hero_name, friends, opponents, tgt_index, is_buff,
                    is_self)

                if tgt_hero is None:
                    avail_list[selected] = -1
                    if debug: print("找不到对应目标英雄")
                    continue
                [tgtid, tgtpos] = TeamBattleTrainer.choose_skill_target(
                    tgt_index, state_info, skill_info, hero_name, hero.pos,
                    tgt_hero, debug)
                if tgtid == -1 or tgtid == 0:
                    avail_list[selected] = tgtid
                    if debug: print("目标不符合施法要求")
                    continue
                else:
                    # 根据规则再去过滤
                    policy_avail = TeamBattlePolicy.check_skill_condition(
                        skill_info, state_info, hero, tgt_hero, friends,
                        opponents)
                    if not policy_avail:
                        avail_list[selected] == -1
                    else:
                        avail_list[selected] = 1
        return avail_list
Beispiel #11
0
    def build_response(self, state_info, prev_state_info, line_model, hero_names=None):

        battle_id = state_info.battleid
        tick = state_info.tick

        if tick >= 139062:
            db = 1

        action_strs=[]

        if hero_names is None:
            hero_names = [hero.hero_name for hero in state_info.heros]
        for hero_name in hero_names:
            hero = state_info.get_hero(hero_name)
            prev_hero = prev_state_info.get_hero(hero.hero_name) if prev_state_info is not None else None

            # 检查是否重启游戏
            # 线上第一个塔被摧毁


            # 如果有可以升级的技能,优先升级技能3
            skills = StateUtil.get_skills_can_upgrade(hero)
            if len(skills) > 0:
                skillid = 3 if 3 in skills else skills[0]
                update_cmd = CmdAction(hero.hero_name, CmdActionEnum.UPDATE, skillid, None, None, None, None, None, None)
                update_str = StateUtil.build_command(update_cmd)
                action_strs.append(update_str)

            # 检查周围状况
            near_enemy_heroes = StateUtil.get_nearby_enemy_heros(state_info, hero.hero_name, StateUtil.LINE_MODEL_RADIUS)
            near_enemy_units = StateUtil.get_nearby_enemy_units(state_info, hero.hero_name, StateUtil.LINE_MODEL_RADIUS)
            nearest_enemy_tower = StateUtil.get_nearest_enemy_tower(state_info, hero.hero_name, StateUtil.LINE_MODEL_RADIUS + 3)

            # 回城相关逻辑
            # 如果在回城中且没有被打断则继续回城,什么也不用返回
            if prev_hero is not None:
                if self.hero_strategy[hero.hero_name] == ActionEnum.town_ing and prev_hero.hp <= hero.hp \
                        and not StateUtil.if_hero_at_basement(hero):
                    if not hero.skills[6].canuse:
                        print('回城中,继续回城')
                        continue
                    else:
                        print('回城失败')

            if hero.hp <= 0:
                self.hero_strategy[hero.hero_name] = None
                continue

            # 处在少血状态是,且周围没有地方单位的情况下选择回城
            # if len(near_enemy_heroes) == 0 and len(near_enemy_units) == 0 and nearest_enemy_tower is None:
            #     if hero.hp/float(hero.maxhp) < LineTrainer.TOWN_HP_THRESHOLD:
            #         print('策略层:回城')
            #         # 检查英雄当前状态,如果在回城但是上一帧中受到了伤害,则将状态设置为正在回城,开始回城
            #         if self.hero_strategy[hero.hero_name] == ActionEnum.town_ing:
            #             if prev_hero.hp > hero.hp:
            #                 town_action = CmdAction(hero.hero_name, CmdActionEnum.CAST, 6, hero.hero_name, None, None, None, None, None)
            #                 action_str = StateUtil.build_command(town_action)
            #                 action_strs.append(action_str)
            #         # 检查英雄当前状态,如果不在回城,则将状态设置为正在回城,开始回城
            #         elif self.hero_strategy[hero.hero_name] != ActionEnum.town_ing:
            #             self.hero_strategy[hero.hero_name] = ActionEnum.town_ing
            #             town_action = CmdAction(hero.hero_name, CmdActionEnum.CAST, 6, hero.hero_name, None, None, None, None, None)
            #             action_str = StateUtil.build_command(town_action)
            #             action_strs.append(action_str)
            #
            #         # 无论上面怎么操作,玩家下面的动作应该都是在回城中,所以跳过其它的操作
            #         continue

            # 处在泉水之中的时候设置策略层为吃线
            if StateUtil.if_hero_at_basement(hero):
                if hero.hp < hero.maxhp:
                    continue

            # 撤退逻辑
            # TODO 甚至可以使用移动技能移动
            if hero.hero_name in self.hero_strategy and self.hero_strategy[hero.hero_name] == ActionEnum.retreat:
                dist = StateUtil.cal_distance(hero.pos, self.retreat_pos)
                if dist <= 2:
                    print('到达撤退点附近')
                    self.hero_strategy[hero.hero_name] = None
                elif prev_hero is not None and prev_hero.pos.to_string() == hero.pos.to_string():
                    print('英雄卡住了,取消撤退')
                    self.hero_strategy[hero.hero_name] = None
                else:
                    print('仍然在撤退 ' + str(dist))
                    continue

            # 开始根据策略决定当前的行动
            # 对线情况下,首先拿到兵线,朝最前方的兵线移动
            # 如果周围有危险(敌方单位)则启动对线模型
            # 如果周围有小兵或者塔,需要他们都是在指定线上的小兵或者塔
            line_index = 1
            near_enemy_units_in_line = StateUtil.get_units_in_line(near_enemy_units, line_index)
            nearest_enemy_tower_in_line = StateUtil.get_units_in_line([nearest_enemy_tower], line_index)
            if len(near_enemy_units_in_line) == 0 and len(nearest_enemy_tower_in_line) == 0 and (len(near_enemy_heroes) == 0 or
                    StateUtil.if_in_line(hero, line_index, 4000) == -1):
                self.hero_strategy[hero.hero_name] = ActionEnum.line_1
                # print("策略层:因为附近没有指定兵线的敌人所以开始吃线 " + hero.hero_name)
                # 跟兵线
                front_soldier = StateUtil.get_frontest_soldier_in_line(state_info, line_index, hero.team)
                if front_soldier is None:
                    action_str = StateUtil.build_action_command(hero.hero_name, 'HOLD', {})
                    action_strs.append(action_str)
                else:
                    # 得到最前方的兵线位置
                    move_action = CmdAction(hero.hero_name, CmdActionEnum.MOVE, None, None, front_soldier.pos, None, None, None, None)
                    action_str = StateUtil.build_command(move_action)
                    action_strs.append(action_str)
            else:
                # 使用模型进行决策
                # print("使用对线模型决定英雄%s的行动" % hero.hero_name)
                self.hero_strategy[hero.hero_name] = ActionEnum.line_model
                enemies = []
                enemies.extend((hero.hero_name for hero in near_enemy_heroes))
                enemies.extend((unit.unit_name for unit in near_enemy_units))
                if nearest_enemy_tower is not None:
                    enemies.append(nearest_enemy_tower.unit_name)
                # print('对线模型决策,因为周围有敌人 ' + ' ,'.join(enemies))

                # 目前对线只涉及到两名英雄
                rival_hero = '28' if hero.hero_name == '27' else '27'
                action = line_model.get_action(prev_state_info, state_info, hero.hero_name, rival_hero)
                action_str = StateUtil.build_command(action)
                action_strs.append(action_str)

                # 如果是要求英雄施法回城,更新英雄状态,这里涉及到后续多帧是否等待回城结束
                if action.action == CmdActionEnum.CAST and int(action.skillid) == 6:
                    print("英雄%s释放了回城" % hero_name)
                    self.hero_strategy[hero.hero_name] = ActionEnum.town_ing

                # 如果是选择了撤退,进行特殊标记,会影响到后续的行为
                if action.action == CmdActionEnum.RETREAT:
                    print("英雄%s释放了撤退,撤退点为%s" % (hero_name, action.tgtpos.to_string()))
                    self.hero_strategy[hero.hero_name] = ActionEnum.retreat
                    self.retreat_pos = action.tgtpos

                # 保存action信息到状态帧中
                state_info.add_action(action)
        return action_strs
Beispiel #12
0
    def gen_line_input(self):
        state=[]

        my_hero_info = self.stateInformation.get_hero(self.hero_name)
        rival_hero_info = self.stateInformation.get_hero(self.rival_hero)

        # 添加附近塔信息(2个),搜索半径为self.NEAR_TOWER_RADIUS
        nearest_towers = StateUtil.get_near_towers_in_line(self.stateInformation, my_hero_info, self.line_idx, self.NEAR_TOWER_RADIUS)
        nearest_towers_rival = [t for t in nearest_towers if t.team != my_hero_info.team]
        nearest_towers_team = [t for t in nearest_towers if t.team == my_hero_info.team]

        # 添加双方英雄信息,对线模型暂时只考虑1v1的情况
        my_hero_input = self.gen_input_hero(my_hero_info, nearest_towers_rival)

        # 首先判断对手英雄的位置,如果距离过远则不加入队伍中
        if StateUtil.cal_distance(my_hero_info.pos, rival_hero_info.pos) > self.NEAR_TOWER_RADIUS:
            rival_hero_input = np.zeros(len(my_hero_input)).tolist()
            # print "对手距离过远,不作为输入信息"
        else:
            rival_hero_input = self.gen_input_hero(rival_hero_info, nearest_towers_rival)
        state += my_hero_input
        state += rival_hero_input

        # print(self.hero_name + ' 训练输入信息,敌方塔信息:' + ','.join([str(t.unit_name) for t in nearest_towers_rival]))
        # print(self.hero_name + ' 训练输入信息,己方塔信息:' + ','.join([str(t.unit_name) for t in nearest_towers_team]))
        if len(nearest_towers_rival) == 0:
            tower_input1 = self.gen_input_building(None)
            tower_input2 = self.gen_input_building(None)
        elif len(nearest_towers_rival) == 1:
            tower_input1 = self.gen_input_building(nearest_towers_rival[0], self.stateInformation, self.hero_name)
            tower_input2 = self.gen_input_building(None)
        # 当玩家处在高地时候会有超过2个塔
        elif len(nearest_towers_rival) >= 2:
            tower_input1 = self.gen_input_building(nearest_towers_rival[0], self.stateInformation, self.hero_name)
            tower_input2 = self.gen_input_building(nearest_towers_rival[1], self.stateInformation, self.hero_name)
        else:
            tower_input1 = self.gen_input_building(nearest_towers_rival[0], self.stateInformation, self.hero_name)
            tower_input2 = self.gen_input_building(nearest_towers_rival[1], self.stateInformation, self.hero_name)
        # 添加一个己方塔
        if len(nearest_towers_team) == 0:
            tower_input3 = self.gen_input_building(None)
        else:
            tower_input3 = self.gen_input_building(nearest_towers_team[0], self.stateInformation, self.hero_name)
        state += tower_input1
        state += tower_input2
        state += tower_input3

        # 小兵信息
        enermy_creeps=StateUtil.get_nearby_enemy_units(self.stateInformation,self.hero_name)
        m=len(enermy_creeps)
        n=8
        for i in range(n):
            if i < m:
                state=state+self.gen_input_creep(enermy_creeps[i], self.stateInformation, self.hero_name, nearest_towers_rival)
            else:
                temp=self.gen_input_creep(None)
                state=state+list(temp)
        friend_creeps=StateUtil.get_nearby_friend_units(self.stateInformation, self.hero_name)
        m=len(friend_creeps)
        for i in range(n):
            if i <m:
                state=state+self.gen_input_creep(friend_creeps[i], self.stateInformation, self.hero_name, nearest_towers_rival)
            else:
                temp = self.gen_input_creep(None)
                state=state+list(temp)

        return state
Beispiel #13
0
 def in_skill_range(pos1, pos2, range):
     dis = StateUtil.cal_distance(pos1, pos2)
     if dis < range:
         return dis
     return -1
Beispiel #14
0
    def choose_skill_target(selected,
                            stateinformation,
                            skill,
                            hero_name,
                            pos,
                            rival_hero,
                            debug=False):
        hero_info = stateinformation.get_hero(hero_name)
        skill_info = SkillUtil.get_skill_info(hero_info.cfg_id, skill)
        if selected == 0:
            # 施法目标为自己
            # 首先判断施法目标是不是只限于敌方英雄
            if skill_info.cast_target == SkillTargetEnum.rival:
                return [-1, None]
            tgtid = hero_name
            # TODO 这里有点问题,如果是目标是自己的技能,是不是要区分下目的,否则fwd计算会出现问题
            tgtpos = None
        elif selected == 1:
            # 攻击对方英雄
            # 首先判断施法目标是不是只限于自己
            if skill_info.cast_target == SkillTargetEnum.self:
                return [-1, None]
            rival = stateinformation.get_hero(rival_hero)
            if not rival.is_enemy_visible():
                if debug: print("敌方英雄不可见")
                tgtid = -1
                tgtpos = None
            elif StateUtil.cal_distance(rival.pos,
                                        pos) > skill_info.cast_distance:
                if debug:
                    print("技能攻击不到对方 %s %s %s" %
                          (rival_hero, StateUtil.cal_distance(
                              rival.pos, pos), skill_info.cast_distance))
                tgtid = -1
                tgtpos = None
            # 对方英雄死亡时候忽略这个目标
            elif rival.hp <= 0:
                if debug: print("技能攻击不了对方,对方已经死亡")
                tgtid = -1
                tgtpos = None
            else:
                tgtid = rival_hero
                tgtpos = rival.pos
        else:
            # 对敌方小兵施法
            if skill_info.cast_target == SkillTargetEnum.self:
                return [-1, None]

            # 寻找合适的小兵作为目标
            creeps = StateUtil.get_nearby_enemy_units(stateinformation,
                                                      hero_name)
            n = selected - 2
            if n >= len(creeps):
                # 没有这么多小兵
                if debug: print("技能不能攻击,没有指定的小兵")
                return [-1, None]
            elif not creeps[n].is_enemy_visible():
                if debug: print("敌方小兵不可见")
                tgtid = -1
                tgtpos = None
            elif StateUtil.cal_distance(
                    pos, creeps[n].pos) > skill_info.cast_distance:
                if debug: print("技能不能攻击,小兵距离过远")
                tgtid = -1
                tgtpos = None
            elif creeps[n].hp <= 0:
                if debug: print("技能不能攻击,小兵已经死亡")
                tgtid = -1
                tgtpos = None
            else:
                tgtid = creeps[n].unit_name
                tgtpos = creeps[n].pos
        return [tgtid, tgtpos]
Beispiel #15
0
 def remove_unaval_actions(acts,
                           stateinformation,
                           hero_name,
                           rival_hero,
                           debug=False):
     for i in range(len(acts)):
         hero = stateinformation.get_hero(hero_name)
         selected = i
         if selected < 8:  # move
             # 不再检查movelock,因为攻击硬直也会造成这个值变成false(false表示不能移动)
             continue
         elif selected < 18:  # 对敌英雄,塔,敌小兵1~8使用普攻
             if hero.skills[0].canuse != True and (
                     hero.skills[0].cd == 0 or hero.skills[0].cd == None):
                 # 普通攻击也有冷却,冷却时canuse=false,此时其实我们可以给出攻击指令的
                 # 所以只有当普通攻击冷却完成(cd=0或None)时,canuse仍为false我们才认为英雄被控,不能攻击
                 # 被控制住
                 acts[selected] = -1
                 if debug: print("普攻受限,放弃普攻")
                 continue
             if selected == 8:  # 敌方塔
                 tower = StateUtil.get_nearest_enemy_tower(
                     stateinformation, hero_name,
                     StateUtil.ATTACK_UNIT_RADIUS)
                 if tower is None:
                     acts[selected] = -1
                     if debug: print("塔太远,放弃普攻")
                     continue
                 dist = StateUtil.cal_distance(hero.pos, tower.pos)
                 # if dist > self.att_dist:
                 if dist > StateUtil.ATTACK_UNIT_RADIUS:
                     # 在攻击范围外
                     acts[selected] = -1
                     if debug: print("塔太远,放弃普攻")
                     continue
             elif selected == 9:  # 敌方英雄
                 tgtid = rival_hero
                 rival_info = stateinformation.get_hero(rival_hero)
                 dist = StateUtil.cal_distance(hero.pos, rival_info.pos)
                 # 英雄不可见
                 if not rival_info.is_enemy_visible():
                     acts[selected] = -1
                     if debug: print("英雄不可见")
                     continue
                 # 英雄太远,放弃普攻
                 # if dist > self.att_dist:
                 if dist > StateUtil.ATTACK_HERO_RADIUS:
                     acts[selected] = -1
                     if debug: print("英雄太远,放弃普攻")
                     continue
                 # 对方英雄死亡时候忽略这个目标
                 elif rival_info.hp <= 0:
                     acts[selected] = -1
                     if debug: print("对方英雄死亡")
                     continue
             else:  # 小兵
                 creeps = StateUtil.get_nearby_enemy_units(
                     stateinformation, hero_name)
                 n = selected - 10
                 # 小兵不可见
                 if n >= len(creeps):
                     # 没有这么多小兵
                     acts[selected] = -1
                     if debug: print("没有这么多兵,模型选错了")
                     continue
                 if not creeps[n].is_enemy_visible():
                     acts[selected] = -1
                     if debug: print("小兵不可见")
                     continue
                 dist = StateUtil.cal_distance(hero.pos, creeps[n].pos)
                 # if dist > self.att_dist:
                 if dist > StateUtil.ATTACK_UNIT_RADIUS:
                     acts[selected] = -1
                     if debug: print("小兵太远,放弃普攻")
                     continue
                 # print ("英雄%s可以攻击到小兵%s,英雄位置%s,小兵位置%s,距离%s" % (str(hero_name), str(creeps[n].unit_name),
                 #                     hero.pos.to_string(), creeps[n].pos.to_string(), str(dist)))
         elif selected < 48:  # skill1
             skillid = int((selected - 18) / 10 + 1)
             if hero.skills[skillid].canuse != True:
                 # 被沉默,被控制住(击晕击飞冻结等)或者未学会技能
                 acts[selected] = -1
                 if debug:
                     print("技能受限,放弃施法" + str(skillid) +
                           " hero.skills[x].canuse=" +
                           str(hero.skills[skillid].canuse) + " tick=" +
                           str(stateinformation.tick))
                 continue
             if hero.skills[skillid].cost is not None and hero.skills[
                     skillid].cost > hero.mp:
                 # mp不足
                 acts[selected] = -1
                 if debug: print("mp不足,放弃施法" + str(skillid))
                 continue
             if hero.skills[skillid].cd > 0:
                 # 技能未冷却
                 acts[selected] = -1
                 if debug: print("技能cd中,放弃施法" + str(skillid))
                 continue
             [tgtid, tgtpos] = LineModel.choose_skill_target(
                 selected - 18 - (skillid - 1) * 10, stateinformation,
                 skillid, hero_name, hero.pos, rival_hero, debug)
             if tgtid == -1:
                 acts[selected] = -1
                 if debug: print("目标不符合施法要求")
                 continue
         elif selected == 48:  # 撤退
             acts[selected] = -1
         elif selected == 49:  # 撤退
             acts[selected] = -1
     return acts