0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

はじめに

私自身の復習兼、備忘録的な意味もあり、複数回の記事に渡って React を用いてマルバツゲーム(三目並べ)を開発していきたいと思います。

シリーズの一覧

  1. React入門1: 環境構築 [オンライン版]
  2. React入門2: 盤面の作成
  3. React入門3: インタラクションの実装
  4. React入門4: リファクタリング [リフトアップ編]
  5. React入門5: リファクタリング [インタラクション編]
  6. React入門6: 手番の実装 (今回)
  7. React入門7: ゲームの勝利判定
  8. React入門8: テキストの実装
  9. React入門9: タイムトラベル(1)
  10. React入門10: タイムトラベル(2)
  11. React入門11: タイムトラベル(3)

目的について

全体の目的

React公式のチュートリアルで公開されているマルバツゲームを 3x3 のマスで実装していきます。

今回の目的

マスが「X」だけでなく「O」も表示できるようにして、手番(ターン)を実装していきます。

手番の実装

次のページで、前回のソースファイルを確認できます。

  • 前回の内容はコチラから!

「O」の表示

App.js の Board コンポーネントに次の変更をしましょう。

  • 手番を表す変数を作成する
    • state 型の変数 xIsNext を宣言する
      • 初期値を ture とする
      • set関数の名称を setXIsNext とする
  • handleClick() 関数の変更
    • xIsNext 変数で手番を制御する
      • xIsNext 変数が真のときに、「X」を表示する
      • xIsNext 変数が真ではないときに、「O」を表示する
    • マスの表示を更新した後に手番を相手に譲る
      • set関数で xIsNext の真偽値を反転させる
App.js
import { useState } from "react";
import "./styles.css";

function Square({ value, onSquareClick }) {
  return (
    <button className="square" onClick={onSquareClick}>
      {value}
    </button>
  );
}

export default function Board() {
  const [squares, setSquares] = useState(Array(9).fill(null));
  const [xIsNext, setXIsNext] = useState(true);

  function handleClick(i) {
    const nextSquares = squares.slice();

    if (xIsNext) {
      nextSquares[i] = "X";
    } else {
      nextSquares[i] = "O";
    }
    setSquares(nextSquares);
    setXIsNext(!xIsNext);
  }

  return (
    <>
      <div className="board-row">
        <Square value={squares[0]} onSquareClick={() => handleClick(0)} />
        <Square value={squares[1]} onSquareClick={() => handleClick(1)} />
        <Square value={squares[2]} onSquareClick={() => handleClick(2)} />
      </div>
      <div className="board-row">
        <Square value={squares[3]} onSquareClick={() => handleClick(3)} />
        <Square value={squares[4]} onSquareClick={() => handleClick(4)} />
        <Square value={squares[5]} onSquareClick={() => handleClick(5)} />
      </div>
      <div className="board-row">
        <Square value={squares[6]} onSquareClick={() => handleClick(6)} />
        <Square value={squares[7]} onSquareClick={() => handleClick(7)} />
        <Square value={squares[8]} onSquareClick={() => handleClick(8)} />
      </div>
    </>
  );
}

実行結果を次に示します。これで、マスをクリックすると、「X」と「O」が交互に表示されるようになりました。

OとXの交互.gif

表示処理の修正

現状のプログラムでは、マスの状態が空白である否かを確認せずに「X」と「O」を表示させています。従って、既にどちらかの印をつけたマスを、再びクリックすると内容を塗り替えることできるバグがあります。

表示処理の修正前.gif

これを修正するために、Board コンポーネントの handleClick() 関数にて、クリックしたマスに印が既につけられている場合は、早期リターンをする処理を加えましょう。

handleClick() 関数の変更
  function handleClick(i) {
    if (squares[i]) {
      return;
    }

    const nextSquares = squares.slice();

    if (xIsNext) {
      nextSquares[i] = "X";
    } else {
      nextSquares[i] = "O";
    }
    setSquares(nextSquares);
    setXIsNext(!xIsNext);
  }

これで、既に印があるマスに対してクリックをしても、表示が変更されることはありません。

表示処理の修正後.gif

おわりに

今回は、マスで手番を実装することで、プレイヤーの概念が生まれました。次のページに現段階のソースファイルを示します。

次回は、盤面の状況からゲームの勝者を判定するプログラムを開発していきます。React というよりは、どのようにアルゴリズムを導出するかを中心に記しています。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?