claude codeに数独の回答をさせるコードを考えさせてみた
今回は昨日公開した記事の続編になります。昨日は数独の問題を自動で生成させるコードをclaude codeにて実装させましたが、今回はその問題ファイルを読み込んで計算させるコードを作らせてみました。昨日の記事は以下になりますのでぜひ合わせてご覧ください。
早速やってみる!
プロンプト!
今回入力したプロンプトは以下になります。
@problem_1.txt のようなフォーマットで入力される数独の回答を導くコードをPythonでかいて。結果はsolve_<ナンバリング>.txtで
昨日作成していた問題ファイルはproblem_<番号>.txtのフォーマットで作成されるようにしていたので、そのサンプルを@problem_1.txt
のようにしてclaude codeに読み込ませて、同じナンバリングで回答を作成させるようにしてみました。
実行結果
まずは生成されたコードは以下になります。
sudoku_solver.py
#!/usr/bin/env python3
import re
import sys
import datetime
import os
def parse_sudoku_file(filename):
with open(filename, 'r') as f:
lines = f.readlines()
puzzle_number = None
difficulty = None
generated_time = None
grid = []
for line in lines:
line = line.strip()
if "Sudoku Puzzle #" in line:
match = re.search(r'#(\d+)', line)
if match:
puzzle_number = match.group(1)
elif "Difficulty:" in line:
difficulty = line.split("Difficulty:")[1].strip()
elif "Generated:" in line:
generated_time = line.split("Generated:")[1].strip()
elif "|" in line and not line.startswith("-"):
row_values = []
parts = line.split("|")
for part in parts:
cells = part.strip().split()
for cell in cells:
if cell == ".":
row_values.append(0)
else:
row_values.append(int(cell))
grid.append(row_values)
return puzzle_number, difficulty, generated_time, grid
def is_valid(grid, row, col, num):
for j in range(9):
if grid[row][j] == num:
return False
for i in range(9):
if grid[i][col] == num:
return False
box_row, box_col = 3 * (row // 3), 3 * (col // 3)
for i in range(box_row, box_row + 3):
for j in range(box_col, box_col + 3):
if grid[i][j] == num:
return False
return True
def solve_sudoku(grid):
for i in range(9):
for j in range(9):
if grid[i][j] == 0:
for num in range(1, 10):
if is_valid(grid, i, j, num):
grid[i][j] = num
if solve_sudoku(grid):
return True
grid[i][j] = 0
return False
return True
def format_grid(grid):
formatted = []
for i in range(9):
row = ""
for j in range(9):
row += str(grid[i][j]) + " "
if j == 2 or j == 5:
row += "| "
formatted.append(row.strip())
if i == 2 or i == 5:
formatted.append("-" * 21)
return "\n".join(formatted)
def write_solution(puzzle_number, difficulty, generated_time, grid, output_filename):
with open(output_filename, 'w') as f:
f.write(f"Sudoku Puzzle #{puzzle_number} - Solution\n")
f.write(f"Difficulty: {difficulty}\n")
f.write(f"Generated: {generated_time}\n")
f.write(f"Solved: {datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n")
f.write("=" * 30 + "\n\n")
f.write(format_grid(grid))
f.write("\n")
def create_log(puzzle_number, difficulty, success, log_dir="./claude/log"):
os.makedirs(log_dir, exist_ok=True)
log_filename = os.path.join(log_dir, f"sudoku_solver_{datetime.datetime.now().strftime('%Y%m%d_%H%M%S')}.log")
with open(log_filename, 'w') as f:
f.write(f"Sudoku Solver Execution Log\n")
f.write(f"{'=' * 30}\n")
f.write(f"Timestamp: {datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n")
f.write(f"Puzzle Number: {puzzle_number}\n")
f.write(f"Difficulty: {difficulty}\n")
f.write(f"Status: {'Success' if success else 'Failed'}\n")
f.write(f"Input File: problem_{puzzle_number}.txt\n")
f.write(f"Output File: solve_{puzzle_number}.txt\n")
return log_filename
def main():
if len(sys.argv) > 1:
input_file = sys.argv[1]
else:
input_file = "problem_1.txt"
try:
puzzle_number, difficulty, generated_time, grid = parse_sudoku_file(input_file)
print(f"Solving Sudoku Puzzle #{puzzle_number}...")
print(f"Difficulty: {difficulty}")
if solve_sudoku(grid):
output_file = f"solve_{puzzle_number}.txt"
write_solution(puzzle_number, difficulty, generated_time, grid, output_file)
print(f"Solution saved to {output_file}")
log_file = create_log(puzzle_number, difficulty, True)
print(f"Execution log saved to {log_file}")
return 0
else:
print("No solution found!")
log_file = create_log(puzzle_number, difficulty, False)
print(f"Execution log saved to {log_file}")
return 1
except Exception as e:
print(f"Error: {str(e)}")
return 1
if __name__ == "__main__":
sys.exit(main())
実装日てですが、以下で入力の問題をパースします。入力ファイルは合わせて以下に載せているようなフォーマットで取得されますが、余分な情報が記載されているのでパースする必要があります。
def parse_sudoku_file(filename):
with open(filename, 'r') as f:
lines = f.readlines()
puzzle_number = None
difficulty = None
generated_time = None
grid = []
for line in lines:
line = line.strip()
if "Sudoku Puzzle #" in line:
match = re.search(r'#(\d+)', line)
if match:
puzzle_number = match.group(1)
elif "Difficulty:" in line:
difficulty = line.split("Difficulty:")[1].strip()
elif "Generated:" in line:
generated_time = line.split("Generated:")[1].strip()
elif "|" in line and not line.startswith("-"):
row_values = []
parts = line.split("|")
for part in parts:
cells = part.strip().split()
for cell in cells:
if cell == ".":
row_values.append(0)
else:
row_values.append(int(cell))
grid.append(row_values)
return puzzle_number, difficulty, generated_time, grid
problem_1.txt
Sudoku Puzzle #1
Difficulty: low
Generated: 2025-09-30 20:19:48
==============================
. 8 9 | 3 . 2 | 5 . .
6 5 . | . . . | 1 2 .
. . 1 | 6 8 5 | . 3 .
---------------------
5 . 7 | 1 3 8 | . . 2
3 6 . | 5 9 . | 8 4 1
9 . 8 | . . 4 | . 5 3
---------------------
. . . | 8 5 3 | 6 1 .
. 7 5 | 9 2 . | . 8 .
. 3 . | 7 4 1 | 2 9 .
それ以外で言うと、以下が実際に解いている場所になります。かなりゴリ押しというか、ネストされたforを利用して当てはまる数値を探しています。
def solve_sudoku(grid):
for i in range(9):
for j in range(9):
if grid[i][j] == 0:
for num in range(1, 10):
if is_valid(grid, i, j, num):
grid[i][j] = num
if solve_sudoku(grid):
return True
grid[i][j] = 0
return False
return True
試しにコードを実行した結果を正解と比較してみましょう。見比べてみると、どちらも結果が同じなので、答えは合っていそうです。ただし前回の問題作成の時もそうでしたが、プログラム自体は何も効率化されておらずfor文の多重ネストをはじめとした実装になっているので、実行時間はほとんどかからないものの、改良の余地はありそうです。
answer_1.txt solve_1.txt
============================== ==============================
Sudoku Solution #1 Sudoku Puzzle #1 - Solution
Difficulty: low Difficulty: low
Generated: 2025-09-30 20:19:48 Generated: 2025-09-30 20:19:48
Solved: 2025-10-01 22:40:33
============================== ==============================
4 8 9 | 3 1 2 | 5 7 6 4 8 9 | 3 1 2 | 5 7 6
6 5 3 | 4 7 9 | 1 2 8 6 5 3 | 4 7 9 | 1 2 8
7 2 1 | 6 8 5 | 4 3 9 7 2 1 | 6 8 5 | 4 3 9
--------------------- ---------------------
5 4 7 | 1 3 8 | 9 6 2 5 4 7 | 1 3 8 | 9 6 2
3 6 2 | 5 9 7 | 8 4 1 3 6 2 | 5 9 7 | 8 4 1
9 1 8 | 2 6 4 | 7 5 3 9 1 8 | 2 6 4 | 7 5 3
--------------------- ---------------------
2 9 4 | 8 5 3 | 6 1 7 2 9 4 | 8 5 3 | 6 1 7
1 7 5 | 9 2 6 | 3 8 4 1 7 5 | 9 2 6 | 3 8 4
8 3 6 | 7 4 1 | 2 9 5 8 3 6 | 7 4 1 | 2 9 5
まとめ
今回は昨日claude codeに作成させた数独の問題をclaude codeで解かせるためのコードを作成させました。パッとみた限りではちゃんと溶けていますが、計算効率がとても悪い実装になっているので、プロファイリングもしつつ性能を改善していきたいと思います。
Discussion