三目並べアプリ開発：Reactで作るシンプルな三目並べアプリをDockerで動かすまでの手順

## はじめに
本記事では、Docker環境でReactを使用してシンプルな三目並べ（Tic Tac Toe）アプリを作成する手順について説明します。

今回は、三目並べの戦略や複雑な対戦機能には触れず、プレイヤー同士でシンプルに対戦できる基本機能のみを実装しています。

本記事はITスクールの課題としてアウトプット学習を目的に作成したもので、個人の備忘録レベルの内容ですので、ご了承ください。

## 必要なツール

:::note
**私の環境はM1チップ搭載のMacOSですが、本記事のハンズオンで使用するツールは以下の通りです。**
・``Docker``
・``Docker Compose``
・``Node.js（バージョン14以上推奨）``
・``npm（Node Package Manager）``
:::

## 作成した三目並べアプリのデモ動画
今回のReactアプリは基本的な対戦機能のみを実装していますが、以下はその対戦デモ動画です。

![タイトルなし.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3662571/72c9330a-7c23-62e2-0207-25540e682e41.gif)

## ディレクトリ構成
以下のようなディレクトリ構成でReactアプリを構築します。この構成により、三目並べアプリのファイルを適切に配置し、Docker環境で動作させることができます。

```bash
tictactoe/
│
├── node_modules/         # Node.jsのモジュールが格納されるディレクトリ
│
├── public/               # 公開用のファイル
│   └── index.html        # アプリケーションのエントリーポイントとなるHTMLファイル
│
├── src/                  # ソースコードのディレクトリ
│   ├── TicTacToe.js      # 三目並べのゲームロジック
│   ├── TicTacToe.css     # 三目並べのスタイルシート
│   ├── index.js          # アプリケーションのエントリーポイント
│   └── index.css         # アプリケーションのスタイルシート
│
├── .dockerignore         # Dockerビルド時に無視するファイル
├── Dockerfile            # Dockerイメージを作成するための設定ファイル
├── docker-compose.yml    # Docker Composeの設定ファイル
├── package.json          # プロジェクトの依存関係やスクリプトを管理するファイル
└── README.md             # プロジェクトの説明や使い方を記載したファイル(任意)
```

このディレクトリ構成を作成するために、以下のコマンドを実行して初期ファイルを生成し、不要なファイルを削除して整理します。

```
npx create-react-app tictactoe
```

:::note warn
**上記のコマンドを実行するとデフォルトで多数のファイルが作成されますが、ここでは不要なファイルを削除して進めます。**
:::

## ステップ1: プロジェクトの作成
### Dockerfileの作成
まず、プロジェクトのルートディレクトリに以下の内容で ``Dockerfile`` を作成します。

```Dockerfile
# Dockerfile
FROM node:14

# 作業ディレクトリの設定
WORKDIR /app

# 依存関係のインストール
COPY package*.json ./
RUN npm install

# アプリケーションのソースをコピー
COPY . .

# アプリケーションをビルド
RUN npm run build

# アプリケーションを提供する
CMD ["npm", "start"]
```

この ``Dockerfile`` は、Dockerイメージを作成するための設定ファイルです。Node.js 環境を構築し、アプリケーションの依存関係をインストールし、最終的にアプリをビルドします。

### docker-compose.ymlの作成
次に、プロジェクトのルートディレクトリに以下の内容で ``docker-compose.yml`` を作成します。

```docker-compose.yml
version: '3'
services:
  app:
    build: .
    ports:
      - "3000:3000"
    volumes:
      - .:/app
    environment:
      - CHOKIDAR_USEPOLLING=true
```

このファイルは、Docker Composeを使用してアプリケーションのサービス構成を定義するものです。アプリケーションのビルド、ポートの公開、ボリュームの設定などを管理します。

## ステップ2: Reactアプリの作成
ここでは、三目並べアプリの機能を実装するためのファイルをプロジェクトに追加します。

### TicTacToe.js
以下は ``TicTacToe.js`` のコードです。このコードでは、三目並べの盤面と勝敗判定の基本ロジックを実装しています。

