mirror of
https://github.com/InternLM/InternBootcamp.git
synced 2026-04-23 16:55:02 +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
155 lines
5.9 KiB
Python
Executable file
155 lines
5.9 KiB
Python
Executable file
"""### 谜题描述
|
||
|
||
Hitori is a logic puzzle played on a square grid where each cell contains a number. The objective is to shade (blacken) cells according to the following rules:
|
||
|
||
1. **No Duplicates in Rows/Columns**:
|
||
After shading, all *unshaded* numbers in every row and column must be unique. This means duplicates in the original grid must be resolved by shading some occurrences, ensuring no repeats in the final unshaded cells.
|
||
|
||
2. **Shaded Cells Cannot Be Adjacent**:
|
||
No two shaded cells may be directly adjacent to each other horizontally or vertically (diagonally is allowed).
|
||
|
||
3. **Unshaded Cells Must Be Connected**:
|
||
All unshaded cells must form a single continuous region connected orthogonally (horizontally or vertically). Unshaded cells cannot be isolated from the rest by shaded cells.
|
||
|
||
To solve the puzzle, shade cells strategically to eliminate duplicate numbers while adhering to adjacency and connectivity constraints.
|
||
|
||
|
||
请完成上述谜题的训练场环境类实现,包括所有必要的方法。
|
||
"""
|
||
|
||
from bootcamp import Basebootcamp
|
||
import random
|
||
import re
|
||
import ast
|
||
|
||
class Hitoribootcamp(Basebootcamp):
|
||
def __init__(self, size=5, number_range=None):
|
||
super().__init__()
|
||
self.size = size
|
||
self.number_range = number_range if number_range else (1, size)
|
||
|
||
def case_generator(self):
|
||
size = self.size
|
||
grid = self._generate_latin_square(size)
|
||
shaded_cells = self._generate_valid_shaded_cells(size)
|
||
|
||
for i, j in shaded_cells:
|
||
unshaded_row = [(i, c) for c in range(size) if (i, c) not in shaded_cells and c != j]
|
||
unshaded_col = [(r, j) for r in range(size) if (r, j) not in shaded_cells and r != i]
|
||
if unshaded_row:
|
||
sample_cell = random.choice(unshaded_row)
|
||
grid[i][j] = grid[sample_cell[0]][sample_cell[1]]
|
||
elif unshaded_col:
|
||
sample_cell = random.choice(unshaded_col)
|
||
grid[i][j] = grid[sample_cell[0]][sample_cell[1]]
|
||
|
||
return {"grid": grid}
|
||
|
||
def _generate_valid_shaded_cells(self, size):
|
||
shaded = set()
|
||
candidates = [(i, j) for i in range(size) for j in range(size)]
|
||
random.shuffle(candidates)
|
||
|
||
for cell in candidates:
|
||
i, j = cell
|
||
adjacent = any((i + di, j + dj) in shaded for di, dj in [(-1,0), (1,0), (0,-1), (0,1)] if 0 <= i + di < size and 0 <= j + dj < size)
|
||
if adjacent:
|
||
continue
|
||
shaded.add(cell)
|
||
if not self._is_connected(size, shaded):
|
||
shaded.remove(cell)
|
||
return shaded
|
||
|
||
def _is_connected(self, size, shaded):
|
||
unshaded = [(i, j) for i in range(size) for j in range(size) if (i, j) not in shaded]
|
||
if not unshaded:
|
||
return False
|
||
visited = set()
|
||
queue = [unshaded[0]]
|
||
while queue:
|
||
cell = queue.pop(0)
|
||
if cell in visited:
|
||
continue
|
||
visited.add(cell)
|
||
i, j = cell
|
||
for di, dj in [(-1,0), (1,0), (0,-1), (0,1)]:
|
||
ni, nj = i + di, j + dj
|
||
if 0 <= ni < size and 0 <= nj < size and (ni, nj) not in shaded and (ni, nj) not in visited:
|
||
queue.append((ni, nj))
|
||
return len(visited) == len(unshaded)
|
||
|
||
@staticmethod
|
||
def _generate_latin_square(size):
|
||
return [[(i + j) % size + 1 for j in range(size)] for i in range(size)]
|
||
|
||
@staticmethod
|
||
def prompt_func(question_case):
|
||
grid = question_case["grid"]
|
||
grid_str = "\n".join([" ".join(map(str, row)) for row in grid])
|
||
return f"""你是一名Hitori谜题专家,请根据以下规则解决谜题:
|
||
|
||
规则:
|
||
1. 每行每列未涂黑数字必须唯一。
|
||
2. 涂黑单元格不能相邻(上下左右)。
|
||
3. 所有未涂黑单元格必须连通。
|
||
|
||
题目网格:
|
||
{grid_str}
|
||
|
||
请将答案的单元格坐标列表(从0开始)放在[answer]和[/answer]之间,例如:[answer][(0,1), (2,3)][/answer]"""
|
||
|
||
@staticmethod
|
||
def extract_output(output):
|
||
matches = re.findall(r'\[answer\](.*?)\[/answer\]', output, re.DOTALL)
|
||
if not matches:
|
||
return None
|
||
try:
|
||
result = ast.literal_eval(matches[-1].strip())
|
||
if isinstance(result, list) and all(isinstance(cell, tuple) and len(cell) == 2 for cell in result):
|
||
return result
|
||
except:
|
||
pass
|
||
return None
|
||
|
||
@classmethod
|
||
def _verify_correction(cls, solution, identity):
|
||
if not isinstance(solution, list):
|
||
return False
|
||
grid = identity["grid"]
|
||
size = len(grid)
|
||
shaded = set(solution)
|
||
|
||
if len(shaded) != len(solution):
|
||
return False
|
||
|
||
for i, j in shaded:
|
||
if not (0 <= i < size and 0 <= j < size):
|
||
return False
|
||
for di, dj in [(-1,0), (1,0), (0,-1), (0,1)]:
|
||
if (i + di, j + dj) in shaded:
|
||
return False
|
||
|
||
unshaded = [(i, j) for i in range(size) for j in range(size) if (i, j) not in shaded]
|
||
for i in range(size):
|
||
row = [grid[r][c] for r, c in unshaded if r == i]
|
||
if len(row) != len(set(row)):
|
||
return False
|
||
col = [grid[r][c] for r, c in unshaded if c == i]
|
||
if len(col) != len(set(col)):
|
||
return False
|
||
|
||
if not unshaded:
|
||
return False
|
||
visited = set()
|
||
queue = [unshaded[0]]
|
||
while queue:
|
||
cell = queue.pop(0)
|
||
if cell in visited:
|
||
continue
|
||
visited.add(cell)
|
||
i, j = cell
|
||
for di, dj in [(-1,0), (1,0), (0,-1), (0,1)]:
|
||
ni, nj = i + di, j + dj
|
||
if (ni, nj) in unshaded and (ni, nj) not in visited:
|
||
queue.append((ni, nj))
|
||
return len(visited) == len(unshaded)
|