マインスイーパーの作り方 — JavaScriptでブラウザゲームを作ろう

このゲームで遊ぶ → ソースコード全文 →

このチュートリアルで学べること

マインスイーパーは、地雷の位置を推理しながらセルを開いていくパズルゲームです。このチュートリアルでは、JavaScriptでマインスイーパーを一から作る方法を学びましょう。グリッドの管理、再帰的なセル展開(フラッドフィル)、地雷の配置アルゴリズムなど、ゲーム開発で役立つ技術がたくさん身につきます。

ボードのデータ構造を準備しよう

まず、盤面の各セルが持つ情報を決めましょう。マインスイーパーでは、各セルに「地雷かどうか」「開いたかどうか」「旗を立てたか」「隣接する地雷の数」の4つの情報が必要です。2次元配列で盤面を管理します。

var NEIGHBORS = [
  [-1, -1], [-1, 0], [-1, 1],
  [0,  -1],          [0,  1],
  [1,  -1], [1,  0], [1,  1]
];

var board = [];
for (var r = 0; r < rows; r++) {
  board[r] = [];
  for (var c = 0; c < cols; c++) {
    board[r][c] = {
      mine: false,
      revealed: false,
      flagged: false,
      adjacentMines: 0
    };
  }
}

NEIGHBORSは8方向のオフセットを表す配列です。あるセルの周囲8マスを調べるときに使います。boardは2次元配列で、各セルをオブジェクトとして管理しています。最初は地雷を置かず、プレイヤーの最初のクリック後に配置するのがポイントです。

地雷の配置と隣接数の計算を作ろう

最初のクリックが安全になるしくみ

マインスイーパーでは、最初のクリックで地雷を踏まないようにするのがお約束です。クリックされた場所とその周囲を「安全ゾーン」として記録してから、地雷をランダムに配置しましょう。

function placeMines(safeRow, safeCol) {
  var safeSet = {};
  safeSet[safeRow + ',' + safeCol] = true;
  for (var i = 0; i < NEIGHBORS.length; i++) {
    var nr = safeRow + NEIGHBORS[i][0];
    var nc = safeCol + NEIGHBORS[i][1];
    if (nr >= 0 && nr < rows && nc >= 0 && nc < cols) {
      safeSet[nr + ',' + nc] = true;
    }
  }

  var placed = 0;
  while (placed < totalMines) {
    var r = Math.floor(Math.random() * rows);
    var c = Math.floor(Math.random() * cols);
    if (!board[r][c].mine && !safeSet[r + ',' + c]) {
      board[r][c].mine = true;
      placed++;
    }
  }
}

safeSetでクリック位置とその周囲を記録し、そこには地雷を置かないようにしています。whileループでランダムな位置に地雷を1つずつ配置していきます。地雷の配置後は、各セルの周囲にある地雷の数を数えてadjacentMinesに格納します。

フラッドフィル(再帰的展開)を実装しよう

マインスイーパーの面白さは、空白セルをクリックすると周囲の空白が一気に開くところです。これを「フラッドフィル」という再帰処理で実現しましょう。隣接地雷数が0のセルを見つけたら、その周囲のセルも再帰的に開いていきます。

function floodReveal(r, c) {
  if (r < 0 || r >= rows || c < 0 || c >= cols) return;
  var cellData = board[r][c];
  if (cellData.revealed || cellData.flagged || cellData.mine) return;

  cellData.revealed = true;
  revealedCount++;
  updateCellDisplay(r, c);

  if (cellData.adjacentMines === 0) {
    for (var i = 0; i < NEIGHBORS.length; i++) {
      floodReveal(r + NEIGHBORS[i][0], c + NEIGHBORS[i][1]);
    }
  }
}

この関数のポイントは3つです。まず、範囲外チェックで配列の外にアクセスしないようにしています。次に、すでに開いたセル・旗付き・地雷のセルは処理をスキップします。そしてadjacentMines === 0のとき、8方向すべてに対して自分自身を呼び出す「再帰」を行います。再帰の終了条件がしっかり書かれているので、無限ループにはなりません。

まとめ — 次のステップ

このチュートリアルでは、マインスイーパーの核となる3つの仕組みを学びました。2次元配列によるグリッド管理、安全な地雷配置、そしてフラッドフィルによる再帰的展開です。ここからさらに、難易度の切り替え機能やタイマー、旗を立てる機能を追加すると、本格的なマインスイーパーが完成します。右クリックや長押しで旗を立てる操作も、イベント処理の良い練習になりますよ。

よくある質問

Q: プログラミング初心者でも作れますか?

A: はい、大丈夫です。このチュートリアルではステップごとにコードを書いていくので、初めての方でも順番に進めれば完成できます。わからないところがあれば、ひなテックの教室で質問もできますよ。

Q: どのくらい時間がかかりますか?

A: 基本部分は約30分〜1時間で作れます。見た目をこだわったり機能を追加すると、さらに楽しく発展させられます。