PHPで間違い探しゲームを作成してみましょう。多くのマス目を作成し、その中に同一の文字やをアイコンを配置して1箇所だけ類似の文字を配置します。その中から探し出すというゲームです。
完成イメージ

間違い探しゲームの考え方
1. ゲームの基本ルール
- 複数のマス目を作る(例:10×10で100マス)
- ほとんどのマスには同じ文字(例:森)を入れる
- 1つだけ違う文字(例:林)を入れる
- ユーザーがどのマスかクリックして、正解かどうか判定する
2. 乱数(ランダム配置)の仕組み
- まず「全マス分の配列」を作り、全てに同じ文字を入れる
- そのうち1個だけ違う文字に変えておく
shuffle()で配列全体をシャッフル(ランダムに並べ替え)- 順番が毎回変わるので、どこに「林」が出るかわからなくなる
3. 正解判定
- マス目にはリンクを付ける(
?choice=番号のようにGETで番号を送る) - クリックされた番号の配列要素が「林」だったら正解!それ以外はハズレ!
フォルダ構成とファイル名
- 作成フォルダ:
php-practice-onlygame - 作成ファイル:
only01.php - 使用CSSファイル(任意):
style.cssは任意で作成
only01.php基本コード
<?php
// 文字の設定
$target = "森";
$odd = "林";
$cols = 10;
$total = $cols * $cols;
//乱数の種(「シャッフルのやり方」をメモ)
if (isset($_GET['seed'])) {
$seed = $_GET['seed'];
} else {
$seed = random_int(1, 99999);
}
// 同じseedでシャッフルを再現
mt_srand($seed);
//0 番から $total - 1 個ぶん、すべて '森' の配列を作る」
$cells = array_fill(0, $total - 1, $target);
$cells[] = $odd;
shuffle($cells);
// クリックされた番号を取得
$choice = $_GET['choice'] ?? null;
$message = '';
if ($choice !== null) {
if ($cells[$choice] === $odd) {
$message = "正解!";
} else {
$message = "ハズレ...";
}
}
?>
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>間違い探しゲーム</title>
<style>
table {
border-collapse: collapse;
margin: 1em auto;
}
td {
border: 1px solid #ccc;
width: 50px;
height: 50px;
text-align: center;
font-size: 2rem;
}
.msg {
text-align: center;
font-size: 1.2rem;
margin-bottom: 1em;
}
</style>
</head>
<body>
<?php if ($message): ?>
<p class="msg"><?= htmlspecialchars($message, ENT_QUOTES, 'UTF-8') ?></p>
<?php endif; ?>
<table>
<?php foreach ($cells as $i => $char): ?>
<?php if ($i % $cols === 0) echo "<tr>"; ?>
<td><a href="?choice=<?= $i ?>&seed=<?= $seed ?>"><?= $char ?></a></td>
<?php if ($i % $cols === $cols - 1) echo "</tr>"; ?>
<?php endforeach; ?>
</table>
<p style="text-align:center;">
<a href="only01.php">新しい問題</a>
</p>
</body>
</html>
プログラムの構成と解説
初期設定
$target = "森"; $odd = "林"; $cols = 10; $total = $cols * $cols;
$target… 通常マスに入れる文字(ここでは「森」)$odd… 間違いの文字(ここでは「林」)$cols… 列数(10列×10行=100マスに設定)$total… マス目の総数($cols × $cols)
乱数の種(シード)を作る
if (isset($_GET['seed'])) {
$seed = $_GET['seed'];
} else {
$seed = random_int(1, 99999);
}
- 最初のアクセス時は
random_int()で新しい seed を作る - クリック後は GETパラメータの seed を再利用して
- 同じ並びを再現する
乱数の初期化
mt_srand($seed);
- PHP の乱数生成器を
$seedを使って初期化 mt_srand()は乱数生成器を初期化する関数$seedを渡すことで、乱数列のスタート位置を決定- 同じ seed で初期化すると、後に呼ばれる
mt_rand()系の乱数を作成する関数が同じ順番の乱数になります - これにより、同じ seed なら shuffle() の結果も同じになる
マス目を作る
$cells = array_fill(0, $total - 1, $target); $cells[] = $odd; shuffle($cells);
array_fill(0, $total - 1, $target)- → 「森」を $total-1 個ぶん作って配列に入れる
$cells[] = $odd;- → 最後に1個だけ「林」を追加
shuffle($cells);アルゴリズム込みで安全にシャッフルしてくれる便利関数- → 内部的に「乱数」を使って配列をシャッフル 各要素をランダムに入れ替えるときに
mt_rand()を呼んでいます。 shuffle()自体に「seed を渡す引数」はありませんが、すでにグローバルな乱数生成器がmt_srand($seed)で初期化されているため、同じ配列を同じ環境でshuffle()すれば、同じ結果になります。
- → 内部的に「乱数」を使って配列をシャッフル 各要素をランダムに入れ替えるときに
クリックされた場所を判定
$choice = $_GET['choice'] ?? null;
$message = '';
if ($choice !== null) {
if ($cells[$choice] === $odd) {
$message = "正解!";
} else {
$message = "ハズレ...";
}
}
$_GET['choice']… クリックされたマスの番号$cells[$choice]… そのマスの文字- 「林」だったら「正解!」、それ以外なら「ハズレ…」を表示
盤面の表示
<table>
<?php foreach ($cells as $i => $char): ?>
<?php if ($i % $cols === 0) echo "<tr>"; ?>
<td><a href="?choice=<?= $i ?>&seed=<?= $seed ?>"><?= $char ?></a></td>
<?php if ($i % $cols === $cols - 1) echo "</tr>"; ?>
<?php endforeach; ?>
</table>
$cellsの中身を1つずつ表示$i % $cols === 0は、「今表示しているセルが1行の先頭かどうか」を調べています。$iは0から始まるインデックスなので、$cols で割り切れるとき(0, $cols, $cols×2…)は新しい行が始まるタイミングです。そのときに<tr>タグを出力して、次のセルから新しい行に配置されるようにしています。<a href="?choice=番号&seed=シード">でクリックできるリンクを作る- これにより、どのマスがクリックされたか番号で分かる
$i % $cols === 0の挙動
具体例($cols = 5 のとき、最初の5行)
| $i | $i % $cols | 余り | 意味 | 出力するタグ |
|---|---|---|---|---|
| 0 | 0 % 5 | 余り 0 | 1行目の先頭 | <tr> |
| 1 | 1 % 5 | 余り 1 | 1行目の2列目 | なし |
| 2 | 2 % 5 | 余り 2 | 1行目の3列目 | なし |
| 3 | 3 % 5 | 余り 3 | 1行目の4列目 | なし |
| 4 | 4 % 5 | 余り 4 | 1行目の最後 | </tr>(次の if 文で出力) |
| 5 | 0 % 5 | 余り 0 | 2行目の先頭 | <tr> |
| 6 | 1 % 5 | 余り 1 | 2行目の2列目 | なし |
| 7 | 2 % 5 | 余り 2 | 2行目の3列目 | なし |
| 8 | 3 % 5 | 余り 3 | 2行目の4列目 | なし |
| 9 | 4 % 5 | 余り 4 | 2行目の最後 | </tr> |
ステップアップ:マス目が変更できるようにしよう!
only02.phpに出来上がった01ファイルの内容をコピーし、form要素を追加。マス目を自由に変更できるように追加してみましょう。