```TicTacToe.js
// src/TicTacToe.js
import React, { useState } from 'react';
import './TicTacToe.css';

const TicTacToe = () => {
  const [board, setBoard] = useState(Array(9).fill(null));
  const [isXNext, setIsXNext] = useState(true);

  const handleClick = (index) => {
    if (board[index] || calculateWinner(board)) return;
    const newBoard = board.slice();
    newBoard[index] = isXNext ? 'X' : 'O';
    setBoard(newBoard);
    setIsXNext(!isXNext);
  };

  const calculateWinner = (squares) => {
    const lines = [
      [0, 1, 2],
      [3, 4, 5],
      [6, 7, 8],
      [0, 3, 6],
      [1, 4, 7],
      [2, 5, 8],
      [0, 4, 8],
      [2, 4, 6],
    ];
    for (let i = 0; i < lines.length; i++) {
      const [a, b, c] = lines[i];
      if (squares[a] && squares[a] === squares[b] && squares[a] === squares[c]) {
        return squares[a];
      }
    }
    return null;
  };

  const winner = calculateWinner(board);
  const status = winner ? `勝者: ${winner}` : `次のプレイヤー: ${isXNext ? 'X' : 'O'}`;

  return (
    <div className="container">
      <h1>三目並べ</h1>
      <div className="status">{status}</div>
      <div className="board">
        {board.map((cell, index) => (
          <div
            key={index}
            className="cell"
            onClick={() => handleClick(index)}
            data-value={cell || ""}
          />
        ))}
      </div>
    </div>
  );
};

export default TicTacToe;
```

### TicTacToe.css
以下は ``TicTacToe.css`` のコードです。三目並べの盤面と駒の表示にスタイルを適用しています。

```TicTacToe.css
/* src/TicTacToe.css */
body {
  display: flex;
  justify-content: center;
  align-items: center;
  height: 100vh;
  background-color: #d5f5d5; /* 薄い緑色の背景 */
  margin: 0;
}

.container {
  text-align: center;
  font-family: 'Arial', sans-serif;
}

.board {
  display: grid;
  grid-template-columns: repeat(3, 100px);
  gap: 5px;
  margin: 20px auto;
}

.cell {
  width: 100px;
  height: 100px;
  display: flex;
  justify-content: center;
  align-items: center;
  font-size: 36px;
  border: 1px solid #333;
  cursor: pointer;
}

.cell[data-value="O"] {
  color: red; /* ⚪︎の色 */
}

.cell[data-value="X"] {
  color: blue; /* ✕の色 */
}

/* data-value属性の内容を表示 */
.cell::before {
  content: attr(data-value); /* data-value属性をテキストとして表示 */
}
```

### index.js
以下は ``index.js`` のコードです。Reactのエントリーポイントとして、アプリケーションをレンダリングしています。

```index.js
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import TicTacToe from './TicTacToe';

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <React.StrictMode>
    <TicTacToe />
  </React.StrictMode>
);
```

### index.css
次に、全体のスタイルを設定するための ``index.css`` ファイルをプロジェクトに追加します。

```index.css
/* src/index.css */
body {
  margin: 0;
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
  background-color: #f5f5f5;
}
```

## ステップ3: アプリの起動
最後に、以下のコマンドでアプリケーションを起動します。

```bash
# Docker Composeを使ってアプリケーションを起動
docker-compose up
```

ブラウザで、``http://localhost:3000/``を入力すると、以下のページが表示されていれば成功です。

![スクリーンショット 2024-11-03 10.13.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3662571/6717ee74-7b7b-2277-708f-8f99a7cd6517.png)

このアプリでは、プレイヤー同士でシンプルに対戦できる基本機能のみを実装しています。時間があれば、botとの対戦機能なども追加したいと考えましたが、今回はこの段階で終了としました。

![スクリーンショット 2024-11-03 10.15.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3662571/02a86ef5-73b6-e6e1-8ae2-c0470dfb79c3.png)

## まとめ

本記事では、Dockerを使ってReactで三目並べアプリを作成しました。

現時点では機能が限られていますが、時間や学習コストの観点から今回はここまでとしました。今後は、botと対戦できる機能の実装など、さらに学びを深めていきたいと考えています。

## 参考記事

https://ja.react.dev/learn/tutorial-tic-tac-toe