from typing import List, Optional, Dict, Any import random class Question: """ 问题类,用于生成不同类型的24点题目 """ # 缓存数据 _cache = { 'A': [], # 推理未知数题目 'B': [], # 恰好有两个解法的题目 'C': [], # 有三个或以上解法的题目 'D': [], # 包含flag=1的题目 'E': [] # 包含flag=2的题目 } _is_cache_loaded = False def __init__(self, q_type: str): self.type = q_type self.question = "" self.numbers: List[Optional[int]] = [] self.answers: List[Any] = [] # 确保缓存已加载 if not Question._is_cache_loaded: Question._load_cache() @classmethod def _load_cache(cls): """ 从core.load模块加载缓存数据并按题型和特性分类 """ try: # 初始化缓存结构 cls._cache = { 'A': [], # 推理未知数题目 'B': [], # 恰好有两个解法的题目 'C': [], # 有三个或以上解法的题目 'D': [], # 包含flag=1的题目 'E': [] # 包含flag=2的题目 } # 从core.load模块获取数据 from core.load import all_data data = all_data # 分类处理数据 for item in data: # 从GameDataDTO构建numbers数组 numbers = [item.num1, item.num2, item.num3, item.num4] solutions = item.solutions # 转换解法格式 formatted_solutions = [] for sol in solutions: formatted_solutions.append({ 'expression': sol.expression, 'flag': sol.flag }) # 构建标准格式的题目数据 formatted_item = { 'id': item.id, 'no': item.no, 'numbers': numbers, 'solutions': formatted_solutions } if not solutions: continue # 计算解法数量和最高flag值 solution_count = len(solutions) max_flag = max([sol.flag for sol in solutions], default=0) # 分类存储 # 类型A:推理未知数题目 - 只有4个数字中有两个相同的题目才可以用于类型A # 检查numbers中是否有两个相同的数字 num_count = {} for num in numbers: num_count[num] = num_count.get(num, 0) + 1 has_duplicate = any(count == 2 for count in num_count.values()) if solution_count > 0 and has_duplicate: cls._cache['A'].append(formatted_item) # 类型B:恰好有两个解法的题目 if solution_count == 2: cls._cache['B'].append(formatted_item) # 类型C:有三个或以上解法的题目 if solution_count >= 3: cls._cache['C'].append(formatted_item) # 类型D:包含flag=1的题目 if max_flag == 1: cls._cache['D'].append(formatted_item) # 类型E:包含flag=2的题目 if max_flag == 2: cls._cache['E'].append(formatted_item) cls._is_cache_loaded = True print(f"缓存加载完成,各类型题目数量:A:{len(cls._cache['A'])}, B:{len(cls._cache['B'])}, C:{len(cls._cache['C'])}, D:{len(cls._cache['D'])}, E:{len(cls._cache['E'])}") except Exception as e: print(f"加载缓存数据失败: {e}") cls._is_cache_loaded = False def generate(self) -> Dict[str, Any]: """ 根据题型生成题目 """ valid_types = ["A", "B", "C", "D", "E"] # 如果类型无效,随机选择一个有效类型 if self.type not in valid_types: self.type = random.choice(valid_types) return self.generate() # 调用对应类型的生成方法 generator_method = getattr(self, f"_generate_type_{self.type.lower()}") data = generator_method() data['type'] = self.type return data @classmethod def _ensure_cache_loaded(cls, cache_type: str) -> None: """ 确保缓存已加载,并验证指定类型的缓存是否有可用数据 """ if not cls._is_cache_loaded: cls._load_cache() if not cls._cache[cache_type]: raise ValueError(f"缓存中没有可用的{cache_type}类型题目数据") @classmethod def _get_random_item(cls, cache_type: str) -> Dict[str, Any]: """ 从指定类型的缓存中随机获取一个题目 """ cls._ensure_cache_loaded(cache_type) return random.choice(cls._cache[cache_type]) @classmethod def _format_solutions(cls, solutions: List[Dict], flag_value: Optional[int] = None) -> List[Dict]: """ 统一格式化解法数据 如果指定了flag_value,则只保留该flag值的解法 """ answers = [] for solution in solutions: # 如果指定了flag值且当前解法的flag不匹配,则跳过 if flag_value is not None and solution.get('flag', 0) != flag_value: continue answers.append({ "expression": solution.get('expression', ''), "flag": flag_value if flag_value is not None else solution.get('flag', 0) }) return answers @classmethod def _create_question_result(cls, question_text: str, numbers: List, answers: List) -> Dict[str, Any]: """ 创建标准格式的问题结果对象 """ return { "question": question_text, "numbers": numbers, "answers": answers } @classmethod def _generate_type_a(cls) -> Dict[str, Any]: """ 推理未知数:给出四个数字(1-13)算24,其中一个是x,并且x等于另外三个数(这三个数不能相同)中的一个。 要求找出x的可能值,并写出相应的算式 """ # 获取随机题目 item = cls._get_random_item('A') original_numbers = item.get('numbers', []) solutions = item.get('solutions', []) if len(original_numbers) != 4 or not solutions: raise ValueError("缓存数据格式不正确") # 找出重复的数字和不重复的数字 num_count = {} for num in original_numbers: num_count[num] = num_count.get(num, 0) + 1 # 找出重复的数字(出现次数为2的数字) duplicate_num = None for num, count in num_count.items(): if count == 2: duplicate_num = num break if duplicate_num is None: raise ValueError("A类型题目数据中没有重复的数字") # 收集三个不同的数字(包括重复的那个数字) distinct_nums = [] for num in num_count.keys(): if num not in distinct_nums: distinct_nums.append(num) if len(distinct_nums) >= 3: break # 随机选择一个位置放置未知数 unknown_pos = random.randint(0, 3) numbers = distinct_nums.copy() numbers.insert(unknown_pos, None) # None 表示未知数 x # 构造答案 answers = [] for possible_x in distinct_nums: # 构建排序后的测试数字组合 test_numbers = sorted([n if n is not None else possible_x for n in numbers]) test_no = f"{test_numbers[0]}_{test_numbers[1]}_{test_numbers[2]}_{test_numbers[3]}" # 收集当前x值的所有解法 for item in cls._cache['A']: if item.get('no', "") == test_no: solution = item.get('solutions', []) # 使用正确的 join 方法 solution_str = ", ".join([sol['expression'] for sol in solution]) answers.append(f"当X={possible_x}时,解法为:{solution_str}") # 构造问题文本 question_text = "推理未知数:给出四个数字算24点,其中一个是未知数x,且x等于另外三个数中的一个。请找出x的可能值,并写出对应算式。" if len(answers)>1: question_text += f"(共有{len(answers)}个答案,请写全)" return cls._create_question_result(question_text, numbers, answers) @classmethod def _generate_type_b(cls) -> Dict[str, Any]: """ 一题多解1:生成恰好有两个解法的题目 """ # 获取随机题目 item = cls._get_random_item('B') numbers = item.get('numbers', []) solutions = item.get('solutions', []) question_text = "一题多解:请找出这组数字的所有24点解法。" # 格式化解法 answers = cls._format_solutions(solutions) return cls._create_question_result(question_text, numbers, answers) @classmethod def _generate_type_c(cls) -> Dict[str, Any]: """ 一题多解2:生成有三个或以上解法的题目 """ # 获取随机题目 item = cls._get_random_item('C') numbers = item.get('numbers', []) solutions = item.get('solutions', []) question_text = "一题多解:请找出这组数字的所有24点解法!" # 格式化解法 answers = cls._format_solutions(solutions) return cls._create_question_result(question_text, numbers, answers) @classmethod def _generate_type_d(cls) -> Dict[str, Any]: """ 一星题目:生成包含flag=1的题目 """ # 获取随机题目 item = cls._get_random_item('D') numbers = item.get('numbers', []) solutions = item.get('solutions', []) question_text = "【一星】题目:请找出这组数字的24点解法。" # 格式化解法,只保留flag=1的解法 answers = cls._format_solutions(solutions, flag_value=1) return cls._create_question_result(question_text, numbers, answers) @classmethod def _generate_type_e(cls) -> Dict[str, Any]: """ 二星题目:生成包含flag=2的题目 """ # 获取随机题目 item = cls._get_random_item('E') numbers = item.get('numbers', []) solutions = item.get('solutions', []) question_text = "【二星】题目:请找出这组数字的24点解法。" # 格式化解法,只保留flag=2的解法 answers = cls._format_solutions(solutions, flag_value=2) return cls._create_question_result(question_text, numbers, answers)