123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279 |
- import random
- """ RedHelper
- 将关卡red文件转化为json文件
- """
- class RedHelper:
- """ 初始化 """
- def __init__(self):
- print("init helper...")
- """
- __nScrewTypes
- 模拟C++算法分配钉子的时候使用
- 钉子的种类数
- 如果screwconfig里面总共有10种钉子
- 我们挑其中的__nScrewTypes种
- 往挑好、摆好的盘子上放
- """
- self.__nScrewTypes = 3
- print(f"钉子总种类{self.__nScrewTypes}")
- """ 从red文件的dict中获取使用的模板ID """
- def get_template_IDs(self, levelData: dict) -> list:
- # ['nodeGraph']['children'][0]['children'] -> [模板, 模板, 模板...]
- # [0] 对应的是 red工程文件中的"元素" 目前只有一个
- # 关卡red文件格式:
- # 关卡1.red
- # --CCLayer
- # ------元素
- # ----------模板号
- # ----------模板号
- # ----------模板号
- template_list = levelData['nodeGraph']['children'][0]['children']
- template_id_list = [template['displayName'] for template in template_list]
- return template_id_list
- """ 从模板中获取盘子配置 """
- def get_plate_configs(self, template: dict) -> list:
- # ['nodeGraph']['children'][0]['children'] -> [盘子, 盘子, 盘子]
- # [0]对应CCNode 目前只有一个
- # 关卡模板文件格式:
- # 模板1.red
- # --CCLayer
- # ------CCNode
- # ----------盘子号
- # ----------盘子号
- # ----------盘子号
- plates = template['nodeGraph']['children'][0]['children']
- plate_configs = []
- for plate in plates:
- properties = plate['properties']
- plate_data = {'plateId': int(plate['displayName'])}
- for plate_property in properties:
- property_name = plate_property['name']
- if property_name == 'position':
- plate_data['position'] = [round(float(plate_property['value'][i]), 1) for i in range(2)]
- elif property_name == 'scale':
- plate_data['scale'] = round(float(plate_property['value']), 1)
- elif property_name == 'rotation':
- plate_data['rotate'] = round(float(plate_property['value']), 1)
- elif property_name == 'zorder':
- plate_data['zorder'] = int(plate_property['value'], 1)
- if 'position' not in plate_data:
- plate_data['position'] = [0, 0]
- # 目前大部分文件中没有后面这几个参数 除非在redream工程中设置过
- if 'scale' not in plate_data:
- plate_data['scale'] = 1.0
- if 'rotate' not in plate_data:
- plate_data['rotate'] = 0.0
- if 'zorder' not in plate_data:
- plate_data['zorder'] = 1
- plate_configs.append(plate_data)
- return plate_configs
- """ 获得盘子能容纳的最大的钉子个数 """
- def get_max_screws_of_plate(self, plate_condition: dict) -> int:
- # ['nodeGraph']['children'][0]['children'].size()
- max_screws_of_plate = len(plate_condition['nodeGraph']['children'][0]['children'])
- return max_screws_of_plate
- """
- @brief 随机选取盘子情况 返回对应情况的id
- @param max_screw_of_plate: 盘子上钉子最大个数
- @return 盘子配置情况的下标(从0开始)
- """
- def generate_condition_id(self, max_screws_of_plate) -> int:
- condition_id = random.randint(1, max_screws_of_plate)
- # -1 是因为盘子的情况配置下标从0开始
- return condition_id - 1
- """
- @brief 调整选择的盘子情况 结果要满足三消的个数
- @param plate_conditions: 被选择的盘子的数据列表
- @param conditions_selected: 被选择的盘子情况的下标列表
- @return 调整后的被选择的盘子情况的下标列表
- """
- def adjust_conditions_selected(self, plate_conditions: list, condition_selected: list) -> list:
- # print(plate_conditions)
- print(condition_selected)
- n_holes_available_of_plates = []
- for condition in plate_conditions:
- # print(condition)
- n_hole_available_of_plate = []
- for c in condition['nodeGraph']['children'][0]['children']:
- # print(len(c['children']))
- n_hole_available_of_plate.append(len(c['children']))
- n_holes_available_of_plates.append(n_hole_available_of_plate)
- # print(n_holes_available_of_plates)
- # 记录每个盘子包含多少个钉子洞
- n_holes_used_in_each_condition_selected = []
- for i in range(len(condition_selected)):
- n_holes_used_in_each_condition_selected.append(n_holes_available_of_plates[i][condition_selected[i]])
- total_holes_used = sum(n_holes_used_in_each_condition_selected)
- # print(total_holes_used)
- # 总钉子个数不满足三消条件 需要调整
- n_redundant_holes = total_holes_used % 3
- if n_redundant_holes != 0:
- # 缺少 / 多余的hole的个数
- holes_need_to_adjust = [3 - n_redundant_holes, n_redundant_holes]
- holes_delta = []
- for i in range(len(n_holes_used_in_each_condition_selected)):
- holes_delta.append([
- hole_number - n_holes_used_in_each_condition_selected[i] for hole_number in
- n_holes_available_of_plates[i]
- ])
- # print(holes_delta)
- # 减少或增加到3的倍数
- # 先简单的每个组plate找一遍 大概率可以只调整一个plate的情况就能满足3的倍数
- # TODO: 以后有复杂情况再说
- adjust_complete = False
- for delta in holes_need_to_adjust:
- for i, condition in enumerate(holes_delta):
- for j, number in enumerate(condition):
- if number == delta:
- condition_selected[i] = j
- adjust_complete = True
- break
- if adjust_complete:
- break
- if adjust_complete:
- break
- return condition_selected
- # """
- # @brief 看看是否每种钉子的出现次数都是3的倍数 不满足要调整
- # @param 每个盘子上分配的钉子种类的列表
- # @return 调整后的每个盘子上分配的钉子种类的列表
- # """
- #
- # def adjust_screws_distribution(self, screw_types_list: list) -> list:
- # screw_type_to_n_dict = {}
- # for screws_on_plate in screw_types_list:
- # for screw_id in screws_on_plate:
- # if screw_id in screw_type_to_n_dict:
- # screw_type_to_n_dict[screw_id] += 1
- # else:
- # screw_type_to_n_dict[screw_id] = 1
- #
- # # 个数需要调整的钉子的id
- # screw_need_to_adjust = {}
- # for screw_id in screw_type_to_n_dict:
- # n_delta = screw_type_to_n_dict[screw_id] % 3
- # if n_delta != 0:
- # screw_need_to_adjust[screw_id] = n_delta
- #
- # # 让所有需要调整的钉子都先向下减少到3的倍数
- # # 多出来的空位数肯定是3的倍数
- # # 再往里随机分配就好
- # for screw_id in screw_need_to_adjust:
- """
- @brief 从盘子情况数据中获得对应情况所能容纳的钉子个数的列表
- @param plate_conditions: 盘子的情况的列表
- @param condition_selected: 选择的盘子情况的下标
- @return 对应的盘子情况所能容纳钉子的个数的列表
- """
- def get_n_screw_of_conditions(self, plate_conditions: list, condition_selected: list) -> list:
- n_screw_of_conditions = []
- for i, condition_id in enumerate(condition_selected):
- n_screw_of_conditions.append(
- len(plate_conditions[i]['nodeGraph']['children'][0]['children'][condition_id]['children'])
- )
- return n_screw_of_conditions
- """
- @brief 根据盘子情况和随机挑选的情况生成盘子上摆放的钉子类型
- @param condition_selected: 随机挑选出的盘子的情况的下标
- @param n_screws_of_conditions: 被选中的盘子情况能容纳的钉子个数的列表
- @return 为被选中的盘子生成的钉子种类的ID列表
- """
- def generate_screw_types_for_plates(self, condition_selected: list, n_screws_of_conditions: list) -> list:
- total_holes = sum(n_screws_of_conditions)
- # 总分组数
- total_groups = int(total_holes / self.__nScrewTypes)
- # 随机选择钉子的组数
- screw_id_to_group_n_dict = {}
- for i in range(1, self.__nScrewTypes + 1):
- screw_id_to_group_n_dict[i] = random.randint(1, int(total_groups/self.__nScrewTypes))
- total_groups -= screw_id_to_group_n_dict[i]
- i = 1
- while total_groups > 0:
- i = i % self.__nScrewTypes + 1
- screw_id_to_group_n_dict[i] += 1
- i += 1
- total_groups -= 1
- screw_id_to_group_n_dict[1] += total_groups
- screw_types = []
- for screw_id in screw_id_to_group_n_dict:
- screw_types.extend([screw_id] * screw_id_to_group_n_dict[screw_id] * 3)
- random.shuffle(screw_types)
- ret = []
- n_screw_added = 0
- for n_screw in n_screws_of_conditions:
- ret.append([screw_types[j] for j in range(n_screw_added, n_screw_added + n_screw)])
- n_screw_added += n_screw
- return ret
- """ 为每种盘子生成钉子数据 """
- def generate_screw_configs(self, plate_condition: dict, condition_selected: int, screw_types: list) -> list:
- # ['nodeGraph']['children'][0]['children'] -> [空位, 空位, 空位...]
- condition = plate_condition['nodeGraph']['children'][0]['children'][condition_selected]
- screws = [
- {
- "screwId": screw_types[i],
- "scale": 1,
- "rotate": 0,
- "position": []
- } for i in range(len(screw_types))
- ]
- i = 0
- for hole in condition['children']:
- for hole_property in hole['properties']:
- if hole_property['name'] == 'position':
- screws[i]['position'] = [round(float(hole_property['value'][j]), 1) for j in range(2)]
- i += 1
- break
- return screws
- """ 将钉子和盘子的配置合成为最终的关卡配置 """
- def generate_final_level_config(self, plate_configs_of_this_level: list, screw_configs: list) -> dict:
- for i in range(len(plate_configs_of_this_level)):
- plate_configs_of_this_level[i]['screws'] = screw_configs[i]
- plate_position = plate_configs_of_this_level[i]['position']
- for screw in plate_configs_of_this_level[i]['screws']:
- screw['position'] = [screw['position'][j] + plate_position[j] for j in range(2)]
- final_level_config = {
- 'plateData': plate_configs_of_this_level
- }
- return final_level_config
- """
- 将plate的zorder从都是1修正为正确的数字
- """
- def correct_plate_zorders(self, plate_configs_of_this_level: list) -> list:
- plate_cnt = 1
- for plate in plate_configs_of_this_level:
- plate['zorder'] = plate_cnt
- plate_cnt += 1
- return plate_configs_of_this_level
|