スライドパズルをJavaScriptで作ってみた


# ３＊３のスライドさせるあれをJavaScriptで作ってみた

正式名称良く分からないですが、スライドさせるパズルを作ってみました。
- HTML / CSS / JavaScript（vanillaJS）のフロントエンドのみの構成
- GitHubpagesでホスト
- クリックまたはタップのみのシンプル操作
- CSSトランジションで数字パネルをすーっと動かす感じに制御 ＃これがやってみたかった
---

# デモ

https://kubo-4ka.github.io/slide-puzzle/


# ソース

https://github.com/kubo-4ka/slide-puzzle/

---


<details><summary>htmlについて</summary>

### html

```html
<!DOCTYPE html>
<html lang="ja">
```
- HTML文書の開始。lang="ja" は日本語向けであることを明示します。
---

### head

```html
<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>Slide Puzzle</title>
  <link rel="stylesheet" href="style.css" />
</head>
```
`<head>`内の要素の意味：

| 要素 | 内容 |
|------------------|-------------|
| `<meta charset="UTF-8">` | 日本語など多言語対応の文字コード設定 |
| `<meta name="viewport"...>` | スマホなど小画面でも拡大縮小せずに表示できる設定 |
| `<title>` | ブラウザのタブに表示されるページタイトル |
| `<link rel="stylesheet"...>` | 外部CSS（style.css）を読み込む指定 |

- ★コメントでOGP対応の提案いただきました。是非確認してみてください★

---
### body
```html
<body>
  <div class="container">
```
- container クラスで全体のレイアウトを中央揃え＆縦方向に整えます（CSSに定義）

---

### ステータス表示

```html
    <div class="status">
      <span id="timerLabel">Time: <span id="timer">0.0</span> s</span>
      <span id="clearMessage" class="hidden">Clear !!</span>
    </div>
```

- タイマー表示：ゲーム中の経過時間を表示。初期は 0.0 秒
- クリアメッセージ：ゲームをクリアすると hidden が外れて "Clear !!" が表示されます

---

### パズル盤面

```html
    <div id="board" class="board"></div>
```

- ここにJavaScriptがパネルを動的生成して挿入します
- 盤面は 3x3の正方形で、CSSの position: relative を使って中に absolute でタイルを配置します

---

### ボタン（スタート／再挑戦）

```html
    <button id="startBtn" class="fixed-button">START</button>
```

- ゲーム開始／再挑戦をコントロールするボタン
- 状態に応じてラベルが「START」「Trying...」「Try again?」と変わります
- ボタンの幅は常に一定で、見た目がぶれません（CSS指定）

</details>

---

<details><summary>cssについて</summary>

##  style.css の構成と役割

### 1.`body`

| 設定 | 意味 |
|----------|------|
| margin: 0 | ページ全体の余白をなくす |
| font-family: sans-serif | スッキリしたフォントを使用 |
| background-color: #121212 | ダークテーマ（背景を暗く） |
| color: #ccc | 文字を白系に |
| display: flex; justify-content: center; align-items: start; | 中央寄せ（横）＋上から並べる |
| height/min-height: 100vh | 画面の高さにぴったり合わせる |
| padding-top: 5vh | 上に少し余裕を持たせる |
| user-select: none | テキストを選択不可にする |
| overflow: hidden | スクロールバーを出さない |

---

### 2. `.container`
```
.container {
  text-align: center;
}
```
- 中の文字や要素を 中央揃えにします

---

### 3. `.status`

| 設定 | 意味 |
|----------|------|
| display: flex	 | タイマーとクリアメッセージを横並びにする |
| justify-content: space-between | 左右に均等配置 |
| margin: 10px auto | 上下10px・中央寄せ |
| width: 260px | 盤面と同じ幅に合わせて整える |
| font-size/height | タイマー表示のサイズ感を調整 |

---

### 4. `.board`

| 設定 | 意味 |
|----------|------|
| position: relative | 中の .tile を絶対位置で配置するための基準にする |
| width/height: 255px | 正方形盤面（85px×3）＋微調整 |
| margin | 上下に余白・中央揃え |
| background-color | 黒に近いパネル背景 |

---

### 5. `.tile`

| 設定項目                         | 意味・目的                                             |
|----------------------------------|--------------------------------------------------------|
| `background-color` / `border`   | パネルのダークな色合いと枠線を設定                     |
| `font-size` / `font-weight`     | 数字の見た目を強調して視認性アップ                    |
| `display: flex` + 中央揃え       | 数字をタイル中央に表示                                |
| `cursor: pointer`               | クリックできることを視覚的に示す                      |
| `will-change: transform`        | アニメーションのパフォーマンスを向上させるヒント     |
| `transition: transform 0.6s ease-in-out` | スライド移動のアニメーションを滑らかに設定         |
| `position: absolute`            | `.board` 内での個別配置を可能にする                   |
| `width` / `height: 83px`        | 盤面全体（255px）を 3×3 で均等に割り当てる             |

---

### 6. `button`

