# -*- coding:utf-8 -*-
# author: Jiang

"""
想定：尤卡坦冲突-接口调用示例想定
红方智能体
创建任务、分配单元到任务和设置任务，以及设置各级别条令智能体
备注：此智能体仅为态势处理和接口调用示例，而非有效红方策略。
1, 设置条令示例：set_rules
2, 巡逻任务创建以及设置示例：patrol_mission_sample
3, 打击任务创建以及设置示例：strike_mission_sample
4, 支援任务创建以及设置示例：support_mission_sample
5, 转场任务创建以及设置示例：ferry_mission_sample
6, 部雷任务创建以及设置示例：mine_mission_sample
7, 投送任务创建以及设置示例：cargo_mission_sample
8, 扫雷创建以及设置示例：mine_clear_mission_sample
"""

import logging

from engine.LingYi.entitys.global_util import *
from engine.LingYi.entitys.agent_base import RuleAgentBase

logger = logging.getLogger("MissionDoctrineAgent")
logger.setLevel(level=logging.INFO)
formatter_play = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s',
                                   datefmt="%Y-%m-%d %H:%M:%S")
console = logging.StreamHandler()
console.setLevel(logging.INFO)
console.setFormatter(formatter_play)
logger.propagate = False
logger.addHandler(console)


class Agent(RuleAgentBase):
    def __init__(self, side_name, params):
        RuleAgentBase.__init__(self, side_name)
        logger.info('%s:%s play game' % (side_name, self.__class__.__name__))
        self.air_control_mission_name = "制空North"  # 制空巡逻任务名
        self.air_control_mission = None  # 空战巡逻任务对象 patrolmission.py的PatrolMission对象
        self.attack_mission_name = "选定对陆打击"  # 打击任务名
        self.attack_mission = None  # 对陆打击任务对象 strikemission.py的StrikeMission对象
        self.land_patrol_mission_name = "陆上巡逻"  # 陆上巡逻任务名
        self.land_patrol = None  # patrolmission.py的PatrolMission对象
        self.support_detect_mission_name = "预警机侦察"  # 预警机侦察任务名
        self.support_detect_mission = None  # supportmission.py的SupportMission对象
        self.ferry_mission_name = "T50转场"  # 战场任务名 
        self.T50_ferry_mission = None  # 战场任务对象 ferrymission.py的FerryMission对象
        self.west_mine_mission_name = "西部布雷"  # 布雷任务名
        self.west_mine_mission = None  # 西部布雷对象 minemission.py的MineMission对象
        self.cargo_mission_name = "陆战武器投送"  # 货运任务名
        self.cargo_mission = None  # 货运任务对象 cargomission.py的CargoMission对象
        self.mine_clear_mission_name = "A口清雷"  # 清雷任务名
        self.mine_clear_mission = None  # mineclearmission.py的MineClearMission对象

    def set_rules(self):
        """
        设置推演方、单元和任务条令、武器使用规则、电磁规则或撤退规则
        :return:
        """
        # 设置推演方条令
        # 设置对空武器状态：自由开火
        self.doctrine_weapon_control_status_air(WeaponControlStatus.Free)
        # 设置对海武器状态：限制开火
        self.doctrine_weapon_control_status_surface(WeaponControlStatus.Hold)
        # 武器状态，预先规划
        self.doctrine_weapon_state_planned(WeaponStatePlanned.WinchesterDisengage)
        # 设置武器状态返航
        self.doctrine_weapon_state_rtb(WeaponStateRTB.YesLeaveGroup)
        # 设置燃油状态返航
        self.doctrine_fuel_state_rtb(FuelStateRTB.YesLeaveGroup)
        # 设置燃油状态-预先规划
        self.doctrine_fuel_state_planned(FuelState.Joker10Percent)  # 剩余10%任务燃油

        # 设置武器使用规则
        # 武器使用规则--齐射武器数
        self.wra_qty_salvo('1827', WRA_WeaponTargetType.Air_Contact_Unknown_Type, '1')
        self.wra_qty_salvo('1827', WRA_WeaponTargetType.Aircraft_Unspecified, '2')
        self.wra_qty_salvo('1827', WRA_WeaponTargetType.Aircraft_5th_Generation, '3')
        self.wra_qty_salvo('1827', WRA_WeaponTargetType.Aircraft_4th_Generation, '2')
        self.wra_qty_salvo('1827', WRA_WeaponTargetType.Aircraft_3rd_Generation, '1')

        # 武器使用规则--齐射发射架数
        self.wra_shooter_salvo('1827', WRA_WeaponTargetType.Air_Contact_Unknown_Type, 'Max')
        self.wra_shooter_salvo('1827', WRA_WeaponTargetType.Aircraft_Unspecified, 'Max')

        # 武器使用规则 - -自动开火距离
        self.wra_firing_range('1827', WRA_WeaponTargetType.Air_Contact_Unknown_Type, '60')
        self.wra_firing_range('1827', WRA_WeaponTargetType.Aircraft_Unspecified, '80')
        self.wra_firing_range('1827', WRA_WeaponTargetType.Aircraft_5th_Generation, '50')
        self.wra_firing_range('1827', WRA_WeaponTargetType.Aircraft_4th_Generation, '60')
        self.wra_firing_range('1827', WRA_WeaponTargetType.Aircraft_3rd_Generation, '70')

        # 设置任务条令
        if self.air_control_mission is not None:
            self.air_control_mission.doctrine_fuel_state_planned(FuelState.Bingo)  # bingo油量返航
        if self.land_patrol is not None:
            self.land_patrol.doctrine_gun_strafing(GunStrafeGroundTargets.Yes)  # 空对地可用航炮攻击
            self.land_patrol.doctrine_weapon_control_status_land(WeaponControlStatus.Free)  # 对地武器自由开火

        # 设置单元条令
        unit_name = "伊尔-96-400TZ型加油机"
        if unit_name in self.units_of_name:
            unit = self.units_of_name[unit_name]
            if unit is not None:
                unit.doctrine_switch_radar(False)
                unit.doctrine_weapon_control_status_air(WeaponControlStatus.Hold)    # 对空武器自由开火
                unit.doctrine_weapon_control_status_surface(WeaponControlStatus.Hold)  # 对海武器限制开火

        unit_name = "Pr.2235.0 “戈尔什科夫海军元帅”级护卫舰"
        if unit_name in self.units_of_name:
            unit = self.units_of_name[unit_name]
            if unit is not None:
                unit.doctrine_weapon_control_status_surface(WeaponControlStatus.Free)  # 对水面舰船武器自由开火

        unit_name = "地空导弹营(KN-06型地空导弹 [Pongae-5型防空导弹])"
        if unit_name in self.units_of_name:
            unit = self.units_of_name[unit_name]
            if unit is not None:
                unit.wra_firing_range('3442', WRA_WeaponTargetType.Air_Contact_Unknown_Type, '40')
                unit.wra_firing_range('3442', WRA_WeaponTargetType.Aircraft_Unspecified, '40')
                unit.wra_firing_range('3442', WRA_WeaponTargetType.Aircraft_5th_Generation, '35')
                unit.wra_firing_range('3442', WRA_WeaponTargetType.Aircraft_4th_Generation, '40')
                unit.wra_firing_range('3442', WRA_WeaponTargetType.Aircraft_3rd_Generation, '45')

    def patrol_mission_sample(self, situation):
        """
        巡逻任务创建以及设置示例
        :param situation: tuple: units, contacts
        :return: None
        """
        # 智能体的单元获取
        select_points_id = list(self.client_info['point'].keys())  # 智能体开发平台或客户端选择的参考的id列表

        # 智能体目标若为在选择的区域，夺取空权：单元参数配置战斗机，在某区域创建空战巡逻任务
        patrol_area = []  # 空战巡逻区域（需夺取空权区域）
        for id in select_points_id:
            if id in self.ReferencePoints:
                # 配置的参考点在本推演方中
                point_name = self.ReferencePoints[id]["Name"]
                patrol_area.append(point_name)
        if not patrol_area:
            patrol_area = [(19.2, -93.1, 'APN1'), (19.2, -91.7, 'APN2'), (17.8, -91.7, 'APN3'), (17.8, -93.1, 'APN4')]

        self.air_control_mission_name = "制空North"
        self.air_control_mission = self.get_mission_by_name(self.air_control_mission_name)  # 获取任务对象
        if self.air_control_mission is None:
            # 还没有创建“制空North”任务, 创建“巡逻任务”-“防空作战巡逻”
            self.air_control_mission = self.create_patrol_mission(self.air_control_mission_name, MissionPatrolType.AIR,
                                                                  patrol_area)
        else:
            # 如果智能体已在客户端导入运行，任务已创建好，无需重复创建
            # 此时可能客户端选择的任务区域变化，重新设置任务巡逻区
            self.air_control_mission.set_patrolZone(patrol_area)

        # 设置任务条令：对空目标自由开火
        self.air_control_mission.doctrine_weapon_control_status_air(WeaponControlStatus.Free)

        # 任务各种设置，接口文件：mission.py和patrolmission.py
        self.air_control_mission.set_start('5/23/2090 11:02:00')  # 设置任务开始时间 5月23日 11:02:00
        self.air_control_mission.set_end('5/23/2090 11:55:00')  # 设置任务结束时间  5月23日 11:55:00
        self.air_control_mission.set_one_third_rule(False)  # 设置巡逻任务不执行三分之一规则，不然不会全部飞机第一时间起飞
        # 设置任务不对巡逻区外的探测目标进行分析，不然会出巡逻区打击巡逻区外空中目标
        self.air_control_mission.patrol_checkOPA(False)
        self.air_control_mission.patrol_flight_size(FlightSize.Two)  # 设置任务飞机编队规模：两机编队
        self.air_control_mission.set_groupName("G1,G2,G3,G4,G5,G6,G7,G8,G9,G10")  # 设置飞机编队名
        self.air_control_mission.patrol_set_throttle_transit(Throttle.Full)  # 飞机出航油门，全速出发
        self.air_control_mission.patrol_set_throttle_station(Throttle.Cruise)  # 飞机阵位油门，巡航
        self.air_control_mission.patrol_set_throttle_attack(Throttle.Full)  # 飞机攻击油门，全速
        self.air_control_mission.patrol_set_stationAltitude(10500)  # 飞机 阵位高度

        # 使用固定区域创建反水面战巡逻(陆上)---在某区域反陆上巡逻（例：在某区域有敌坦克、装甲车或跑兵，直升机进行反陆上巡逻打击）
        self.land_patrol_mission_name = "陆上巡逻"  # 陆上巡逻任务名

        self.land_patrol = self.get_mission_by_name(self.land_patrol_mission_name)
        if self.land_patrol is None:
            # 区域列表参数点：先纬度，再经度，负纬度为南纬；负经度为西经
            self.land_patrol = self.create_patrol_mission(self.land_patrol_mission_name, MissionPatrolType.ANTI_LAND,
                                                          [(23.04, -81.98), (23.18, -81.34), (22.88, -81.0),
                                                           (22.18, -81.44), (22.69, -82.72)])
        else:
            self.land_patrol.set_patrolZone([(23.04, -81.98), (23.18, -81.34), (22.88, -81.0),
                                             (22.18, -81.44), (22.69, -82.72)])

        # 分配作战单元到任务
        attacker = []
        units, contacts = situation
        for unit_id, unit in units.items():
            # 遍历我方单元
            if unit['category'] == 'Aircraft' and unit['type'] == AircraftType.Attack.value:
                # 单元是飞机, 且是攻击机（直升机攻击机或固定翼攻击机）
                attacker.append(unit_id)
                if len(attacker) == 10:
                    self.assign_units_to_mission(attacker, self.land_patrol_mission_name)
                attacker = []
        if attacker:
            self.assign_units_to_mission(attacker, self.land_patrol_mission_name)

        # 设置巡逻任务不执行三分之一规则，不然不会全部飞机第一时间起飞
        self.land_patrol.set_one_third_rule(False)  
        # 设置任务不对巡逻区外的探测目标进行分析，不然会出巡逻区打击巡逻区外空中目标
        self.land_patrol.patrol_checkOPA(False)
        self.land_patrol.patrol_flight_size(FlightSize.Two)  # 设置任务飞机编队规模：两机编队
        self.land_patrol.patrol_set_throttle_transit(Throttle.Cruise)  # 飞机出航油门，巡航出发
        self.land_patrol.patrol_set_stationAltitude(2000)  # 飞机 阵位高度

    def strike_mission_sample(self):
        """
        打击任务创建以及设置示例
        :return: None
        """
        select_contacts_id = list(self.client_info['contact'].keys())  # 智能体开发平台或客户端选择的情报实体的id列表
        self.attack_mission_name = "选定目标对陆打击"  # 打击任务名
        self.attack_mission = self.get_mission_by_name(self.attack_mission_name)
        if self.attack_mission is None:
            # 创建对陆地目标打击任务
            self.attack_mission = self.create_strike_mission(self.attack_mission_name, MissionStrikeType.LAND)
        # 可以按以上巡逻任务分配单元到任务的方式分配单元到打击任务
        pass
        # 任务各种设置，接口文件：mission.py和strikemission.py
        # 设置任务开始、结束时间
        self.attack_mission.set_start('5/23/2090 11:58:00')  # 设置任务开始时间 5月23日 11:58:00
        self.attack_mission.set_end('5/23/2090 12:40:00')  # 设置任务结束时间  5月23日 12:40:00
        # 分配打击目标到打击任务
        if select_contacts_id:
            self.attack_mission.strike_add_target(select_contacts_id)
        # 打击任务仅考虑计划目标
        self.attack_mission.strike_setPreplan(True)
        # 设置打击任务触发条件：不明
        self.attack_mission.strike_setAttackCondition(StrikeMinimumTrigger.Unknown)
        # 设置打击任务飞机编队规模:三机编队
        self.attack_mission.strike_setStrikeFlightSize(FlightSize.Three)
        # 设置打击任务不会飞机数低于编组规模数要求就不能起飞
        self.attack_mission.strike_setStrikeUseFlightSize(False)
        # 分配作战单元到任务，仅分配一个单元
        if select_contacts_id:
            self.attack_mission.assign_unit(select_contacts_id[0])

        # 任务条令
        self.attack_mission.doctrine_switch_radar(False)
        self.attack_mission.doctrine_switch_oecm(False)
        self.attack_mission.doctrine_switch_sonar(False)

        # 设置打击任务的护航任务的条令
        self.attack_mission.escort.doctrine_switch_radar(True)
        self.attack_mission.escort.doctrine_switch_oecm(False)
        self.attack_mission.escort.doctrine_weapon_control_status_air(WeaponControlStatus.Free)
        self.attack_mission.escort.doctrine_weapon_control_status_surface(WeaponControlStatus.Free)

        unit_name = "图-160M Blackjack 轰炸机 #1"
        if unit_name in self.units_of_name:
            unit = self.units_of_name[unit_name]
            self.attack_mission.assign_unit(unit.ID)
            self.attack_mission.wra_qty_salvo('935', WRA_WeaponTargetType.Runway_Facility_Unspecified, '0')
            self.attack_mission.set_weapon_release_authority('935', '5106', quantity_salvo=1, shooter_salvo='Max', 
                                                             firing_range='1000', self_defense='Max')

    def support_mission_sample(self, situation):
        """
        支援任务创建以及设置示例：最适用于预警机、空中加油和侦察任务。
        :param situation: tuple: units, contacts
        :return: None
        """
        self.support_detect_mission_name = "预警机侦察"  # 预警机侦察任务名
        self.support_detect_mission = self.get_mission_by_name(self.support_detect_mission_name)
        if self.support_detect_mission is None:
            # 支援航线列表：先纬度，再经度
            self.support_detect_mission = self.create_support_mission(self.support_detect_mission_name,
                                                                      [(14.4, -90.83, 'SP_D1'), (15.7, -88.74, 'SP_D2'),
                                                                       (16.5, -87.32, 'SP_D3')])

        # 任务各种设置，接口文件：mission.py和supportmission.py
        self.support_detect_mission.set_one_third_rule(False)
        self.support_detect_mission.support_loopType(False)

        self.support_detect_mission.set_start('5/23/2090 11:20:00')  # 设置任务开始时间 5月23日 11:20:00
        # 不设置结束时间，则任务不限制结束时间

        # 分配作战单元到任务
        attacker = []
        units, contacts = situation
        for unit_id, unit in units.items():
            # 遍历我方单元
            if unit['category'] == 'Aircraft' and unit['type'] == AircraftType.AEW.value:
                # 单元是飞机, 且是预警机
                attacker.append(unit_id)
                if len(attacker) == 10:
                    self.assign_units_to_mission(attacker, self.land_patrol_mission_name)
                attacker = []
        if attacker:    
            self.assign_units_to_mission(attacker, self.land_patrol_mission_name)

    def ferry_mission_sample(self):
        """
        转场任务创建以及设置示例：转场任务把一个空军部队从一个地方转移到另一个地方。转场任务的目的地始终是可以容纳部署任务单元的基地或设施。
        :return: None
        """
        target_host_name = "C国单实体机场 (4x 4000m+ 跑道)"  # 可以通过单元名快速找到单元
        ferry_units = ["T-50型 #1", "T-50型 #2", "T-50型 #3", "T-50型 #4"]
        self.ferry_mission_name = "T50转场"  # 战场任务名
        self.T50_ferry_mission = self.get_mission_by_name(self.ferry_mission_name)
        if self.T50_ferry_mission is None:
            if target_host_name in self.units_of_name:
                self.T50_ferry_mission = self.create_ferry_mission(self.ferry_mission_name,
                                                                   self.units_of_name[target_host_name].ID)
            else:
                self.T50_ferry_mission = self.create_ferry_mission(self.ferry_mission_name, "zjj7bf-0hn937r864m85")

        # 分配作战单元到任务
        t50_id_list = []
        for unit_name in ferry_units:
            if unit_name in self.units_of_name:
                unit_id = self.units_of_name[unit_name].ID
                t50_id_list.append(unit_id)
        if t50_id_list:
            self.assign_units_to_mission(t50_id_list, self.ferry_mission_name)

        # 任务各种设置，接口文件：mission.py和ferrymission.py
        self.T50_ferry_mission.set_behavior(FerryBehavior.OneWay)  # 单程转场
        self.T50_ferry_mission.set_flight_size(FlightSize.Two)  # 两机编队
        self.T50_ferry_mission.set_aircraft_throttle(Throttle.Cruise)  # 转场：巡航油门
        self.T50_ferry_mission.set_aircraft_alt(10800)  # 转场高度

    def mine_mission_sample(self):
        """
        布雷任务创建以及设置示例
        :return: None
        """
        self.west_mine_mission_name = "西部布雷"  # 布雷任务名
        self.west_mine_mission = self.get_mission_by_name(self.west_mine_mission_name)
        if self.west_mine_mission is None:
            self.west_mine_mission = self.create_mine_mission(self.west_mine_mission_name, [(17.4, -107.83, 'WM_P1'), (17.8, -107.14, 'WM_P2'),
                                                                       (18.2, -105.83, 'WM_P3'), (17.9, -106.23, 'WM_P4'), (17.1, -107.65, 'WM_P5')])
        # 任务各种设置，接口文件：mission.py和minemission.py
        # 布雷单元  客户端离线模式进入界面后，加载想定，菜单“想定”-“编辑模式”，选择单元，右键，想定编辑-复制单元ID
        unit_name = "Pr.317 “阿廖莎”级布雷舰" 
        if unit_name in self.units_of_name:
            # 通过单元名获取单元id
            unit_id = self.units_of_name[unit_name].ID
            self.west_mine_mission.assign_unit(unit_id)
        self.west_mine_mission.set_one_third_rule(False)
        self.west_mine_mission.set_armingdelay('0:12:20:0')  # 12小时 20分
        self.west_mine_mission.set_group_size(GroupSize.Single)

    def cargo_mission_sample(self, situation):
        """
        货运任务创建以及设置示例
        从E国野战机场往陆上交战区运送便携防空弹和火炮
        :param situation: tuple: units, contacts
        :return: None
        """
        self.cargo_mission_name = "陆战武器投送"  # 货运任务名
        self.cargo_mission = self.get_mission_by_name(self.cargo_mission_name)
        if self.cargo_mission is None:
            self.cargo_mission = self.create_cargo_mission(self.cargo_mission_name, [(16.7, -93.7, 'CargoP1'), (17.4, -93.3, 'CargoP2'),
                                                                       (17.3, -93.1, 'CargoP3'), (16.5, -93.4, 'CargoP4')])

            self.cargo_mission.set_transit_throttle(Throttle.Cruise)
            self.cargo_mission.set_transit_alt(8000)

        host_unit_name = "E国野战机场 (2x 1401-2000m 跑道)"
        # 分配机场的4架运输机到任务中
        mission_air_count = 4
        air_id_list = []
        if host_unit_name in self.units_of_name:
            host_unit_id = self.units_of_name[host_unit_name].ID

            host_unit = self.get_unit(host_unit_id)
            if host_unit is not None:
                # 查找对陆打击装备，例如：火炮，坦克
                cargo_mount_count = {}
                for cargo_id, cargo in host_unit.Cargos.items():
                    if "Mounts" in cargo:
                        for mount_id, mount in cargo["Mounts"].items():
                            mount_dbid = None
                            if "Component" in mount and "DBID" in mount["Component"]:
                                mount_dbid = mount["Component"]["DBID"]
                            if mount_dbid is not None and "WeaponRecs" in mount:
                                for weapon_rid, weapon_rd in mount["WeaponRecs"].items():
                                    if weapon_rd["CurrentLoad"] > 0 and weapon_rd["LandRangeMax"] > 0:
                                        # 武器数量大于0，且可对陆打击
                                        if mount_dbid not in cargo_mount_count:
                                            cargo_mount_count[mount_dbid] = 1
                                        else:
                                            cargo_mount_count[mount_dbid] = cargo_mount_count[mount_dbid] + 1
                                        break
                max_cargo_count = 10  # 每种武器运送10个基数
                for mount_dbid, count in cargo_mount_count.items():
                    cargo_count = min(max_cargo_count, count)
                    self.cargo_mission.set_unload_mount(mount_dbid, cargo_count)

            units, contacts = situation
            for unit_id, unit in units.items():
                # 遍历我方单元, 是运输飞机，且停靠在E国野战机场
                if unit['category'] == 'Aircraft' and unit['type'] == AircraftType.Transport.value:
                    # 是运输机
                    if "CHU" in unit["airops"] and unit["airops"]["CHU"] == host_unit_id:
                        # 飞机是停靠在E国机场
                        if "Condition" in unit["airops"] and unit["airops"]["Condition"] == AirOpsCondition.Readying.value:
                            # 飞机飞行状态挂载已准备好
                            air_id_list.append(unit_id)
                            if len(air_id_list) >= mission_air_count:
                                break
        if air_id_list:
            self.assign_units_to_mission(air_id_list, self.cargo_mission_name)

    def mine_clear_mission_sample(self):
        """
        清雷任务创建以及设置示例
        :return: None
        """
        self.mine_clear_mission_name = "A口清雷"  # 清雷任务名
        self.mine_clear_mission = self.get_mission_by_name(self.mine_clear_mission_name)
        if self.mine_clear_mission is None:
            self.mine_clear_mission = self.create_mineclear_mission(self.mine_clear_mission_name,
                                                           [(21.2, -86.2, 'MCP1'), (21.4, -85.3, 'MCP2'),
                                                            (20.4, -85.4, 'MCP3'), (20.5, -86.2, 'MCP4')])

            self.mine_clear_mission.set_group_size(GroupSize.Single)  # 设置任务舰船/潜艇编队规模
            # 设置任务的出航油门
            self.mine_clear_mission.set_transit_throttle(Throttle.Full, unit_category=ElementType.Ship)
            # 设置任务的阵位油门
            self.mine_clear_mission.set_station_throttle(Throttle.Cruise, unit_category=ElementType.Ship)

            self.mine_clear_mission.set_end('5/23/2090 15:20:00')  # 设置任务结束时间 5月23日 15:20:00
            self.mine_clear_mission.set_one_third_rule(False)  # 三分之一规则

            # 清雷单元  客户端离线模式进入界面后，加载想定，菜单“想定”-“编辑模式”，选择单元，右键，想定编辑-复制单元ID
            unit_id = "k55efi-0hnfuvhnpoppe"  # 清雷单元id
            self.mine_clear_mission.assign_unit(unit_id)

    def assign_mission(self):
        # 分配选择的单元到任务中
        select_units_guid = list(self.client_info['unit'].keys())  # 智能体开发平台或客户端选择的单元对象id列表
        select_points_id = list(self.client_info['point'].keys())  # 智能体开发平台或客户端选择的参考的id列表
        select_contacts_id = list(self.client_info['contact'].keys())  # 智能体开发平台或客户端选择的情报实体的id列表

        # 每10架飞机分配到任务，超过10架，则可能通信问题传输异常；
        select_air_count = len(select_units_guid)  # 配置的单元数量
        if select_air_count < 11:
            if select_air_count == 1:
                # 仅1架飞机到任务
                self.air_control_mission.assign_unit(select_units_guid[0])
            elif select_air_count > 0:
                # 分配多个单元到任务
                self.assign_units_to_mission(select_units_guid, self.air_control_mission_name)  # 分配任务
            else:
                # 没有选定飞机单元到空战控制巡逻区
                units_name = ["米格-29型 #1", "米格-29型 #2", "米格-29型 #3", "米格-29型 #4", "米格-29型 #5", "米格-29型 #6"]
                units_id = []
                for name in units_name:
                    if name in self.units_of_name:
                        units_id.append(self.units_of_name[name].ID)
                self.assign_units_to_mission(units_id, self.air_control_mission_name)  # 分配任务
        else:
            air_ten_count = select_air_count // 10  # 每次分10架飞机，需分配次数
            if select_air_count % 10 != 0:
                air_ten_count += 1
            for i in range(air_ten_count):
                if i == air_ten_count - 1:
                    start_index = i * 10
                    # 分配多个单元到任务
                    self.assign_units_to_mission(select_units_guid[start_index:], self.air_control_mission_name)
                else:
                    end_index = i * 10 + 10
                    start_index = i * 10
                    # 分配多个单元到任务
                    self.assign_units_to_mission(select_units_guid[start_index:end_index],
                                                 self.air_control_mission_name)

    def move_zone(self, time_elapse):
        """
        移动参考点，删除参考点
        :param time_elapse: int: 推演时间
        :return:
        """
        # 移动制空巡逻任务的参考点APN1  19.2, -93.1
        point1 = "APN1"  
        if 600 < time_elapse < 670:
            for _, point in self.ReferencePoints.items():
                if "Name" in point and point["Name"] == point1:
                    self.reference_point_move(point1, (19.1, -92.9))  # 移动参考点位置
                    break
        elif 1200 < time_elapse < 1270:
            for _, point in self.ReferencePoints.items():
                if "Name" in point and point["Name"] == point1:
                    self.reference_point_delete(point1)  # 删除参考点
                    break

    def initial(self, situation):
        """
        初始化函数，每局推演开始前被调用. 可用于任务创建、设置，条令设置，变量初始化等
        :param situation: tuple: units, contacts
        :return:
        """
        logger.info('%s:%s play initial' % (self.Name, self.__class__.__name__))
        select_units_guid = list(self.client_info['unit'].keys())  # 智能体开发平台或客户端选择的单元对象id列表
        select_points_id = list(self.client_info['point'].keys())  # 智能体开发平台或客户端选择的参考的id列表
        select_contacts_id = list(self.client_info['contact'].keys())  # 智能体开发平台或客户端选择的情报实体的id列表
        self.patrol_mission_sample(situation)
        self.strike_mission_sample()
        self.support_mission_sample(situation)
        self.ferry_mission_sample()
        self.mine_mission_sample()
        self.mine_clear_mission_sample()
        self.cargo_mission_sample(situation)
        self.assign_mission()  # 分配单元到任务
        self.set_rules()  # 设置推演方、任务和单元条令规则

    def step(self, time_elapse, situation):
        """
        # 每步决策函数
        :param time_elapse:  int, time elapse
        :param situation: tuple: units-list, contacts-list
        :return:
        """
        self.move_zone(time_elapse)

    def deduction_end(self):
        # agent结束后自动被调用函数， 可保存模型，比如记录本局策略后的得分等
        logger.info('%s:%s play game result:%d' % (self.Name, self.__class__.__name__, self.TotalScore))

    def is_done(self):
        # agent主动结束本局推演，比如一定胜利或失败后
        # 只能训练时调用此函数，比赛对战时此函数不可用
        if self.TotalScore >= 1500 or self.TotalScore <= -1500:
            logger.info('%s:%s play game do end' % (self.Name, self.__class__.__name__))
            return True
        return False
