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]: """ 根据题型生成题目 """ if self.type == "A": data = self._generate_type_a() data['type'] = "A" elif self.type == "B": data = self._generate_type_b() data['type'] = "B" elif self.type == "C": data = self._generate_type_c() data['type'] = "C" elif self.type == "D": data = self._generate_type_d() data['type'] = "D" elif self.type == "E": data = self._generate_type_e() data['type'] = "E" else: self.type= random.choice(["A", "B", "C", "D", "E"]) data = self.generate() return data @classmethod def _generate_type_a(cls) -> Dict[str, Any]: """ 推理未知数:给出四个数字(1-13)算24,其中一个是x,并且x等于另外三个数(这三个数不能相同)中的一个。 要求找出x的可能值,并写出相应的算式 """ if not cls._is_cache_loaded: cls._load_cache() if not cls._cache['A']: raise ValueError("缓存中没有可用的A类型题目数据") # 从缓存中随机选择一个题目 item = random.choice(cls._cache['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 { "question": question_text, "numbers": numbers, "answers": answers } @classmethod def _generate_type_b(cls) -> Dict[str, Any]: """ 一题多解1:生成恰好有两个解法的题目 """ if not cls._is_cache_loaded: cls._load_cache() if not cls._cache['B']: raise ValueError("缓存中没有可用的B类型题目数据") # 从缓存中随机选择一个题目 item = random.choice(cls._cache['B']) numbers = item.get('numbers', []) solutions = item.get('solutions', []) question_text = "一题多解:请找出这组数字的所有24点解法。" # 转换解法格式 answers = [] for solution in solutions: answers.append({ "expression": solution.get('expression', ''), "flag": solution.get('flag', 0) }) return { "question": question_text, "numbers": numbers, "answers": answers } @classmethod def _generate_type_c(cls) -> Dict[str, Any]: """ 一题多解2:生成有三个或以上解法的题目 """ if not cls._is_cache_loaded: cls._load_cache() if not cls._cache['C']: raise ValueError("缓存中没有可用的C类型题目数据") # 从缓存中随机选择一个题目 item = random.choice(cls._cache['C']) numbers = item.get('numbers', []) solutions = item.get('solutions', []) question_text = "一题多解:请找出这组数字的所有24点解法!" # 转换解法格式 answers = [] for solution in solutions: answers.append({ "expression": solution.get('expression', ''), "flag": solution.get('flag', 0) }) return { "question": question_text, "numbers": numbers, "answers": answers } @classmethod def _generate_type_d(cls) -> Dict[str, Any]: """ 一星题目:生成包含flag=1的题目 """ if not cls._is_cache_loaded: cls._load_cache() if not cls._cache['D']: raise ValueError("缓存中没有可用的D类型题目数据") # 从缓存中随机选择一个题目 item = random.choice(cls._cache['D']) numbers = item.get('numbers', []) solutions = item.get('solutions', []) question_text = "一星题目:请找出这组数字的24点解法。" # 转换解法格式,只保留flag=1的解法 answers = [] for solution in solutions: if solution.get('flag', 0) == 1: answers.append({ "expression": solution.get('expression', ''), "flag": 1 }) return { "question": question_text, "numbers": numbers, "answers": answers } @classmethod def _generate_type_e(cls) -> Dict[str, Any]: """ 二星题目:生成包含flag=2的题目 """ if not cls._is_cache_loaded: cls._load_cache() if not cls._cache['E']: raise ValueError("缓存中没有可用的E类型题目数据") # 从缓存中随机选择一个题目 item = random.choice(cls._cache['E']) numbers = item.get('numbers', []) solutions = item.get('solutions', []) question_text = "二星题目:请找出这组数字的24点解法。" # 转换解法格式,只保留flag=2的解法 answers = [] for solution in solutions: if solution.get('flag', 0) == 2: answers.append({ "expression": solution.get('expression', ''), "flag": 2 }) return { "question": question_text, "numbers": numbers, "answers": answers }