mirror of
https://github.com/InternLM/InternBootcamp.git
synced 2026-04-24 17:05:00 +00:00
* 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
175 lines
6.9 KiB
Python
Executable file
175 lines
6.9 KiB
Python
Executable file
"""### 谜题描述
|
||
|
||
Futoshiki is a logic puzzle played on an N×N grid where the objective is to fill each cell with a unique number from 1 to N, adhering to three core principles:
|
||
|
||
1. **Row and Column Uniqueness**:
|
||
Every row and column must contain all numbers from 1 to N exactly once, with no repetitions (similar to Sudoku).
|
||
|
||
2. **Inequality Constraints**:
|
||
Between certain pairs of adjacent cells (horizontally or vertically), there are inequality symbols (< or >). These symbols enforce relationships:
|
||
- **A > B** means the number in cell A must be greater than the number in cell B.
|
||
- **A < B** means the number in cell A must be less than the number in cell B.
|
||
The direction of the symbol determines the comparison (e.g., a \">\" between two horizontal cells means the left cell is greater; a \">\" between vertical cells means the upper cell is greater).
|
||
|
||
3. **Deductive Logic**:
|
||
The puzzle begins with some numbers pre-filled and inequalities provided. Solvers must deduce the remaining numbers by ensuring all uniqueness and inequality rules are satisfied simultaneously. Inequalities override potential number placements even if row/column uniqueness is temporarily met.
|
||
|
||
The challenge lies in balancing the constraints of uniqueness and inequalities to uniquely determine the solution.
|
||
|
||
|
||
请完成上述谜题的训练场环境类实现,包括所有必要的方法。
|
||
"""
|
||
|
||
from bootcamp import Basebootcamp
|
||
import random
|
||
import re
|
||
import ast
|
||
from typing import List, Dict, Any
|
||
|
||
class Futoshikibootcamp(Basebootcamp):
|
||
def __init__(self, size=5, inequality_prob=0.3, retain_ratio=0.3):
|
||
self.size = size
|
||
self.inequality_prob = inequality_prob
|
||
self.retain_ratio = retain_ratio
|
||
|
||
def case_generator(self) -> dict:
|
||
"""生成带有唯一解的Futoshiki谜题实例"""
|
||
solution = self._generate_latin_square()
|
||
inequalities = self._generate_inequalities(solution)
|
||
initial = self._generate_initial_grid(solution)
|
||
return {
|
||
'size': self.size,
|
||
'initial': initial,
|
||
'inequalities': inequalities
|
||
}
|
||
|
||
def _generate_latin_square(self) -> List[List[int]]:
|
||
"""生成随机拉丁方阵作为解"""
|
||
n = self.size
|
||
base_row = list(range(1, n+1))
|
||
random.shuffle(base_row)
|
||
rows = [base_row[i:] + base_row[:i] for i in range(n)]
|
||
random.shuffle(rows)
|
||
perm = list(range(1, n+1))
|
||
random.shuffle(perm)
|
||
return [[perm[x-1] for x in row] for row in rows]
|
||
|
||
def _generate_inequalities(self, solution: List[List[int]]) -> List[Dict]:
|
||
"""根据解生成不等式约束"""
|
||
inequalities = []
|
||
for i in range(self.size):
|
||
for j in range(self.size):
|
||
if j+1 < self.size and random.random() < self.inequality_prob:
|
||
a, b = solution[i][j], solution[i][j+1]
|
||
inequalities.append({
|
||
'cell1': [i, j],
|
||
'cell2': [i, j+1],
|
||
'symbol': '>' if a > b else '<'
|
||
})
|
||
if i+1 < self.size and random.random() < self.inequality_prob:
|
||
a, b = solution[i][j], solution[i+1][j]
|
||
inequalities.append({
|
||
'cell1': [i, j],
|
||
'cell2': [i+1, j],
|
||
'symbol': '>' if a > b else '<'
|
||
})
|
||
return inequalities
|
||
|
||
def _generate_initial_grid(self, solution: List[List[int]]) -> List[List[int]]:
|
||
"""生成初始谜题网格"""
|
||
n = self.size
|
||
indices = [(i, j) for i in range(n) for j in range(n)]
|
||
retain_num = int(len(indices) * self.retain_ratio)
|
||
selected = random.sample(indices, retain_num)
|
||
grid = [[0]*n for _ in range(n)]
|
||
for i, j in selected:
|
||
grid[i][j] = solution[i][j]
|
||
return grid
|
||
|
||
@staticmethod
|
||
def prompt_func(case) -> str:
|
||
"""生成面向用户的自然语言问题描述"""
|
||
prompt = [
|
||
"你是Futoshiki谜题专家,请根据以下条件解开谜题:",
|
||
"\n规则说明:",
|
||
"1. 填充1到N的整数(N为网格大小),满足:",
|
||
" - 每行和每列数字不重复",
|
||
" - 遵守所有不等式约束(>表示左边/上边数字更大)",
|
||
f"\n初始网格({case['size']}x{case['size']},0表示空格):"
|
||
]
|
||
|
||
# 添加网格可视化
|
||
for row in case['initial']:
|
||
prompt.append("[" + " ".join(str(n) if n != 0 else "_" for n in row) + "]")
|
||
|
||
# 添加不等式描述
|
||
prompt.append("\n不等式约束:")
|
||
for idx, ineq in enumerate(case['inequalities'], 1):
|
||
c1, c2 = ineq['cell1'], ineq['cell2']
|
||
direction = '右边' if c1[1]+1 == c2[1] else '下方'
|
||
prompt.append(
|
||
f"{idx}. 单元格({c1[0]}, {c1[1]}) {direction}的单元格应满足: "
|
||
f"{ineq['symbol']}"
|
||
)
|
||
|
||
prompt.append(
|
||
"\n将完整解答的二维数组放在[answer]标签内,例如:\n"
|
||
"[answer]\n"
|
||
"[[1,2,3],\n[2,3,1],\n[3,1,2]]\n"
|
||
"[/answer]"
|
||
)
|
||
return "\n".join(prompt)
|
||
|
||
@staticmethod
|
||
def extract_output(output: str) -> List[List[int]]:
|
||
"""从模型输出中提取最后一个答案块"""
|
||
answer_blocks = re.findall(
|
||
r'\[answer\](.*?)\[/answer\]',
|
||
output,
|
||
re.DOTALL
|
||
)
|
||
if not answer_blocks:
|
||
return None
|
||
|
||
try:
|
||
# 尝试解析最后一个答案块
|
||
raw_answer = answer_blocks[-1].strip()
|
||
return ast.literal_eval(raw_answer)
|
||
except (SyntaxError, ValueError):
|
||
return None
|
||
|
||
@classmethod
|
||
def _verify_correction(cls, solution: List[List[int]], case: dict) -> bool:
|
||
"""完整验证解的三个核心条件"""
|
||
n = case['size']
|
||
initial = case['initial']
|
||
inequalities = case['inequalities']
|
||
|
||
# 基础结构验证
|
||
if len(solution) != n or any(len(row)!=n for row in solution):
|
||
return False
|
||
|
||
# 预填数字验证
|
||
for i in range(n):
|
||
for j in range(n):
|
||
if initial[i][j] != 0 and solution[i][j] != initial[i][j]:
|
||
return False
|
||
|
||
# 行列唯一性验证
|
||
valid_numbers = set(range(1, n+1))
|
||
for row in solution:
|
||
if set(row) != valid_numbers:
|
||
return False
|
||
for col in zip(*solution):
|
||
if set(col) != valid_numbers:
|
||
return False
|
||
|
||
# 不等式验证
|
||
for ineq in inequalities:
|
||
i1, j1 = ineq['cell1']
|
||
i2, j2 = ineq['cell2']
|
||
a, b = solution[i1][j1], solution[i2][j2]
|
||
if not (a > b if ineq['symbol'] == '>' else a < b):
|
||
return False
|
||
|
||
return True
|