同じパズル、二つの方法
やさしいパズル一つ(空きマス35)を、3回目の記事の 8B LoRA(15サイクル)で2回解きました。
- 1回目: 数字1から9まで順に、VLM が置けないマスを書き出し、場所が一つだけ残ったマスを埋めます。
- 2回目: 同じ方法に加えて、マスを埋めるたびに、空きマスが一つ残ったボックス・行・列をコードがすぐに埋めます。
1回目: 空きマス2つで止まる
16回判定する間に38手を出し、33手が正解でした。空きマスを2つ残して、それ以上打つ場所を見つけられませんでした。置けないマスを漏れなく当てた判定は16回中9回でした。
間違えた5手は、すべて置けるマスを置けないと誤って書いたことから生まれました。場所が一つ余計に消されたので、見当違いのマスが唯一の場所として残ったのです。デモは間違えた手を盤に載せず、記録だけしました。
2回目: 10回の判定で完走
2回目は10回の判定で35マスをすべて埋めました。VLM の判定で15マス、続けてコードが20マスを埋め、間違えたマスはありませんでした。漏れなく当てた判定は10回中8回でしたが、漏れたマスが答えを変えることはありませんでした。
数字2で2マスを埋めると、空きマスが一つだけ残ったボックス・行・列ができ、コードが5マスを続けて埋めました。数字7と2周目の数字3でも5マスずつ続きました。判定すべきことが減ったので、モデルが間違える機会も減りました。

前の答えが次の答えを作る
1回目の記事のモデルは左上から横に埋め、前に埋めた答えを次のマスの根拠に使いませんでした。2回目の解き方は盤のあちこちに散らばって埋まり、いま埋めたマスが次のマスの根拠になります。人が解く順序と同じです。

この段階の実際のコード
2回目で VLM の判定の後に動くコードです。ボックス・行・列に空きマスが一つだけ残ったら、足りない数字で埋めます。
vlm_digit_strategy.py
def _missing_one(values: list[int]) -> int | None:
present = {v for v in values if v != 0}
miss = [d for d in range(1, 10) if d not in present]
return miss[0] if len(miss) == 1 else None
def last_empty_unit_moves(
board: list[list[int]],
) -> list[tuple[int, int, int, str]]:
"""박스·행·열에 빈칸이 정확히 1개면 빠진 숫자로 채움."""
found: dict[tuple[int, int], tuple[int, str]] = {}
def add(r: int, c: int, digit: int, reason: str) -> None:
key = (r, c)
if key not in found:
found[key] = (digit, reason)
elif found[key][0] == digit:
prev = found[key][1]
if reason not in prev:
found[key] = (digit, f"{prev}+{reason}")
for br in range(3):
for bc in range(3):
cells = [
(r, c)
for r in range(br * 3, br * 3 + 3)
for c in range(bc * 3, bc * 3 + 3)
]
empties = [(r, c) for r, c in cells if board[r][c] == 0]
if len(empties) != 1:
continue
digit = _missing_one([board[r][c] for r, c in cells])
if digit is not None:
add(empties[0][0], empties[0][1], digit, "code_last_box")
for r in range(9):
empties = [(r, c) for c in range(9) if board[r][c] == 0]
if len(empties) != 1:
continue
digit = _missing_one([board[r][c] for c in range(9)])
if digit is not None:
add(empties[0][0], empties[0][1], digit, "code_last_row")
for c in range(9):
empties = [(r, c) for r in range(9) if board[r][c] == 0]
if len(empties) != 1:
continue
digit = _missing_one([board[r][c] for r in range(9)])
if digit is not None:
add(empties[0][0], empties[0][1], digit, "code_last_col")
return [
(r, c, digit, reason)
for (r, c), (digit, reason) in sorted(found.items())
]次の記事は「5. 人を助けるAI」です。
COMMENTS · CHAPTER 04
学習前と学習後の解き方の比較 コメント 0
まだコメントはありません。気になった点や補足があれば残してください。
コメントを登録するには、Googleで始めてニックネームとメールアドレスを登録してください。
Googleで始める