InternBootcamp/internbootcamp/bootcamp/slitherlink/slitherlink_default.py
2025-05-23 15:27:15 +08:00

290 lines
9.4 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.

import ast
import json
import random
import re
from typing import Dict, List, Any, Tuple, Optional
from internbootcamp.bootcamp.base import Basebootcamp
from internbootcamp.libs.slitherlink.slitherlink_generator import SlitherlinkSolver, generate_puzzle
from internbootcamp.libs.slitherlink.slitherlink_verifier import verify_puzzle
class Slitherlinkbootcamp(Basebootcamp):
"""
Slitherlink谜题解决系统用于生成谜题、提供提示和验证解答
"""
def __init__(self, size: Tuple[int, int] = (5, 5), difficulty: str = 'medium', seed: Optional[int] = None):
"""
初始化Slitherlink解答系统
Args:
size: 谜题大小,(行数,列数)
difficulty: 难度级别 ('easy','medium','hard')
seed: 随机种子,用于生成可重复的谜题
"""
self.size = tuple(size)
self.difficulty = difficulty
self.grid = None
self.solution = None
self.seed = seed
if seed is not None:
random.seed(seed)
def case_generator(self) -> Dict[str, Any]:
"""
生成一个Slitherlink谜题
返回:
包含谜题信息的字典
"""
rows, cols = self.size
# 调用现有的generate_puzzle函数生成谜题
puzzle = generate_puzzle(rows, cols, self.difficulty)
# 确保谜题有解
solver = SlitherlinkSolver()
solver.cells = puzzle
solver.height = rows
solver.width = cols
if solver.solve():
identity = {
'grid': puzzle,
'size': self.size,
'difficulty': self.difficulty,
'solution': solver.solution,
'seed': self.seed
}
return identity
else:
# 如果无解则重新生成
return self.case_generator()
@staticmethod
def extract_output(output: str) -> List[int]:
"""
从模型输出中提取解答
Args:
output: 模型输出的文本
Returns:
边的列表
"""
pattern = r'```json\s*([\s\S]*?)\s*```'
matches = re.findall(pattern, output)
if matches:
python_str = matches[-1]
try:
# 尝试解析为Python对象
result = ast.literal_eval(python_str.strip())
if isinstance(result, list):
return result
return []
except Exception:
# 如果解析失败,尝试查找数字列表
number_pattern = r'\[([0-9, ]+)\]'
number_matches = re.findall(number_pattern, python_str)
if number_matches:
try:
return [int(x.strip()) for x in number_matches[0].split(',')]
except:
return []
return []
@staticmethod
def print_puzzle_str(identity: Dict[str, Any]) -> str:
"""
返回谜题的字符串表示
Args:
identity: 包含谜题信息的字典
Returns:
谜题的字符串表示
"""
if identity.get('grid') is None:
return "没有谜题可显示"
result = "Slitherlink谜题:\n"
for row in identity['grid']:
line = ""
for cell in row:
line += str(cell) if cell is not None else "."
result += line + "\n"
return result
@staticmethod
def visualize_solution(identity: Dict[str, Any], solution: List[int]) -> str:
"""
可视化解决方案
Args:
identity: 包含谜题信息的字典
solution: 解决方案(边的列表)
Returns:
解决方案的可视化字符串
"""
rows, cols = identity['size']
grid = identity['grid']
# 创建点的网格 (rows+1) x (cols+1)
points = [['.' for _ in range(cols + 1)] for _ in range(rows + 1)]
# 创建水平边和垂直边的网格
h_edges = [[' ' for _ in range(cols)] for _ in range(rows + 1)]
v_edges = [[' ' for _ in range(cols + 1)] for _ in range(rows)]
# 填充解决方案中的边
for edge in solution:
edge = edge - 1 # 调整索引假设边从1开始编号
vert_edges = rows * (cols + 1)
if edge < vert_edges:
# 垂直边
edge_row = edge // (cols + 1)
edge_col = edge % (cols + 1)
v_edges[edge_row][edge_col] = '|'
else:
# 水平边
edge -= vert_edges
edge_row = edge // cols
edge_col = edge % cols
h_edges[edge_row][edge_col] = '-'
# 生成可视化输出
result = "解决方案:\n"
for i in range(rows + 1):
# 打印水平边
h_line = ""
for j in range(cols + 1):
h_line += points[i][j]
if j < cols:
h_line += h_edges[i][j]
result += h_line + "\n"
# 打印垂直边和数字
if i < rows:
v_line = ""
for j in range(cols + 1):
v_line += v_edges[i][j]
if j < cols:
cell_value = grid[i][j]
v_line += str(cell_value) if cell_value is not None else " "
result += v_line + "\n"
return result
@classmethod
def prompt_func(cls, identity: Dict[str, Any]) -> str:
"""
生成提示信息
Args:
identity: 包含谜题信息的字典
Returns:
提示信息字符串
"""
statements = [
f"""你是一个擅长解决Slitherlink谜题的智能助手。以下是一个Slitherlink谜题请找出解决方案。
Slitherlink规则
1. 在点之间连线形成一个单一的闭环
2. 线不能交叉或分叉
3. 每个数字表示该格子周围经过的线段数量
4. 空格子(标记为.可以经过任意数量的线段0-4
谜题如下:
{cls.print_puzzle_str(identity)}
请给出解决方案以边的列表形式表示。边的编号从1开始先从左到右、从上到下编号所有垂直边然后从左到右、从上到下编号所有水平边。
请确保你的解决方案形成一个单一的闭环,不包含任何交叉或分叉。
""",
f"""You are an intelligent assistant specializing in solving Slitherlink puzzles. Below is a Slitherlink puzzle that needs to be solved.
Slitherlink Rules:
1. Connect dots with lines to form a single closed loop
2. Lines cannot cross or branch
3. Numbers indicate how many lines surround that cell
4. Empty cells (marked with .) can be surrounded by any number of lines (0-4)
The puzzle is as follows:
{cls.print_puzzle_str(identity)}
Please provide the solution as a list of edges. Edges are numbered starting from 1, first numbering all vertical edges from left to right, top to bottom, then all horizontal edges from left to right, top to bottom.
Make sure your solution forms a single closed loop without any crossings or branches.
"""
]
instruction_following = """\nLet's think step by step and output the final answer with an example markdown formatting:
Final-answer: ```json
[edge1, edge2, edge3, edge4, edge5, ... , edgeN]
]
```"""
return statements[random.randint(0, len(statements) - 1)] + instruction_following
@classmethod
def _verify_correction(cls, solution: List[int], identity: Dict[str, Any]) -> bool:
"""
验证解决方案是否正确
Args:
solution: 解决方案(边的列表)
identity: 包含谜题信息的字典
Returns:
解决方案是否正确
"""
if not solution:
return False
solver = SlitherlinkSolver()
solver.cells = identity['grid']
solver.height = identity['size'][0]
solver.width = identity['size'][1]
# 验证单元格约束
for row in range(solver.height):
for col in range(solver.width):
cell_value = solver.cells[row][col]
if cell_value is not None:
# 获取单元格周围的边
cell_id = row * solver.width + col
edges = solver.get_cell_edges(cell_id)
# 计算解决方案中包含的边数
edge_count = sum(1 for edge in edges if edge + 1 in solution)
# 验证边数是否与单元格值匹配
if edge_count != cell_value:
return False
# 验证是否形成有效的闭环
return solver.validate(solution)
if __name__ == '__main__':
# 单元测试
slitherlink_bootcamp = Slitherlinkbootcamp(size=(5, 5), difficulty='medium')
identity = slitherlink_bootcamp.case_generator()
print(slitherlink_bootcamp.prompt_func(identity))
# 使用正确的解决方案进行测试
solution = identity['solution']
fake_output = f"""\n经过分析,
Final-answer: ```json
{solution}
```"""
print(fake_output)
# 可视化解决方案
print(slitherlink_bootcamp.visualize_solution(identity, solution))
print("Is it correct? ", slitherlink_bootcamp.verify_score(fake_output, identity))