庙算兵棋推演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']来获取
4.特征提取(特征化为编码区分,以便输入神经网络)
一般使用 one-hot 编码对特征进行编码,再放到神经网络中
神经网络的输入是有形状要求的
……(这部分回头补上)
最后是附录,从官网文档整理得到,加了与demoAI的agnet里行为枚举的中英对照
吐槽:官网文档里竟然还有括号没补全的小错误!!!我给补上了。
附录:行为指令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": "对于此命令的其他描述,字符串"} }}
附录:观测状态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": # 玩家信息和编组信息{#席位00: {"faction": "int 红为0,蓝为1","role": "int 分队为0,群队为1","operators": "list[int],拥有的算子id","user_id": "int","user_name": "str"},#席位11: {"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"}}
}
相关文章:
庙算兵棋推演AI开发初探(5-数据处理)
碎碎念:这最近几个月过得那叫一个难受,研究生开题没过、需求评审会在4月和6月开了2次、7月紧接着软件设计评审会,加班干得都是文档的事情,还有开会前的会务和乱七八糟的琐事,我们干的还被规定弄的束手束脚,…...
【MyBatis】#{} 与 ${} 的区别(常见面试题)
目录 前言 预编译SQL和即时SQL 什么是预编译SQL? 什么是即时SQL? 区别 #{} 与 ${}的使用 防止SQL注入 什么是SQL注入? 原理 排序功能 模糊查询 总结#{}和${}的区别 前言 在前面的学习中,我们已经知道了如果SQL语句想…...
鸿蒙开发环境搭建-入门篇
本文章讲述如何搭建鸿蒙应用开发环境:新建工程、虚拟机运行、真机调试等。 开发工具: DevEco Studio 5.0.3.906 os系统: mac 参考文档:https://juejin.cn/post/7356143704699699227 官网鸿蒙应用开发学习文档:https://developer.huawei.com/c…...
力扣-贪心-53 最大子数组和
思路 先把每一个值都加到当前集合中,记录当前的和,直到当前记录和小于0了,再重置改记录,再次尝试累加 代码 class Solution { public:int maxSubArray(vector<int>& nums) {int res INT32_MIN;int curSum 0;for(in…...
iOS开发 网络安全
iOS开发中的网络安全 在当前的数字化时代,任何应用程序都需要重视网络安全。尤其是对于iOS应用开发者而言,确保应用与服务器之间的数据传输安全是至关重要的。接下来,我们将学习“iOS开发 网络安全”的实现过程。 流程步骤 以下是实现iOS网…...
MATLAB在投资组合优化中的应用:从基础理论到实践
引言 投资组合优化是现代金融理论中的核心问题之一,旨在通过合理配置资产,实现风险与收益的最佳平衡。MATLAB凭借其强大的数学计算能力和丰富的金融工具箱,成为投资组合优化的理想工具。本文将详细介绍如何使用MATLAB进行投资组合优化&#…...
银河麒麟系统安装mysql5.7【亲测可行】
一、安装环境 cpu:I5-10代; 主板:华硕; OS:银河麒麟V10(SP1)未激活 架构:Linux 5.10.0-9-generic x86_64 GNU/Linux mysql版本:mysql-5.7.34-linux-glibc2.12-x86_64.ta…...
自动创建spring boot应用(eclipse版本)
使用spring starter project创建项目 设置Service URL 把Service URL设置为 https://start.aliyun.com/ 如下图: 使用这个网址,创建项目更快。 选择Spring Web依赖 项目结构 mvnw和mvnw.cmd:这是maven包装器(wrapper)脚本&…...
基于Flask的第七次人口普查数据分析系统的设计与实现
【Flask】基于Flask的第七次人口普查数据分析系统的设计与实现(完整系统源码开发笔记详细部署教程)✅ 目录 一、项目简介二、项目界面展示三、项目视频展示 一、项目简介 基于Flask的人口普查可视化分析系统 二、项目界面展示 登录/注册 首页/详情 …...
DNS, domain name system
DNS 是一种应用层协议和http/https是同一等级的 其传输层主要用的是udp,也可能用tcp DNS协议完成的作用:查 域名对应的 ip DNS服务器完成的作用:存储 域名 -> ip 的映射 DNS服务器有三个等级:根DNS,顶级域DNS&…...
Linux:文件(三)
1. 磁盘 基本概念 机械磁盘在现在的计算机中基本是唯一的一个机械设备 速度较内存更慢,容量大价格便宜。 磁盘是永久性存储介质,断电后数据还在。 内存是易失性存储介质,断电后(未写入磁盘的)数据丢失。 物理存储结构 扇区:…...
DeepSeek 给我一个 DeepSeekUI 页面
接着上次分享内容 三步安装 DeepSeek 说,DeepSeek 下载好了,总不能是黑框框对话吧,总得找一个 UI 界面使用吧。 本地运行 DeepSeek 比安装 python、jdk 简单多了,本地还没装过的可以参考上次的文档安装。 于是找了几个开源的试了试…...
Java NIO与传统IO性能对比分析
Java NIO与传统IO性能对比分析 在Java中,I/O(输入输出)操作是开发中最常见的任务之一。传统的I/O方式基于阻塞模型,而Java NIO(New I/O)引入了非阻塞和基于通道(Channel)和缓冲区&a…...
054 redisson
文章目录 使用Redisson演示可重入锁读写锁信号量闭锁获取三级分类redisson分布式锁 package com.xd.cubemall.product.config;import org.redisson.Redisson; import org.redisson.api.RedissonClient; import org.redisson.config.Config; import org.springframework.context…...
C#上位机--进程和线程的区别
引言 在 C# 上位机开发中,进程和线程是两个非常重要的概念,它们在程序的运行和性能优化方面起着关键作用。理解进程和线程的区别,能够帮助开发者更好地设计和实现高效、稳定的上位机程序。本文将深入探讨 C# 上位机中进程和线程的区别&#…...
小智机器人CMakeLists编译文件解析
编译完成后,成功烧录! 这段代码是一个CMake脚本,用于配置和构建一个嵌入式项目,特别是针对ESP32系列芯片的项目。CMake是一个跨平台的构建系统,用于管理项目的编译过程。 set(SOURCES "audio_codecs/audio_code…...
【科研绘图系列】R语言绘制SCI论文图合集
禁止商业或二改转载,仅供自学使用,侵权必究,如需截取部分内容请后台联系作者! 文章目录 介绍加载R包数据下载Load dataFigure 1Fig 1B: functional assays adhensionFIG 1C: Functional assays OPK Figure 2Fig 2C: Settings and function fo…...
Luckfox Pico Max运行RKNN-Toolkit2中的Yolov5 adb USB仿真
1:下载rknn-toolkit2 git clone https://github.com/rockchip-linux/rknn-toolkit2 2:修改onnx目录下的yolov5的test.py的代码 # pre-process config print(--> Config model) rknn.config(mean_values[[0, 0, 0]], std_values[[255, 255, …...
VSCode ssh远程连接内网服务器(不能上网的内网环境的Linux服务器)的终极解决方案
VSCode ssh远程连接内网服务器(不能上网的内网环境的Linux服务器) 离线下载vscode-server并安装: 如果远程端不能联网可以下载包离线安装,下载 vscode-server 的 url 需要和 vscode 客户端版本的 commit-id 对应.通过 vscode 面板的帮助->关于可以获…...
大语言模型:从开发到运行的深度解构
一、LLM开发训练的全流程解析 1. 数据工程的炼金术 数据采集:构建涵盖网页文本(Common Crawl)、书籍、论文、代码等领域的超大规模语料库,典型规模可达数十TB。例如GPT-4的训练数据包含超过13万亿token数据清洗:通过…...
支持向量机(SVM):算法讲解与原理推导
1 SVM介绍 SVM是一个二类分类器,它的全称是Support Vector Machine,即支持向量机。 SVM的目标是找到一个超平面,使用两类数据离这个超平面越远越好,从而对新的数据分类更准确,即使分类器更加健壮。比如上面的图中&am…...
Redis 缓存穿透、击穿、雪崩:问题与解决方案
在使用 Redis 作为缓存中间件时,系统可能会面临一些常见的问题,如 缓存穿透、缓存击穿 和 缓存雪崩。这些问题如果不加以解决,可能会导致数据库压力过大、系统响应变慢甚至崩溃。本文将详细分析这三种问题的起因,并提供有效的解决…...
macos sequoia 禁用 ctrl+enter 打开鼠标右键菜单功能
macos sequoia默认ctrlenter会打开鼠标右键菜单,使得很多软件有冲突。关闭方法: end...
Android14 Camera框架中Jpeg流buffer大小的计算
背景描述 Android13中,相机框架包含对AIDL Camera HAL的支持,在Android13或更高版本中添加的相机功能只能通过AIDL Camera HAL接口使用。 对于Android应用层来说,使用API34即以后版本的Camera应用程序通过Camera AIDL Interface访问到HAL层…...
springboot系列十四: 注入Servlet, Filter, Listener + 内置Tomcat配置和切换 + 数据库操作
文章目录 注入Servlet, Filter, Listener官方文档基本介绍使用注解方式注入使用RegistrationBean方法注入DispatcherServlet详解 内置Tomcat配置和切换基本介绍内置Tomcat配置通过application.yml完成配置通过类配置 切换Undertow 数据库操作 JdbcHikariDataSource需求分析应用…...
区块链共识机制详解
区块链共识机制详解 🤝 1. 什么是共识机制? 共识机制是区块链网络中,所有节点就某个状态(如交易的有效性)达成一致的规则和过程。它解决了在去中心化网络中如何确保数据一致性的问题。 2. 主流共识机制 2.1 工作量证…...
详解单例模式、模板方法及项目和源码应用
大家好,我是此林。 设计模式为解决特定问题提供了标准化的方法。在项目中合理应用设计模式,可以避免重复解决相同类型的问题,使我们能够更加专注于具体的业务逻辑,减少重复劳动。设计模式在定义系统结构时通常考虑到未来的扩展。…...
解耦的艺术_应用架构中的解耦
文章目录 Pre解耦的技术演化应用架构中的解耦小结 Pre 解耦的艺术_通过DPI依赖倒置实现解耦 解耦的艺术_通过中间层映射实现解耦 解耦的技术演化 技术的演化史,也是一部解耦的历史。从最初的面向对象编程(OOP)到Spring框架的依赖注入&…...
Winform(C#) 项目保存页面
上一张我们已经实现了TCP和串口页面的数据展示,和保存控件 我们这一章,实现如何去,控制保存。 一、控件展示 CheckBox TextBox Button label Name: checkSaveImage checkDelete txtSaveDays txtSaveImagePath btnSelectIm…...
Ubuntu 下 nginx-1.24.0 源码分析 - ngx_array_init 函数
ngx_array_init 定义在 src/core/ngx_array.h static ngx_inline ngx_int_t ngx_array_init(ngx_array_t *array, ngx_pool_t *pool, ngx_uint_t n, size_t size) {/** set "array->nelts" before "array->elts", otherwise MSVC thinks* that "…...
