庙算兵棋推演AI开发初探(5-数据处理)

碎碎念:这最近几个月过得那叫一个难受,研究生开题没过、需求评审会在4月和6月开了2次、7月紧接着软件设计评审会,加班干得都是文档的事情,还有开会前的会务和乱七八糟的琐事,我们干的还被规定弄的束手束脚,领导还在“动态的增加任务”,逼得我和领导发了个火……把人当承载任务的工具和垫脚石,不考虑员工的自身发展、创造性和工作时间,我是怎么还能待到现在的。

——2024.7.28以上

开题终于在12月过了,刚过去的这周又全周无休准备出差的东西,今天终于有时间在开题后搞一搞了——2025.1.6

关于庙算的东西网上实在太少,再深入的话我可能先去找找sc2(星际2)的相关内容了。后来我建了个QQ庙算智能体开发研讨群聊——962415181,欢迎同好加入。


0.实现神经网络驱动的智能体的步骤

以下是模仿学习的步骤(分拣、提取、构建神经网络+行为预测

1_filter

从源视数据中筛选出符合标准的对局复盘(replay)

2_extract

从筛选过的复盘数据中提取样本(sample)

切碎的细节特征(features)

——这部分是用numpy把各种特征组合成矩阵,方便神经网络来学习

3_neuralnetwork

设计的单算子行为克隆网络

设计的多算子分层监督学习网络

1.复盘格式版本问题

首先,庙算平台在2024年更新过一次,从python3.8改成3.10了,存储的复盘文件从一个json变成了一帧一个json然后打成压缩包的形式了(更方便找数据了,但我也需要重新写解析的代码了……)

写了一个拆分版本、一个json版本相互转化的代码:


def replay_merge(input_dir, output_file):    
    """
    用于新版1800+个分文件合并回旧文件
    """
    merged_data = []

    for file_name in sorted(os.listdir(input_dir)):
        if file_name.endswith('.json'):
            file_path = os.path.join(input_dir, file_name)
            with open(file_path, 'r', encoding='utf-8') as f:
                data = json.load(f)
                merged_data.append(data)

    with open(output_file, 'w', encoding='utf-8') as f:
        json.dump(merged_data, f, ensure_ascii=False, indent=4)
        # json.dump(merged_data, f, ensure_ascii=False) # 一行json不缩进
    print(f"Created {output_file}")


def replay_split(source_file, output_dir=None):
    """
    用于旧版一行json文件转化为新版1800+个分文件
    """
    with open(source_file, 'r', encoding='gbk') as f:
        content = f.read()

    json_data = json.loads(content)

    #直接输出到源目录
    if output_dir is None:
        # 新建一个文件夹路径
        new_dir = os.path.join(os.path.dirname(source_file), 'replay_split')    
        # 创建新文件夹
        os.makedirs(new_dir, exist_ok=True)
        output_dir = new_dir

    # 检查 json_data 是否是列表
    if isinstance(json_data, list):
        for i, item in enumerate(json_data):
            new_file_name = f"{output_dir}/element_{i}.json"
            with open(new_file_name, 'w', encoding='utf-8') as new_file:
                json.dump(item, new_file, ensure_ascii=False, indent=4)
                # json.dump(item, new_file, ensure_ascii=False) # 一行json不缩进
            print(f"Created {new_file_name}")
    else:
        print("json_data is not a list")

2.复盘json查看方法

在每次的离线推演后,都有数据压缩包在log文件夹中被保存(新版把每一帧的数据当作独立的json数据文件了,也还可以)

为了我的RLHF(RLHF (RL with Human Feedback))来模拟人决策风格的想法,我需要处理实时的人类操作和交互数据。

比如我打开了上面的某条数据,是“一行”的json,我用vscode打开,可以右键“格式化文档”,左侧也可以找一个json扩展来方便使用。【格式化文档后,记得点一下插件上的“刷新”来重新匹配所在行】

格式化后的效果

目前我用qt绘制了兵棋的棋盘(已经搁置,用不上了),通过linux虚拟机运行庙算引擎与我的外部qt进行udp通信来进行交互。

3.复盘json代码解析

这部分一般需要通过json.load(file)函数,然后用['xxx']来获取

然后在获取帧的内容,如下举个例子 

    #攻击特征列表获取
    def attack_feature(self,valid_action):
        # 阵亡算子攻击力不做处理,后续并不会用到
        # 真实攻击力,从validaction获取。最小化我方攻击力
        for i in self.alliance_ids:
            self.attack_list[i] = {}
            if i in valid_action:
                action = valid_action[i]
                if action.__contains__(2):
                    for attack_action in action[2]:
                        if self.attack_list[i].__contains__(attack_action['target_obj_id']):
                            self.attack_list[i][attack_action['target_obj_id']] = max(
                                self.attack_list[i][attack_action['target_obj_id']],
                                attack_action['attack_level'])
                        else:
                            self.attack_list[i][attack_action['target_obj_id']] = attack_action['attack_level']

4.特征提取(特征化为编码区分,以便输入神经网络)

一般使用 one-hot 编码对特征进行编码,再放到神经网络中

提取好onehot编码过的特征,可以用如下方法存成zip

    data_path = f'{name}'
    np.savez(data_path, game_stats, bop_features, spatial_features, bop_embeddings, sample_label) # save as npz file
    with zipfile.ZipFile(train_data_save_path + f'{name}' + '.zip', 'w', compression=zipfile.ZIP_DEFLATED, compresslevel=7) as f: # compress npz to zip
            f.write(data_path + '.npz')
    os.remove(data_path + '.npz')

神经网络的输入是有形状要求的,需要与神经网络的输入进行配合……(这部分在下一节神经网络设计中补上)


五个要素

庙算·陆战指挥官 平台文档

态势-State and Observation

state一般代表环境当前的所有状态。observation一般情况下代表对于某个智能体可观测的态势。observationstate的子集。

TrainEnvstep函数返回的state,表示当前环境的所有状态合集。状态合集有红方蓝方绿方态势组成:state[0]代表的是红方态势,state[1]代表的是蓝方态势,state[-1]代表的是绿方态势。 agent代码的step函数接受的参数是态势observation,它封装了当前时间,此agent能观测到的所有盘面信息,包括算子信息、裁决信息等。以下是态势最外层的数据结构以及他们代表的含义。


动作-Action

agent的step函数必须返回一个动作列表。 列表中的每个元素action表示的是该agent当前帧要进行的动作的确切信息,需要遵守正确的数据结构。 而后此动作列表将作为TrainEnv.step的参数传入环境。


地图-Map

为方便AI开发,平台将相关公开地图基础函数工具放置于ai/map.py中,开发者可以在自己的agent中使用其中Map类加载地图数据,并使用其提供的一些开放接口获得地图基础数据相关信息。


想定-Scenario

想定文件是环境初始化时的必要文件,内部包含一个想定的所有初始条件。想定文件直接决定一场推演的初始态势。开发者可以自行修改想定文件的内容,达到修改想定的目的。


武器-Weapon

打击效果由【毁伤的裁决表格】查表得到。

最后是附录,从官网文档整理得到,加了与demoAI的agnet里行为枚举的中英对照

吐槽:官网文档里竟然还有括号没补全的小错误!!!我给补上了。

附录1:指令行为(Action)json解释

"""
兵棋以json串来作为执行命令的载体,action的type来解释实际使用的是什么动作
https://wargame.ia.ac.cn/docs/reference/actions/
"""




actions = \
{
    "机动,Move": {
        "actor": "int 动作发出者席位",
        "obj_id": "算子ID int",
        "type": 1,
        "move_path": "机动路径 list(int)"
    },
    "打击,Shoot": {
        "actor": "int 动作发出者席位",
        "obj_id": "攻击算子ID int",
        "type": 2,
        "target_obj_id": "目标算子ID",
        "weapon_id": "武器ID int"
    },
    "上车,GetOn": {
        "actor": "int 动作发出者席位",
        "obj_id": "乘员算子ID int",
        "type": 3,
        "target_obj_id": "车辆算子ID"
    },
    "下车,GetOff": {
        "actor": "int 动作发出者席位",
        "obj_id": "车辆算子ID int",
        "type": 4,
        "target_obj_id": "乘员算子ID"
    },
    "夺控,Occupy": {
        "actor": "int 动作发出者席位",
        "obj_id": "算子ID int",
        "type": 5
    },
    "切换状态,ChangeState": {
        "actor": "int 动作发出者席位",
        "obj_id": "算子ID int",
        "type": 6,
        "target_state": "目标状态 0-正常机动 1-行军 2-一级冲锋 3-二级冲锋, 4-掩蔽 5-半速"
    },
    "移除压制,RemoveKeep": {
        "actor": "int 动作发出者席位",
        "obj_id": "算子ID int",
        "type": 7
    },
    "间瞄射击,JMPlan": {
        "actor": "int 动作发出者席位",
        "obj_id": "攻击算子ID int",
        "type": 8,
        "jm_pos": "目标位置",
        "weapon_id": "武器ID int"
    },
    "引导射击,GuideShoot": {
        "actor": "int 动作发出者席位",
        "obj_id": "引导算子ID int",
        "type": 9,
        "target_obj_id": "目标算子ID",
        "weapon_id": "武器ID int",
        "guided_obj_id": "射击算子ID"
    },
    "停止机动,StopMove": {
        "actor": "int 动作发出者席位",
        "obj_id": "算子ID int",
        "type": 10
    },
    "武器锁定,WeaponLock": {
        "actor": "int 动作发出者席位",
        "obj_id": "算子ID int",
        "type": 11
    },
    "武器展开,WeaponUnFold": {
        "actor": "int 动作发出者席位",
        "obj_id": "算子ID int",
        "type": 12
    },
    "取消间瞄计划,CancelJMPlan": {
        "actor": "int 动作发出者席位",
        "obj_id": "算子ID int",
        "type": 13
    },
    "配置编组信息(营长专属动作)": {
        "actor": "int 动作发出者席位",
        "type": 100,
        "info": {
            "int 席位数": {
                "operators": [
                    "int 算子id",
                    "int 算子id"
                ]
            }
        }
    },
    "进攻任务(营长专属下达)": {
        "actor": "int 动作发出者席位",
        "type": 207,
        "seat": "命令接收人id",
        "hex": "任务目标位置",
        "start_time": "起始时间",
        "end_time": "结束时间",
        "unit_ids": "执行任务的单位ID列表",
        "route": "执行此任务的途径点列表"
    },
    "防御任务(营长专属下达)": {
        "actor": "int 动作发出者席位",
        "type": 208,
        "seat": "命令接收人id",
        "hex": "任务目标位置",
        "start_time": "起始时间",
        "end_time": "结束时间",
        "unit_ids": "执行任务的单位ID列表",
        "route": "执行此任务的途径点列表"
    },
    "侦察任务(营长专属下达)": {
        "actor": "int 动作发出者席位",
        "type": 209,
        "seat": "命令接收人id",
        "hex": "任务目标位置",
        "radius": "侦察半径",
        "start_time": "起始时间",
        "end_time": "结束时间",
        "unit_ids": "执行任务的单位ID列表",
        "route": "执行此任务的途径点列表"
    },
    "集结任务(营长专属下达)": {
        "actor": "int 动作发出者席位",
        "type": 210,
        "seat": "命令接收人id",
        "hex": "任务目标位置",
        "start_time": "起始时间",
        "end_time": "结束时间",
        "unit_ids": "执行任务的单位ID列表",
        "route": "执行此任务的途径点列表"
    },
    "删除作战任务(营长专属动作)": {
        "actor": "int 动作发出者席位",
        "type": 202,
        "msg_id": "int 要删除的作战指令的id"
    },
    "部署上车": {
        "actor": "int 动作发出者席位",
        "obj_id": "乘员算子ID int",
        "type": 303,
        "target_obj_id": "车辆算子ID"
    },
    "部署下车": {
        "actor": "int 动作发出者席位",
        "obj_id": "车辆算子ID int",
        "type": 304,
        "target_obj_id": "乘员算子ID"
    },
    "解聚,Fork": {
        "actor": "int 动作发出者",
        "obj_id": "算子ID int",
        "type": 14
    },
    "聚合,Union": {
        "actor": "int 动作发出者",
        "obj_id": "算子ID int",
        "target_obj_id": "算子ID int",
        "type": 15
    },
    "部署解聚(赛前部署动作)": {
        "actor": "int 动作发出者",
        "obj_id": "算子ID int",
        "type": 314
    },
    "部署聚合(赛前部署动作)": {
        "actor": "int 动作发出者",
        "obj_id": "算子ID int",
        "target_obj_id": "算子ID int",
        "type": 315
    },
    "改变高程,ChangeAltitude": {
        "actor": "int 动作发出者",
        "obj_id": "算子ID int",
        "type": 16,
        "target_altitude": "目标高程,20超低空,200低空 500高空"
    },
    "部署改变高程(赛前部署动作)": {
        "actor": "int 动作发出者",
        "obj_id": "算子ID int",
        "type": 316,
        "target_altitude": "目标高程,20超低空,200低空 500高空"
    },
    "开启校射雷达,ActivateRadar": {
        "actor": "int 动作发出者",
        "obj_id": "算子ID int",
        "type": 17
    },
    "进入工事,EnterFort": {
        "actor": "int 动作发出者",
        "obj_id": "算子ID int",
        "type": 18,
        "target_obj_id": "工事算子ID"
    },
    "退出工事,ExitFort": {
        "actor": "int 动作发出者",
        "obj_id": "算子ID int",
        "type": 19,
        "target_obj_id": "工事算子ID"
    },
    "布雷,LayMine": {
        "actor": "int 动作发出者",
        "obj_id": "布雷车算子ID int",
        "type": 20,
        "target_pos": "布雷坐标 int"
    },
    "导演击杀算子(导演动作)": {
        "actor": "int",
        "type": 401,
        "target_obj_id": "击杀算子id"
    },
    "导演布雷(导演动作)": {
        "actor": "int",
        "type": 402,
        "target_pos": "布雷坐标"
    },
    "导演建造路障(导演动作)": {
        "actor": "int",
        "type": 403,
        "target_pos": "路障坐标"
    },
    "导演增加算子(导演动作)": {
        "actor": "int",
        "type": 404,
        "sub_type": "算子sub_type",
        "color": "0红, 1蓝",
        "hex": "空降位置"
    },
    "结束部署(赛前部署动作)": {
        "actor": "int,动作发出者",
        "type": 333
    },
    "发送聊天信息": {
        "actor": "int 动作发出者",
        "type": 204,
        "to_all": "0-发给队友,1-发给全部",
        "msg_body": "custoum strings, up to 100 characters in Chinese and 50 words in English"
    },
    "发送辅助渲染信息":
    {
        "actor": "int 动作发出者",
        "type": 205,
        "msg_body": {
        "hexs": ["六角格坐标"], 
        "graphic_type": "渲染模式,见下文",
        "word": "渲染字符",
        "color": "颜色,hex各式,#ffffff",
        "description": "对于此命令的其他描述,字符串"
        }  
    }

}

附录2:观测状态(Observation)json解释

"""
态势信息json格式
整理来源 https://wargame.ia.ac.cn/docs/reference/observations/
"""


observation =\
{
    "actions": # 上一步接收到的动作
    [
        {
            "cur_step": "int, 当前步长",
            "message": "dict, 动作信息",
            "error": {
                "code": "int, 错误码 int",
                "message": "str, 错误原因"
            }
        }
    ],
    "cities":  # 各个夺控点的信息
    [
        {
            "coord": "int, 坐标",
            "value": "int, 分值",
            "flag": "int, 阵营 0-红 1-蓝",
            "name": "str, 名称 str"
        }
    ],
    "communication": # 通信相关信息
    [
        # 进攻任务信息
        {
            "actor": "int 动作发出者席位",
            "type": 207,
            "seat": "命令接收人id",
            "hex": "任务目标位置",
            "start_time": "起始时间",
            "end_time": "结束时间",
            "unit_ids": "执行任务的单位ID列表",
            "route": "执行此任务的途径点列表"
        },
        # 防御任务
        {
            "actor": "int 动作发出者席位",
            "type": 208,
            "seat": "命令接收人id",
            "hex": "任务目标位置",
            "start_time": "起始时间",
            "end_time": "结束时间",
            "unit_ids": "执行任务的单位ID列表",
            "route": "执行此任务的途径点列表"
        },
        # 侦察任务
        {
            "actor": "int 动作发出者席位",
            "type": 209,
            "seat": "命令接收人id",
            "hex": "任务目标位置",
            "radius": "侦察半径",
            "start_time": "起始时间",
            "end_time": "结束时间",
            "unit_ids": "执行任务的单位ID列表",
            "route": "执行此任务的途径点列表"
        },
        # 集结任务
        {
            "actor": "int 动作发出者席位",
            "type": 210,
            "seat": "命令接收人id",
            "hex": "任务目标位置",
            "start_time": "起始时间",
            "end_time": "结束时间",
            "unit_ids": "执行任务的单位ID列表",
            "route": "执行此任务的途径点列表"
        },
        # 聊天信息
        {
            "actor": "int, 本方营长的席位id",
            "type": "int, 204",
            "receive_step": "int, 接收时的步数",
            "to_all": "int, 0-对队友发出,1-对所有人发出",
            "msg_body": "str",
            "msg_id": "int, 此消息的id"
        },
        # 渲染信息
        {
            "actor": "int 动作放出者",
            "type": "int, 205",
            "msg_id": "int, 此消息的id",
            "receive_step": "int, 接收时的步数",
            "to_all": "int, 0-对队友发出,1-对所有人发出",
            "msg_body": {
                "hexs": "list[int], 要渲染的六角格坐标",
                "graphic_type": "str, 渲染类型",
                "word": "str, 渲染字符",
                "color": "str, 颜色",
                "description": "str, 对于此命令的其他描述"
            }
        }
    ],
    "jm_points":  # 间瞄点信息
    [
        {
            "obj_id": "int, 攻击算子ID",
            "weapon_id": "int, 攻击武器ID",
            "pos": "int, 位置",
            "status": "int, 当前状态 0-正在飞行 1-正在爆炸 2-无效",
            "fly_time": "int, 已飞行时间",
            "boom_time": "int, 已爆炸时间"
        }
    ],
    "judge_info":  # 裁决信息
    [
  # 直瞄射击类型
  {
            "att_level": "int, 攻击等级  ",
            "att_obj_blood": "int, 攻击算子血量",
            "att_obj_id": "int, 攻击算子ID",
            "attack_color": "int, 攻击算子颜色",
            "attack_sub_type": "int, 攻击算子类型",
            "cur_step": "int, 当前步长",
            "damage": "int, 最终战损",
            "distance": "int, 距离",
            "ele_diff": "int, 高差等级",
            "ori_damage": "int, 原始战损",
            "random1": "int, 随机数1",
            "random2": "int, 随机数2",
            "random2_rect": "int, 随机数2修正值",
            "rect_damage": "int, 战损修正值",
            "target_color": "int, 目标颜色",
            "target_obj_id": "int, 目标id",
            "target_sub_type": "int, 目标类型",
            "type": "str, 直瞄射击",
            "wp_id": "int, 武器ID int"
        },
  # 间瞄射击类型
  {
            "align_status": "int, 较射类型 0-无较射 1-格内较射 2-目标较射",
            "att_obj_blood": "int, 攻击算子血量",
            "att_obj_id": "int, 攻击算子ID",
            "attack_color": "int, 攻击算子颜色",
            "attack_sub_type": "int, 攻击算子类型",
            "cur_step": "int, 当前步长",
            "damage": "int, 最终战损",
            "distance": "int, 距离",
            "ori_damage": "int, 原始战损",
            "ori_random2": "int, ",
            "offset": "bool, 偏移 bool",
            "random1": "int, 随机数1",
            "random2": "int, 随机数2",
            "random2_rect": "int, 随机数2修正值",
            "rect_damage": "int, 战损修正值",
            "target_color": "int, 目标颜色",
            "target_obj_id": "int, 目标id",
            "target_sub_type": "int, 目标类型",
            "type": "str, 间瞄射击",
            "wp_id": "int, 武器ID"
        },
  # 引导射击类型
    {
            "att_level": "int, 攻击等级",
            "att_obj_blood": "int, 攻击算子血量",
            "att_obj_id": "int, 攻击算子ID",
            "attack_color": "int, 攻击算子颜色",
            "attack_sub_type": "int, 攻击算子类型",
            "cur_step": "int, 当前步长",
            "damage": "int, 最终战损",
            "distance": "int, 距离",
            "ele_diff": "int, 高差等级",
            "guide_obj_id": "int, 引导算子ID",
            "ori_damage": "int, 原始战损",
            "random1": "int, 随机数1",
            "random2": "int, 随机数2",
            "random2_rect": "int, 随机数2修正值",
            "rect_damage": "int, 战损修正值",
            "target_color": "int, 目标颜色",
            "target_obj_id": "int, 目标id",
            "target_sub_type": "int, 目标类型",
            "type": "str, 引导射击",
            "wp_id": "int, 武器ID",
        },
  # 雷场射击类型
  {
            "target_obj_id": "int, 目标算子id",
            "target_color": "int, 目标颜色",
            "target_type": "int, 目标类型",
            "target_armor": "int, 目标护甲",
            "original_damage_random_number": "int, 原始战损随机数",
            "calibration_random_number": "int, 修正随机数",
            "calibration_value": "int, 修正值",
            "final_damage": "int, 最终战损",
            "cur_step": "int, 当前步数",
            "minefield_id": "int, 雷场id",
            "minefield_hex": "int, 雷场位置",
            "minefield_color": "int, 雷场颜色",
            "type": "str, 雷场裁决"
        }
    ],
    "landmarks": # 地标信息,雷场,路障
    {
        "roadblocks": "list[int], 六角格坐标",
        "minefields": [
            {
                "id": "int, 雷场id",
                "name": "str, 雷场",
                "hex": "int, 位置",
                "color": "int, 颜色",
                "creator": "int/None, 雷场创造者,None-想定自带雷场,int-算子创造雷场",
                "roads": [
                    {
                        "id": "int, 通路id",
                        "creator": "int, 通路制造者,int-制造通路的算子id",
                        "direction": "int, 通路方向,0~5,0是正右侧,按逆时针递进",
                        "color": "int, 通路颜色",
                        "hex": "int, 通路位置"
                    }
                ]
            }
        ]
    },
    "operators":  # 算子信息
    [
        # "算子信息":
        {
            "obj_id": "int, 算子ID",
            "color": "int, 算子阵营 0-红 1-蓝",
            "type": "int, 算子类型 1-步兵 2-车辆 3-飞机 4-工事 5-战略支援算子",
            "name": "str, 名称",
            "sub_type": "int, 细分类型 坦克 0/  战车1 / 人员2 / 炮兵3 / 无人战车4 / 无人机5 / 直升机6 / 巡飞弹7 / 运输直升机8 / 侦察型战车9 / 炮兵校射雷达车10 / 人员战斗工事11 / 车辆工事12 / 布雷车13 / 扫雷车14 / 防空高炮15 / 便携防空导弹排16 / 车载防空导弹车17 / 皮卡车18 / 天基侦察算子19 / 人员隐蔽工事20",
            "basic_speed": "int, 基础速度 int km/h",
            "armor": "int, 装甲类型 int 0-无装甲 1-轻型装甲 2-中型装甲 3-重型装甲 4-复合装甲",
            "A1": "int, 是否有行进间射击能力",
            "stack": "int, 是否堆叠",
            "carry_weapon_ids": "list[int] 携带武器ID",
            "remain_bullet_nums": "dict[int, int] 剩余弹药数 dict{弹药类型 int 0-非导弹, 100-重型导弹, 101-中型导弹, 102-小型导弹: 剩余弹药数 int}",
            "remain_bullet_nums_bk": "dict[int, int] 敌对阵营看到的弹药数",
            "guide_ability": "int, 是否有引导射击能力",
            "value": "int, 分值",
            "valid_passenger_types": "list[int], 可承载类型,代表可以装在的乘员sub_type",
            "max_passenger_nums": "dict[int, int], 最大承载数",
            "loading_capacity": "int, 车辆单位最大承载算子车班数",
            "observe_distance": "list[int], 观察距离, 一维列表,代表此算子可以观察到各个sub_type算子的最大观察距离",
            "move_state": "int, 机动状态 0-正常机动 1-行军 2-一级冲锋 3-二级冲锋 4-掩蔽 5-半速",
            "cur_hex": "int, 四位当前坐标",
            "cur_pos": "float, 当前格到下一格的百分比进度",
            "speed": "int, 当前机动速度 格/s >0: 移动中, =0: 暂停或停止 int",
            "move_to_stop_remain_time": "int, 机动转停止剩余时间 >0表示",
            "can_to_move": "int, 是否可机动标志位.只在停止转换过程中用来判断是否可以继续机动.强制停止不能继续机动,正常停止可以继续机动. 0-否 1-是",
            "flag_force_stop": "int, 是否被强制停止机动 0-否 1-是",
            "stop": "int, 是否静止 0-否, 1-是",
            "move_path": "list[int], 计划机动路径, 首个元素代表下一目标格",
            "blood": "int, 当前血量",
            "max_blood": "int, 最大血量",
            "tire": "int, 疲劳等级 0-不疲劳 1-一级疲劳 2-二级疲劳",
            "tire_accumulate_time": "int, 疲劳累积时间",
            "keep": "int, 是否被压制",
            "keep_remain_time": "int, 压制剩余时间",
            "on_board": "int, 是否在车上",
            "car": "int, 所属车辆ID",
            "launcher": "int, 算子下车/发射后,记录所属发射器",
            "passenger_ids": "list[int],乘客列表",
            "launch_ids": "list[int],记录车辆发射单元列表",
            "lose_control": "int, 算子是否失去控制(指无人车失去指挥)",
            "alive_remain_time": "int, 巡飞弹剩余存活时间",
            "get_on_remain_time": "float, 上车剩余时间",
            "get_on_partner_id": "list[int], 车辆算子ID(本算子为上车算子) 或 待上车算子(本算子为车辆算子)",
            "get_off_remain_time": "int,下车剩余时间",
            "get_off_partner_id": "list[int], 车辆算子ID(本算子为待下车算子) 或 车上算子ID(本算子为车辆算子ID)",
            "change_state_remain_time": "int, 切换状态剩余时间",
            "target_state": "int, 状态转换过程中记录目标状态 int 0-正常机动 1-行军 2-一级冲锋 3-二级冲锋 4-掩蔽",
            "weapon_cool_time": "int, 武器剩余冷却时间",
            "weapon_unfold_time": "int, 武器锁定状态表示展开剩余时间, 武器展开状态下表示锁定剩余时间",
            "weapon_unfold_state": "int, 武器状态 0-锁定 1-展开",
            "see_enemy_bop_ids": "list[int], 观察敌方算子列表",
            "owner": "int/str, 当前拥有此算子的玩家席位id",
            "close_combat": "int, 当前算子是否在同格交战中",
            "stationary_count": "int, 算子距离上次改变坐标的时间步长",
            "forking": "int, 是否在解聚",
            "forking_remain_time": "int, 解聚剩余时长",
            "unioning": "int, 算子是否在聚合",
            "unioning_remain_time": "int, 聚合剩余时间",
            "unioning_partner": "int, 聚合对象算子id",
            "unioining_role": "int, 1-聚合发起者,2-聚合被动者",
            "altitude": "int, 算子当前高度",
            "changing_altitude": "int, 是否在改变高度",
            "changing_altitude_remain_time": "int, 改变高度剩余时间",
            "target_altitude": "int, 目标高程",
            "activating_radar": "int, 是否在开启炮兵校射雷达",
            "activating_radar_remain_time": "int, 开启雷达剩余时间",
            "radar_activated": "int, 雷达是否开启",
            "in_fort": "int, 是否在工事中",
            "fort": "int, 工事id",
            "entering_fort": "int, 是否在进入工事",
            "entering_fort_remain_time": "int, 进入工事剩余时间",
            "entering_fort_partner": "list[int], 进入工事动作对象",
            "exiting_fort": "int, 是否在离开工事",
            "exiting_fort_remain_time": "int, 离开工事剩余时间",
            "exiting_fort_partner": "list[int], 离开工事动作对象",
            "fort_passengers": "list[int]工事中的算子",
            "laying_mine": "int, 是否在布雷中",
            "laying_mine_remain_time": "int, 布雷剩余时间",
            "remaining_mine_count": "int, 剩余可布雷场数",
            "laying_mine_target_pos": "int, 当前布雷目标点",
            "observalbe_distance": "int, 此算子可被观察的基础距离"
        },
        # "敌方阵营的不可见信息或部分可见的信息": 
        {
            "remain_bullet_nums": "剩余弹药数 dict{弹药类型 int 0-非导弹, 100-重型导弹, 101-中型导弹, 102-小型导弹: 剩余弹药数 int}",
            "move_to_stop_remain_time": "机动转停止剩余时间 >0表示",
            "can_to_move": "是否可机动标志位.只在停止转换过程中用来判断是否可以继续机动.强制停止不能继续机动,正常停止可以继续机动. 0-否 1-是",
            "move_path": "计划机动路径 [int] 首个元素代表下一目标格,只能观察到敌方机动的下一格,不能观察到全部路径",
            "tire_accumulate_time": "疲劳状态剩余时间 int",
            "keep_remain_time": "压制状态剩余时间 int",
            "launcher": "算子下车/发射后,记录所属发射器 int",
            "passenger_ids": "乘客列表 [int]",
            "launch_ids": "记录车辆发射单元列表 [int]",
            "alive_remain_time": "巡飞弹剩余存活时间",
            "get_on_remain_time": "上车剩余时间 float",
            "get_off_remain_time": "下车剩余时间 float",
            "weapon_unfold_time": "武器锁定状态表示展开剩余时间, 武器展开状态下表示锁定剩余时间 float",
            "see_enemy_bop_ids": "观察敌方算子列表 list(int)",
            "C2": "普通弹药数",
            "C3": "剩余导弹数",
            "target_state": "状态转换过程中记录目标状态 int 0-正常机动 1-行军 2-一级冲锋 3-二级冲锋 4-掩蔽",
        },
        # "敌方间瞄点信息": 
        {
            "obj_id": "攻击算子ID int",
            "weapon_id": "攻击武器ID int",
            "fly_time": "剩余飞行时间 float",
            "boom_time": "剩余爆炸时间 float"
        }
    ],
    "passengers": [], # 乘员信息
    "role_and_grouping_info": # 玩家信息和编组信息
    {
        #席位0
    0: {
            "faction": "int 红为0,蓝为1",
            "role": "int 分队为0,群队为1",
            "operators": "list[int],拥有的算子id",
            "user_id": "int",
            "user_name": "str"
        },
        #席位1
    1: {
            "faction": "int, 红为0,蓝为1",
            "role": "int, 分队为0,群队为1",
            "operators": "list[int], 拥有的算子id",
            "user_id": "int",
            "user_name": "str"
        },
        2: {
            "faction": "int, 红为0,蓝为1",
            "role": "int, 分队为0,群队为1",
            "operators": "list[int], 拥有的算子id",
            "user_id": "int",
            "user_name": "str"
        }
    },
    "scenario_id": 0, # 想定ID
    "scores":  # 分数
    {
        "blue_attack": "int, 蓝方攻击得分",
        "blue_occupy": "int, 蓝方夺控分",
        "blue_remain": "int, 蓝方剩余得分",
        "blue_reamin_max": "int, 蓝方最大剩余得分",
        "blue_total": "int, 蓝方总分",
        "blue_win": "int, 蓝方净胜分",
        "red_attack": "int, 红方战斗得分",
        "red_occupy": "int, 红方夺控分",
        "red_remain": "int, 红方剩余算子分",
        "red_reamin_max": "int, 红方最大剩余得分",
        "red_total": "int, 红方总分",
        "red_win": "int, 红方净胜分"
    },
    "terrain_id": 0, # 地图id
    "time":  # 时间信息
    {
        "cur_step": "int, 当前步长",
        "tick": "int, 每次step会前进多少帧",
        "max_time": "int, 最大帧数",
        "max_step": "int, 最大步数,等于max_time/tick",
        "stage": "int, 当前处于的阶段,0-环境配置阶段,1-部署阶段,2-正常推进阶段"
    },
    "valid_actions": # 当前态势下的可做动作信息
    {
        "算子ID": {
            "1-机动": "null",
            "2-射击": [
                {
                    "target_obj_id": "目标ID int",
                    "weapon_id": "武器ID int",
                    "attack_level": "攻击等级 int"
                }
            ],
            "3-上车": [
                {
                    "target_obj_id": "车辆ID int"
                }
            ],
            "4-下车": [
                {
                    "target_obj_id": "乘客ID int"
                }
            ],
            "5-夺控": "null",
            "6-切换状态": [
                {
                    "target_state": "目标状态 0-正常机动 1-行军 2-一级冲锋 3-二级冲锋 4-掩蔽"
                }
            ],
            "7-移除压制": "null",
            "8-间瞄": [
                {
                    "weapon_id": "武器ID"
                }
            ],
            "9-引导射击": [
                {
                    "guided_obj_id": "被引导算子ID int",
                    "target_obj_id": "目标算子ID",
                    "weapon_id": "武器ID int",
                    "attack_level": "攻击等级 int"
                }
            ],
            "10-停止机动": "null",
            "11-武器锁定": "null",
            "12-武器展开": "null",
            "13-取消间瞄计划": "null",
            "14-解聚": "null",
            "15-聚合": [
                {
                    "target_obj_id": "聚合对象ID int"
                }
            ],
            "16-改变高程": [
                {
                    "target_altitude": "目标高程 int"
                }
            ],
            "17-开启炮兵校射雷达": "null",
            "18-进入工事": [
                {
                    "target_obj_id": "工事ID int"
                }
            ],
            "19-退出工事": [
                {
                    "target_obj_id": "工事ID int"
                }
            ],
            "20-布雷": "null",
        },
        "如果是绿方态势中,会有绿方专属的valid_actions": {
            "401-导演击杀算子": "null",
            "402-导演布雷": "null",
            "403-导演建造路障": "null",
            "404-导演增加算子": "null"
        }
    }
}

附录3:武器相关规则json转录,方便查找

.其中“打击规则”是先得到“攻击等级”,再去换算“实际打出的伤害”,这部分比较复杂,我也没搞太懂……

"""
此处是对战规则表格的解析

"""



import json

#武器类型表
weapon_id_map = \
{
    "weapons": [
        {"name": "便携导弹", "id": 71},
        {"name": "便携导弹(对地)", "id": 5},
        {"name": "步兵轻武器", "id": 29},
        {"name": "车载导弹", "id": 69},
        {"name": "车载轻武器", "id": 43},
        {"name": "大号直瞄炮", "id": 36},
        {"name": "火箭筒", "id": 35},
        {"name": "速射炮", "id": 56},
        {"name": "速射炮(对地)", "id": 4},
        {"name": "炮射导弹", "id": 84},
        {"name": "轻型炮", "id": 89},
        {"name": "小号直瞄炮", "id": 54},
        {"name": "小型导弹", "id": 75},
        {"name": "巡飞导弹", "id": 76},
        {"name": "中号直瞄炮", "id": 37},
        {"name": "中型导弹(标准)", "id": 83},
        {"name": "中型导弹(便携)", "id": 74},
        {"name": "中型炮", "id": 88},
        {"name": "重型导弹", "id": 73},
        {"name": "重型炮", "id": 72},
        {"name": "防空高炮", "id": 1},
        {"name": "便携防空导弹", "id": 2},
        {"name": "车载防空导弹", "id": 3}
    ]
}

#武器对人员攻击等级表(攻击等级从0计算)
weapon_damage_toPerson = \
{
    "大号直瞄炮": {
        "射程": 10,
        "车/班数": {
            "1": [2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2],
            "2": [3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3],
            "3": [5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5],
            "4": [7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7]
        }
    },
    "中号直瞄炮": {
        "射程": 10,
        "车/班数": {
            "1": [2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2],
            "2": [3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3],
            "3": [5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5],
            "4": [7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7]
        }
    },
    "小号直瞄炮": {
        "射程": 10,
        "车/班数": {
            "1": [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
            "2": [2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2],
            "3": [4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4],
            "4": [5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5]
        }
    },
    "速射炮(对地)": {
        "射程": 10,
        "车/班数": {
            "1": [4, 4, 4, 4, 4, 4, 3, 3, 3, 2, 2],
            "2": [6, 6, 6, 6, 6, 6, 5, 5, 4, 4, 3],
            "3": [8, 8, 8, 8, 8, 8, 7, 7, 6, 6, 5],
            "4": [9, 9, 9, 9, 9, 9, 8, 8, 7, 7, 6]
        }
    },
    "步兵轻武器": {
        "射程": 3,
        "车/班数": {
            "1": [2, 1],
            "2": [4, 2, 1],
            "3": [6, 4, 2, 1],
            "4": [8, 5, 3, 1]
        }
    },
    "车载轻武器": {
        "射程": 10,
        "车/班数": {
            "1": [2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1],
            "2": [3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2],
            "3": [4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3],
            "4": [5, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4]
        }
    },
    "中型导弹": {
        "射程": 10,
        "车/班数": {
            "1": [4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5],
            "2": [5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6],
            "3": [7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8],
            "4": [8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9]
        }
    },
    "小型导弹": {
        "射程": 5,
        "车/班数": {
            "1": [4, 5, 5, 5, 5, 5],
            "2": [5, 6, 6, 6, 6, 6],
            "3": [7, 8, 8, 8, 8, 8],
            "4": [8, 9, 9, 9, 9, 9]
        }
    },
    "巡飞弹": {
        "射程": 2,
        "车/班数": {
            "1": [4, 5, 5],
            "2": [5, 6, 6],
            "3": [7, 8, 8],
            "4": [8, 9, 9]
        }
    }
}

#武器对车辆攻击等级表(攻击等级从0计算)
weapon_damage_toVehicle = \
{
    "大号直瞄炮": {
        "射程": 18,
        "距离(格)/攻击等级": [10, 10, 10, 10, 10, 9, 9, 9, 9, 8, 8, 8, 7, 7, 6, 5, 4, 3, 2]
    },
    "中号直瞄炮": {
        "射程": 15,
        "距离(格)/攻击等级": [10, 10, 10, 9, 9, 9, 8, 8, 7, 7, 7, 6, 5, 5, 2, 2]
    },
    "小号直瞄炮": {
        "射程": 13,
        "距离(格)/攻击等级": [10, 10, 9, 9, 8, 8, 7, 6, 6, 5, 5, 2, 2, 2]
    },
    "速射炮": {
        "射程": 10,
        "距离(格)/攻击等级": [5, 5, 4, 4, 3, 3, 3, 2, 2, 2, 2]
    },
    "火箭筒": {
        "射程": 4,
        "距离(格)/攻击等级": [6, 6, 6, 4, 2]
    },
    "便携导弹": {
        "射程": 10,
        "距离(格)/攻击等级": [7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8]
    },
    "车载导弹(炮射导弹)": {
        "射程": 20,
        "距离(格)/攻击等级": [0, 0, 5, 5, 6, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8]
    },
    "重型导弹": {
        "射程": 20,
        "距离(格)/攻击等级": [0, 0, 5, 5, 6, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8]
    },    
    "中型导弹(标准)": {
        "射程": 20,
        "距离(格)/攻击等级": [7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8]
    },
    "中型导弹(便携)": {
        "射程": 10,
        "距离(格)/攻击等级": [7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8]
    },
    "小型导弹": {
        "射程": 5,
        "距离(格)/攻击等级": [3, 3, 4, 4, 4, 4]
    },
    "巡飞弹": {
        "射程": 2,
        "距离(格)/攻击等级": [5, 5, 5]
    },

    "步兵轻武器": {
        "射程": 4,
        "车/班数": {
            "1": [2, 1, 0, 0],
            "2": [4, 2, 1, 0],
            "3": [6, 4, 2, 1],
            "4": [8, 5, 3, 1]
        }
    }
    
}

#攻击等级高度差修正
weapon_damage_height_diff = \
{
    "高度差/距离": {
        "1": [-2, -2, -1, -1, -1 , 0,  0,  0,  0,  0,  0,  0],
        "2": [-2, -2, -2, -1, -1, -1, -1,  0,  0,  0,  0,  0],
        "3": [-3, -2, -2, -2, -1, -1, -1, -1, -1,  0,  0,  0],
        "4": [-3, -3, -3, -2, -2, -1, -1, -1, -1, -1, -1,  0],
        "5": [-4, -3, -3, -3, -2, -2, -2, -1, -1, -1, -1, -1],
        "6": [-4, -4, -4, -3, -3, -2, -2, -2, -1, -1, -1, -1],
        "7": [-5, -4, -4, -4, -3, -2, -2, -2, -2, -1, -1,  1],
        "8": [-5, -5, -5, -4, -3, -3, -2, -2, -2, -2, -2, -1]
    }
}

#攻击等级转损伤值的表(简化策略:攻击等级高就行了)

#武器攻击范围表
weapon_att_range = \
{
    # "对人员"
    0: {
        "大号直瞄炮": 10,
        "中号直瞄炮": 10,
        "小号直瞄炮": 10,
        "速射炮(对地)": 10,
        "步兵轻武器": 3,
        "车载轻武器": 10,
        "中型导弹": 10,
        "小型导弹": 5,
        "巡飞弹": 2
    },
    # "对车辆"
    1: {
        "大号直瞄炮": 18,
        "中号直瞄炮": 15,
        "小号直瞄炮": 13,
        "速射炮": 10,
        "火箭筒": 4,
        "便携导弹": 10,
        "车载导弹(炮射导弹)": 20,
        "重型导弹": 20,
        "中型导弹(标准)": 20,
        "中型导弹(便携)": 10,
        "小型导弹": 5,
        "巡飞弹": 2,
        "步兵轻武器": 4
    }
}

'''
# 解析JSON对象
weapons = json.loads(weapon_data)

# 使用解析后的数据
for weapon in weapons["weapons"]:
    print(f"武器名称: {weapon['name']}, 武器ID: {weapon['id']}")

'''

#打击规则表TODO

附录4:地图对应编号(部分)

1.地图地形的

地图名称

地图编号

高原通道地形

29

中等起伏地形

94

水网稻田地形

53

山岳丛林地形

96

极简山岳丛林地形

9601

城镇居民地形

21

2. 想定的

想定编号

想定名称

地图编号

2010211129

分队级高原通道地形夺控战斗想定I

29

2010131194

分队级中等起伏地形遭遇战斗想定I

94

2010141294

分队级中等起伏地形遭遇战斗想定II

94

2030111194

群队级中等起伏地形夺控战斗想定I

94

2010431153

分队级水网稻田地形遭遇战斗想定I

53

2010441253

分队级水网稻田地形遭遇战斗想定II

53

2030331196

群队级山岳丛林地形遭遇战斗想定I

96

2030341296

群队级山岳丛林地形遭遇战斗想定II

96

201033019601

极简山岳丛林地形遭遇战斗想定I

9601

201033029601

极简山岳丛林地形遭遇战斗想定II

9601

201033039601

极简山岳丛林地形遭遇战斗想定III

9601

2020331196

群队级山岳丛林地形遭遇战斗想定I(3人)

96

2120531121

2021年群队级城镇居民地形遭遇战斗想定I

21

2120131194

2021年群队级中等起伏地形遭遇战斗想定I

94

2130511121

2021年合成群队级城镇居民地形夺控战斗想定I

21

2130511221

2021年合成群队级城镇居民地形夺控战斗想定II

21

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

超自然祈祷

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值