- **見た目**：角を丸くし、幅を一定（150px）にして統一感を演出
- **操作性**：文字サイズと余白を確保し、スマホでもタップしやすく
- **無効時**：背景色をグレー系に変更し、押せない状態であることを視覚的に伝える
- **ホバー時（有効なとき）**：背景色を少し明るくして反応を視覚的に強調

---

### 7. `.hidden`

- `display: none;` によって、要素（例：クリアメッセージなど）を一時的に非表示にするための共通ユーティリティクラス

</details>

---

<details><summary>jsについて</summary>

## jsについて

## JavaScript（script.js）関数・変数解説

---

### グローバル変数

- `tiles`  
  タイルの状態を保持する配列（1〜8 + null）。現在の並びを記録する

- `emptyIndex`  
  空白（null）の位置インデックス（0〜8の整数）

- `tileElements`  
  数字キーを持つオブジェクト。各タイルDOM要素を保持し、transformの変更に使用

- `startTime`  
  ゲーム開始時刻（経過時間の計算に使用）

- `timerInterval`  
  `setInterval()` によるタイマー更新用のID

- `playing`  
  ゲームが現在プレイ中かどうかを示す真偽値。プレイ中のみクリックが有効になる

---

### `function createTiles()`

- ゲームの初期状態を生成
- 数字 1〜8 と null を `tiles` 配列にセット
- 初期表示用の `initRender()` を呼び出す

---

### `function initRender()`

- `tiles` に従って `.tile` 要素を生成し、DOMに配置
- 空白タイル（null）はDOMに描画しない
- 各タイルにクリックイベントを設定
- `tileElements` に DOM 要素を登録

---

### `function updateTilePositions()`

- `tiles` の状態に合わせて、`tileElements` に対応するタイルの位置（`transform`）を更新
- CSSの `transition` がちょっと重い感じのタイルをすーっと移動させているような動きを実現

---

### `function getTransform(i)`

- 位置インデックス `i`（0〜8）を元に、CSS `transform: translate(x, y)` 文字列を返す
- タイルを盤面の正しい位置に表示するための補助関数

---

### `function moveTile(num)`

- クリックされたタイル番号 `num` を受け取り、その位置を取得
- 空白位置との隣接を確認し、隣接していれば `tiles` 配列を交換
- 空白位置を更新し、`updateTilePositions()` を呼び出して表示を更新
- 完成していれば `checkClear()` → `showResult()` を呼ぶ

---

### `function checkClear()`

- `tiles` の `0〜7` 番目が `[1,2,...,8]` になっているか確認
- パズル完成（クリア）していれば `true` を返す
- ★コメントで改善案いただいているので是非ご確認ください★

---

### `function showResult()`

- タイマー停止
- `playing` を `false` にし、`Clear !!` メッセージと再挑戦ボタンを表示

---

### `function shuffle(times = 20)`

- ランダムに `tiles` 配列をシャッフル
- 一度にすべて変更せず、`setInterval()` を使って1手ずつ順に実行（誰かがバラバラにしてる風に）
- 前回の空白位置と逆方向に戻らないようにする制御あり
- `updateTilePositions()` により移動を表示
- 終了後にゲーム開始・タイマー起動

---

### `function moveAllowed(from, to)`

- 移動元と移動先の位置が「同じ行で隣接」または「上下に隣接」しているかを確認
- `true` なら移動可能と判定

---

### `startBtn.addEventListener("click", ...)`

- 「START」ボタンを押すとゲーム初期化
- ボタン状態を `Trying...` にし、一定時間後に `shuffle()` を実行
- 終了後はタイマー開始＆プレイ可能な状態へ

---

### 関数間の関係図

```mermaid
graph TD
  startBtnClick["スタートボタンクリック"]
  createTiles["createTiles()"]
  initRender["initRender()"]
  shuffle["shuffle()"]
  moveTile["moveTile(num)"]
  updatePos["updateTilePositions()"]
  checkClear["checkClear()"]
  showResult["showResult()"]
  clearMessage["Clear表示＆再挑戦ボタン表示"]

  startBtnClick --> createTiles --> initRender
  startBtnClick --> shuffle --> updatePos
  shuffle --> updatePos
  moveTile --> updatePos
  moveTile --> checkClear -->|クリア| showResult --> clearMessage
```

---

### 処理の流れチャート

```mermaid
flowchart TD
  A["ページ読み込み"] --> B["STARTボタンをクリック"]
  B --> C["createTiles()"]
  C --> D["initRender()"]
  D --> E["一定時間後 shuffle()"]
  E --> F["1手ずつ空白と交換"]
  F --> G["updateTilePositions()"]
  G --> H{"シャッフル完了？"}
  H -- "No" --> E
  H -- "Yes" --> I["playing = true"]
  I --> J["プレイヤーがタイルをクリック"]
  J --> K["moveTile(num)"]
  K --> L["タイル交換 → updateTilePositions()"]
  L --> M{"checkClear()"}
  M -- "No" --> J
  M -- "Yes" --> N["showResult() → Clear表示"]
```


</details>

---


:::note info
自動で解いてくれる機能を追加してみました。

https://qiita.com/kubo4ka/items/8e68d9c6c76fef03958e

:::