InternBootcamp/internbootcamp/bootcamp/shingoki/shingoki.py
Yongkang Chen a8249acc18
update to tech report version (#10)
* feat(run_eval): add checkpoint resume functionality and update example documentation;
- update new bootcamp benchmark dataset

* refactor(data_pipeline): optimize data generation pipeline; add multiple preset configurations for data generation

* docs: update bootcamp list and add new scripts

- Update Fulllist_InternBootcamp.md with new bootcamps and categories
- Add new scripts to .gitignore:
  - examples/pipelines/filter_autogen_configs.py
  - examples/pipelines/quickgen_data_configs_from_eval_meta.py
- Update dependencies in setup.py:
  - Add scipy and scikit-learn

* refactor(internbootcamp): update bootcamp modules and improve error handling

- Update import statements in __init__.py files
- Add timestamp to target directory name in verl_data_preprocess.py
- Improve error handling and scoring logic in bootcamp_judger.py
- Remove unnecessary comments and update puzzle descriptions in multiple files
2025-08-28 12:39:47 +08:00

133 lines
5.1 KiB
Python
Executable file
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""### 谜题描述
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 # 示例实现仅验证线索条件