ソルバーと解法

8パズル ソルバー — マンハッタン距離を使ったA*の実装

8パズルは最小かつ本格的な探索問題です。マンハッタン距離を使った教科書的なA*実装なら、どんな盤面もマイクロ秒単位で解けます。あらゆる言語で実装できるコードのスケッチとともに、その仕組みを詳しく解説します。

更新日 2026-05-20 7 分で読めます

スライドパズル ソルバー

「シャッフル」でランダムな盤面、「編集」で自分の盤面を入力できます。「解く」を押すと手順を1手ずつ再生します。3×3 の解は最短手順です。

8パズルは、ヒューリスティック探索を学んだ日に最初に書くプログラムです。ほぼどんなアプローチでも動くほど小さく、粗いアプローチと優れたアプローチの差がはっきり見えるほど大きい。この記事では、標準的な解法を上から下まで丁寧に解説します。

状態の表現

盤面を9個の整数の配列で表します。行優先順で0〜8のインデックスを付けます。

位置:         インデックス:
 1 2 3         0 1 2
 4 5 6   ←→   3 4 5
 7 8 _         6 7 8

空きマスはセンチネル値で表します——通常は0を使います。ゴール状態は [1, 2, 3, 4, 5, 6, 7, 8, 0] です。

移動の定義

空きマスのインデックスを e とすると、空きマスと上下左右の隣接タイルを入れ替えられます:最上行でなければ e-3(上)、最下行でなければ e+3(下)、最左列でなければ e-1(左)、最右列でなければ e+1(右)です。

neighbors(state) という関数は、1手で到達できる最大4つの状態を返します。

ヒューリスティック:マンハッタン距離

各タイル(空きマスは除く)について、現在位置からゴール位置までの行距離と列距離の和を計算し、全タイルで合計します。この合計は残り手数の下限です——各タイルは少なくともその距離を移動しなければなりません。

疑似コードで表すと:

h(state) = タイル t のすべての和:
  abs(row(現在) - row(ゴール)) + abs(col(現在) - col(ゴール))

マンハッタン距離は許容的(過大評価しない)かつ一貫性がある(三角不等式を満たす)です。A*にとって両方の性質が重要です。

A*の12行実装

A*は f = g + h の順で並べられた状態の優先度付きキューを管理します。g はこれまでの手数(深さ)、h は残り手数のヒューリスティック推定値です。各イテレーションで:最小f値の状態をポップし、展開し、更新されたfで近傍をプッシュします。

open = priority_queue()
open.push(start, f=h(start))
came_from = {}; g = {start: 0}

while open is not empty:
  state = open.pop()
  if state == goal: return reconstruct_path(came_from, state)
  for n in neighbors(state):
    tentative_g = g[state] + 1
    if n not in g or tentative_g < g[n]:
      g[n] = tentative_g
      came_from[n] = state
      open.push(n, f=tentative_g + h(n))

これがソルバーの全体です。hneighbors を実装すれば、どんな8パズルも解けます。

性能

マンハッタン距離を使ったAは、最難のインスタンスでも数百〜数千の状態を展開するだけで、数百マイクロ秒で8パズルを解きます。状態空間が十分小さいため、このサイズではAがIDAより優位です——3×3ではAが正解で、4×4以上ではIDA*に切り替えます。

よくある落とし穴

最初の実装で必ずやらかす3つのこと:

状態のハッシュ化。 Pythonのタプルはうまくハッシュ化されますが、Javaのint配列はそうではありません。どの言語を使っても、閉集合・開集合が機能するよう状態をハッシュ化可能にする必要があります。よく使われる手法は、9タイルの状態を1つの32ビット整数にエンコードすることです(セルは0〜8なので1セルあたり4ビット)。

偶奇性(パリティ)チェックの見落とし。 シャッフルによってランダムな8パズルを生成すると、半分の確率で解けない盤面になります。Aは存在しない経路を求めて181,440状態の半空間全体を探索してしまいます。Aを実行する前に簡単な転倒数チェックを追加するか、ゴールから逆順に歩くことで生成してください。

ヒューリスティックで空きマスをタイルとして扱う。 マンハッタン距離は実際のタイルのみを対象に合計します。空きマスを含めるとヒューリスティックが過大になり許容性が壊れます(空きマスは1手で「無料で」移動できます)。

マンハッタン距離を超えて

8パズルではマンハッタン距離より良くすることはできますが、改善幅は大きくありません:

8パズルでは、マンハッタン距離+線形矛盾が実用上の最良点です。

次に作るもの

8パズル ソルバーを書いたなら、自然な拡張として:

  1. 15パズル ソルバー — IDA* + ウォーキングディスタンス。同じ基本的なアイデア、より深い探索。(ガイドはこちら。)
  2. 汎用Nパズル ソルバー — パターンデータベース使用。週末プロジェクト向け。
  3. 解けるかチェック — 盤面がゴールから到達可能かどうかを返す30行の関数。アプリ開発に有用。(転倒数定理に基づく。)

8パズルは小さい。しかし解く過程で学ぶ技術は、ずっと大きな問題にもそのままスケールします。