only02.phpの解答例はこちら
PHPに下記を追加
マス目を変更するところを追加
<div class="make_cell">
<form action="" method="get">
<p>マス目を変更する</p>
<input type="hidden" name="seed" value="<?= $seed ?>">
<input type="number" name="make_cell" value="<?= $cols ?>">
<button type="submit">作成</button>
</form>
</div>
最小値と最大値を設定できるように変更してみましょう。
HTML 属性: minlengthとmaxlength
ステップアップ:文字と答えが変更できるようにしよう
only03.phpに出来上がった02ファイルの内容をコピーし、さらに文字列が変更できるように追加してみましょう!

only03.phpの解答例はこちら
<?php
// 文字の設定
$target = "森";
$odd = "林";
if (isset($_GET['make_target'])) {
$target = $_GET['make_target'];
} else {
$target = "森";
}
if (isset($_GET['make_odd'])) {
$odd = $_GET['make_odd'];
} else {
$odd = "林";
}
<div class="make_cell">
<form action="" method="get">
<p>マス目の変更と文字の変更</p>
<input type="hidden" name="seed" value="<?= $seed ?>">
<p>
<label>マス目
<input type="number" name="make_cell" value="<?= h($cols) ?>">
</label>
</p>
<p>
<label>文字
<input type="text" name="make_target" value="<?= h($target) ?>">
</label>
の中の
<label>隠れた文字
<input type="text" name="make_odd" value="<?= h($odd) ?>">
</label>
</p>
<button type="submit">作成</button>
</form>
</div>
</body>
</html>
