26 近傍で推理し、表面から内側へ進む 3D マインスイーパーを作った
- 5 分で読めます - 2414 文字マインスイーパーの盤面を立方体に置き換えるだけでは、遊び方は 2D とあまり変わりません。 数字が周囲の地雷数を表し、好きなセルを選べるなら、視点を回転できるマインスイーパーにとどまります。
HyperMines 3D では、ゲーム開始時に選べるのは立方体の表面にあるセルだけです。 安全な表面のセルを開くと、面で接する内側のセルが新しく選べるようになります。 立方体の形を見せるだけでなく、表面から内側へ進む手順をルールに組み込んだゲームです。
この記事では、2026 年 8 月 17 日時点のコミット a76b537 を対象に、ゲームルールと AI アシストの実装を紹介します。
26 近傍で推理し、面で接する方向へ進む
通常のマインスイーパーでは、数字を上下左右と斜めを含む最大 8 セルから計算します。
3 次元の HyperMines 3D では、neighborIds() が X、Y、Z の各方向を調べるため、数字が参照する範囲は最大 26 セルです。
一方、閉じたセルを個別に選べるかどうかは、isSurfaceCell() で判定します。
立方体の境界にあるセルか、面で接する上下左右前後の最大 6 セルのどれかが開いている、または旗になっている場合だけ選べます。
斜めに接するセルは、数字の計算には含まれますが、内側へ進む経路にはなりません。
ただし、6 近傍を使うのはセルを個別に選ぶ場面だけです。 数字が 0 のときに安全な範囲を自動で開く処理と、数字の周囲に立てた旗の数が一致したときに残りを一括で開く処理は、どちらも最大 26 近傍を対象にします。
旗にも、地雷の印とは別の役割があります。 旗を置いたセルは開いたセルと同じように、その奥で面に接するセルを選べる状態にします。 旗を外した結果、ほかに表面へつながる経路がなければ、そのセルは再び選べなくなります。 なお、旗を外せなくならないように、旗が置かれたセル自体は常に選べる状態として扱われます。
次の盤面では、表面のセルを開いた内側に数字が並び、2 本の旗によってさらに奥へ進める状態になっています。 閉じたセルが立方体の形を残す一方で、開いたセルと旗が内側への経路を作っている点を確認してください。

旗は地雷の印を付けるだけでなく、地雷があると判断したセルを開かずに奥へ進むためにも使われています。
最初の一手で突然地雷を引く問題は、地雷を置くタイミングで避けています。 地雷配置を作るのは最初のセルを開いた後であり、そのセルと最大 26 近傍のセルを地雷の候補から除外します。 最初の数字は必ず 0 になり、そこから安全な範囲が開くため、プレイヤーは手掛かりのある状態から推理を始められます。
AI アシストは公開情報から確定手だけを選ぶ
ゲーム本体は正解となる地雷配置を #minefield に保持しますが、UI と AI アシストには渡しません。
両者が受け取る PublicObservation には、各セルの状態、公開済みの数字、現在選べるセルかどうか、残り地雷数など、プレイヤーが確認できる情報だけが入ります。
敗北するまでは地雷のセルも閉じたセルとして見えるため、AI アシストに正解は見えません。
src/autoplay/solver.ts は、公開済みの数字から制約を組み立てるソルバーです。
機械学習は使いません。
たとえば、数字が 2 で周囲に旗が 1 本あれば、残る未確定セルには地雷が 1 個あるという制約を作れます。
ソルバーは、残り地雷数が 0 または未確定セル数と等しい制約を先に確定し、制約同士の包含関係から新しい制約を導きます。 それでも決まらないセルは、同じ制約で結び付いたセルと制約のまとまりである連結成分へ分け、条件を満たす地雷配置を列挙します。 すべての配置で安全になるセル、または地雷になるセルだけが確定手です。
列挙には、1 つの連結成分につき最大 22 セル、1 回の列挙につき最大 200,000 ノードという上限があります。 盤面全体の残り地雷数をセルの確定に使うのは、残りが 0 個か、閉じたセル数と等しい場合だけです。 離れたまとまりを残り地雷数で組み合わせたり、各セルの地雷確率を計算したりはしません。
確定手がなければ、AI アシストは確率の高低でセルを選ばず、人間の一手を待ちます。
確定手がありません。ここからの運ゲーは人間が一手担当してください。
この動作には一つ注意点があります。 ソルバーはプレイヤーが置いた旗を地雷として扱うため、誤った旗を前提に推理を続ける可能性があります。 矛盾が見つかれば停止しますが、旗の正しさまでは証明しません。
Three.js で盤面を描き、URL から同じ盤面を作り直す
3D 盤面を担当する voxel-board.ts は、PublicObservation から描画内容を組み立てます。
表面にある閉じたセルは、セルごとに Mesh を作らず、同じ形状と材質を共有する InstancedMesh にまとめます。
数字と旗は Sprite、セルの選択は Raycaster、回転やズームは OrbitControls が担当します。
押した位置から 6 px を超えて動いた場合はセル操作とみなさず、盤面を回したドラッグ操作が意図しない開封につながらないようにしています。
最初の一手後にコピーした共有 URL には、seed、難易度を表す level、最初に開いた座標 start の 3 つが入ります。
最初の一手より前は start がまだ決まっていないため、URL に含まれません。
最初のセルと周囲を地雷候補から外してから配置を作るため、同じ seed と難易度だけでは同じ盤面になりません。
main.ts は最初の一手を URL に追加し、開いた側でも同じセルからゲームを始めます。
URL が保存するのは盤面の生成条件までです。 途中で開いたセルや旗、経過時間は URL に含まれません。 共有した相手は、同じ問題を最初からプレイします。
さいごに
このゲームを作りながら、AI によって、思いつきを形にして実際に触れるまでの距離は以前よりずっと短くなったと感じました。
作るための手間が減ったぶん、「何を面白いと思うか」「何を作りたいか」に、より時間を使えるようになった気がします。
この変化が良いものなのかは、まだ分かりません。
それでも、役に立つかどうかだけでは拾えない遊び心は、これからも大事にしていきたい。