render_solution
Render crossword puzzle solutions by applying answer assignments to the grid and verifying consistency across intersecting clues.
Instructions
全カギの解答を盤面へ反映し、整合性チェックを通過した描画結果を返す。
Args:
assignments (dict[str, str]): clue_id をキーとした解答文字列の辞書。setup
済みのすべてのカギに対して、黒マス以外のセルを埋める語を指定する。
各文字列は純粋なひらがなのみで構成されている必要がある。
Returns: str: 列・行番号付きで整形したグリッド文字列。交差が一致している場合のみ 返される。
Raises:
RuntimeError: setup が未実行の場合。
ValueError: 未指定または未知の clue_id がある、解答が空文字、長さ不一致、
ひらがな以外の文字が含まれている、あるいは黒マスとの衝突・既存文字との
矛盾が発生した場合。
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| assignments | Yes |
Implementation Reference
- src/server.py:402-471 (handler)The main handler function for the 'render_solution' tool, decorated with @mcp.tool(). It takes a dictionary of assignments (clue_id to hiragana answer string), validates them against the grid and clues, fills the grid, checks for conflicts, and returns a formatted grid string with row/column labels if valid.@mcp.tool() async def render_solution(assignments: dict[str, str]) -> str: """全カギの解答を盤面へ反映し、整合性チェックを通過した描画結果を返す。 Args: assignments (dict[str, str]): `clue_id` をキーとした解答文字列の辞書。`setup` 済みのすべてのカギに対して、黒マス以外のセルを埋める語を指定する。 各文字列は純粋なひらがなのみで構成されている必要がある。 Returns: str: 列・行番号付きで整形したグリッド文字列。交差が一致している場合のみ 返される。 Raises: RuntimeError: `setup` が未実行の場合。 ValueError: 未指定または未知の `clue_id` がある、解答が空文字、長さ不一致、 ひらがな以外の文字が含まれている、あるいは黒マスとの衝突・既存文字との 矛盾が発生した場合。 """ _ensure_setup() if not assignments: raise ValueError("assignments が空です。全てのカギに対する解答を指定してください。") expected_ids = set(state.clues.keys()) provided_ids = set(assignments.keys()) missing = expected_ids - provided_ids extra = provided_ids - expected_ids if missing: raise ValueError(f"未指定の clue_id があります: {sorted(missing)}") if extra: raise ValueError(f"未知の clue_id が含まれています: {sorted(extra)}") grid = [row[:] for row in state.grid] for clue_id, answer in assignments.items(): clue = state.clues[clue_id] word = answer.strip() if not word: raise ValueError(f"clue_id={clue_id} の解答が空文字です。") if len(word) != clue.length: raise ValueError(f"clue_id={clue_id} の長さが一致しません: {len(word)} ≠ {clue.length}") for char in word: code = ord(char) if not (0x3041 <= code <= 0x309F): raise ValueError(f"clue_id={clue_id} の解答にひらがな以外の文字が含まれています: {char}") for (row_idx, col_idx), char in zip(clue.positions, word): cell = grid[row_idx][col_idx] if cell == BLOCK_CELL: raise ValueError(f"clue_id={clue_id} の配置が黒マスと衝突しています。") if cell != FILLABLE_CELL and cell != char: raise ValueError(f"位置({row_idx + 1},{col_idx + 1}) で文字が衝突しました: {cell} vs {char}") grid[row_idx][col_idx] = char if not grid: return "" width = len(grid[0]) header = " " + " ".join(_to_fullwidth_number(i + 1) for i in range(width)) lines = [header] for idx, row in enumerate(grid, start=1): lines.append(f"{_to_fullwidth_number(idx)} {' '.join(row)}") return "\n".join(lines)