"""# 谜题训练场开发任务 ## 任务概述 你是一位资深程序员,我需要你帮我实现一个特定谜题的训练场环境类。这个类继承自`Basebootcamp`,用于生成谜题实例并验证解答。 ## 背景说明 我正在开发一系列谜题训练场,每个训练场对应一个特定类型的谜题。训练场类命名为`{PuzzleName}bootcamp`,其中`PuzzleName`是谜题的名称。 每个训练场类主要提供两个核心功能: 1. 生成该谜题类型的问题实例 2. 验证用户对问题的回答是否正确 ## 技术接口规范 ### 类方法实现要求 ```python class {PuzzleName}bootcamp(Basebootcamp): def __init__(self, **params): \"\"\" 请你自定义params,以保存该puzzle相关的参数,例如网格大小等,参数配有默认值 \"\"\" pass def case_generator(self): \"\"\" 生成谜题实例,提示:为保证谜题有解,可以先生成结果再对结果处理得到谜题 返回:一个可JSON序列化的字典(避免包含set等无法通过json.dumps处理的数据结构) \"\"\" pass @staticmethod def prompt_func(question_case) -> str: \"\"\" 将case_generator生成的谜题实例转换为文本形式的问题,问题中包含问题背景、对谜题规则的介绍、具体要解决的谜题实例、期望最终答案的格式, 例如:你是xxxx,请你解答yyyy,规则如下:yyyy,最终答案放置在:zzzzz 参数: question_case: 由case_generator生成的谜题实例 返回: str: 格式化的问题字符串 注意: 1. 需考虑问题的格式,以便后续能正确提取 2. 问题描述中应包含期望的答案格式说明,以便后续能正确提取,为了避免抽取时匹配出干扰项,请要求模型将答案放在特定标签,如[answer] [/answer]内 \"\"\" pass @staticmethod def extract_output(output): \"\"\" 从LLM的回复中提取符合格式要求的答案,如有多个,请抽取最后一个,避免使用re.search等只抽取第一个结果的方式。 参数: output: LLM的完整输出(包含原始问题和回答) 返回: 提取的答案,若未找到符合格式的答案则返回None \"\"\" pass @classmethod def _verify_correction(cls, solution, identity): \"\"\" 验证提取的答案是否正确,注意一个问题可以能有多个解,按照谜题规则进行检验,不要直接匹配可能的答案。 参数: solution: extract_output提取的答案 identity: case_generator生成的谜题实例 返回: bool: 答案是否正确 \"\"\" pass ``` ### 验证评分方法(基类已实现) ```python @classmethod def verify_score(cls, model_output, identity:dict, format_score=0.1) -> float: \"\"\" 验证输出结果并评分。 参数: model_output: 模型的完整输出 identity: 谜题实例(由case_generator生成) format_score: 答案格式正确时的基础分数 返回: float: 评分结果(0-1之间) \"\"\" score = 0. try: extract_solution = cls.extract_output(model_output) if extract_solution is None: return score else: score = format_score # 格式正确时的基础分数 if cls._verify_correction(extract_solution, identity): score = 1. # 答案完全正确时的满分 except Exception as e: # 处理异常情况 pass return score ``` ### 使用示例 ```python # 初始化谜题训练场 bootcamp = Puzzlebootcamp() # 生成谜题实例 case = bootcamp.case_generator() # 将谜题转换为文本问题 prompt = Puzzlebootcamp.prompt_func(case) # 获取LLM对问题的解答 response = get_response(prompt, \"LLM\") # 从完整对话中提取答案 extracted_output = Puzzlebootcamp.extract_output(prompt + response) # 验证答案并评分 score = Puzzlebootcamp.verify_score(extracted_output, case) ``` ## 你的任务 请根据以下谜题描述(谜题描述可能不完整,请先结合你的知识澄清规则),实现一个完整的谜题训练场类: ### 谜题描述 Shingoki is a logic puzzle where players draw a single continuous, non-intersecting loop on a grid. Here are the core rules: 1. **Objective**: Create a closed loop that traverses *edges* of the grid (lines between dots/nodes). The loop must not branch, cross itself, or form isolated segments. 2. **Clues (Numbered Circles)**: - Numbered circles appear at *intersections* (nodes where four grid edges meet). - Each number specifies *exactly* how many of the four edges connected to that node are part of the loop. For example: - **0**: None of the four edges are used. - **2**: Exactly two edges are used (e.g., a straight line or a turn). - **3/1**: Rare, typically near grid borders where fewer edges exist. 3. **2x2 Block Restriction**: The loop must not enclose any 2x2 area entirely with its lines. This prevents \"solid blocks\" of the loop. 4. **Logical Deductions**: - The loop must form a single closed path. - Unnumbered nodes have no constraints (any number of edges can be used). - Clues override default assumptions (e.g., a \"3\" forces three edges at a node, even if it seems counterintuitive). The puzzle is solved by deducing edge usage around numbered nodes while adhering to these constraints. 请完成上述谜题的训练场环境类实现,包括所有必要的方法。 """ from bootcamp import Basebootcamp import re from typing import Dict, Set, Tuple class Shingokibootcamp(Basebootcamp): def __init__(self, rows=5, cols=5): self.rows = rows self.cols = cols def case_generator(self) -> Dict: """ 生成Shingoki谜题实例(简化的示例版本) 注意:当前示例未实现实际环生成算法,需后续完善 """ return { "rows": self.rows, "cols": self.cols, "clues": {(2, 2): 0} # 示例线索(实际实现需要有效生成) } @staticmethod def prompt_func(question_case: Dict) -> str: clues = question_case['clues'] rows = question_case['rows'] cols = question_case['cols'] prompt = [ "请解决以下Shingoki谜题:", "在{}×{}的网格中绘制一个闭合不交叉的环,满足以下条件:".format(rows, cols), "1. 环必须经过网格边线且满足2×2区块限制", "2. 数字表示相连边数(0-3)", "————————————————", "已知线索节点:" ] # 格式化线索描述 for (i, j), num in clues.items(): prompt.append(f"• 位置 ({i},{j}) 处必须连接 {num} 条边") prompt.extend([ "\n请用以下格式回答:", "[answer]", "(行坐标,列坐标,方向) 每行一个边", "示例:", "(0,0,H) # 水平边,连接(0,0)-(0,1)", "(1,2,V) # 垂直边,连接(1,2)-(2,2)", "[/answer]" ]) return "\n".join(prompt) @staticmethod def extract_output(output: str) -> Set[Tuple[int, int, str]]: # 匹配最后一个answer块 answer_blocks = re.findall(r'\[answer\](.*?)\[/answer\]', output, re.DOTALL) if not answer_blocks: return None # 解析边坐标 edges = set() pattern = re.compile(r'\((\d+),(\d+),(H|V)\)') for line in answer_blocks[-1].strip().split('\n'): match = pattern.search(line) if match: i, j, dir = int(match[1]), int(match[2]), match[3] edges.add((i, j, dir)) return edges if edges else None @classmethod def _verify_correction(cls, solution: Set[Tuple[int, int, str]], identity: Dict) -> bool: # 转存谜题参数 rows = identity['rows'] cols = identity['cols'] clues = identity['clues'] # 验证边有效性 for i, j, dir in solution: if dir == 'H' and j >= cols-1: return False # 水平边越界 if dir == 'V' and i >= rows-1: return False # 垂直边越界 # 验证线索条件 edge_set = {(dir, i, j) for (i, j, dir) in solution} for (node_i, node_j), expected in clues.items(): count = 0 # 检查四边 if ('H', node_i, node_j) in edge_set: # 右边 count += 1 if node_j > 0 and ('H', node_i, node_j-1) in edge_set: # 左边 count += 1 if ('V', node_i, node_j) in edge_set: # 下边 count += 1 if node_i > 0 and ('V', node_i-1, node_j) in edge_set: # 上边 count += 1 if count != expected: return False # TODO: 实际实现需添加以下验证 # 1. 环的连通性检查 # 2. 闭合性检查 # 3. 2×2区块限制检查 # 4. 无交叉检查 return True # 示例实现仅验证线索条件