はじめに
私自身の復習兼、備忘録的な意味もあり、複数回の記事に渡って React を用いてマルバツゲーム(三目並べ)を開発していきたいと思います。
シリーズの一覧
- React入門1: 環境構築 [オンライン版]
- React入門2: 盤面の作成
- React入門3: インタラクションの実装
- React入門4: リファクタリング [リフトアップ編]
- React入門5: リファクタリング [インタラクション編]
- React入門6: 手番の実装
- React入門7: ゲームの勝利判定
- React入門8: テキストの実装 (今回)
- React入門9: タイムトラベル(1)
- React入門10: タイムトラベル(2)
- React入門11: タイムトラベル(3)
目的について
全体の目的
React公式のチュートリアルで公開されているマルバツゲームを 3x3 のマスで実装していきます。
今回の目的
ゲームの状況を示すテキストを実装していきます。また、前回作成した calculateWinner()
関数を使って、決着がついた場合の勝者も表示できるようにします。
テキストの実装
次のページで、前回のソースファイルを確認できます。
- 前回の内容はコチラから!
テキストの表示
App.js の Board
コンポーネントの return
文に <div>
要素を加えて、盤面の上にテキストを表示させてみましょう。次の要件を満たすようにコーディングをしてみます。
- 盤面の上に文字を表示するには
return
文のどこに<div>
要素を加えればよいか - 「
ゲームの状況
」というテキストを表示する
export default function Board() {
/* 省略 */
return (
<>
<div>ゲームの状況</div>
<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」のどちらであるかを表示していきます。
第6回の記事 で定義した、手番を管理している state
型の xIsNext
変数を使って、現在のプレイヤーを取得しましょう。この変数は、true
のときに「X」、false
のときに「O」のプレイヤーを表しています。
従って、テキスト( status
変数)を次のように制御すれば、操作中しているプレイヤーを示すことができます。
let status = "プレイヤー: ";
if (xIsNext) {
status += "X";
} else {
status += "O";
}
では、App.js の Board()
コンポーネントに次の変更を加えましょう。
- 手番を表示するテキストの制御するプログラムを実装する
- ゲームの状況を文字列で示す
status
変数を宣言する -
status
変数の内容を手番 (xIsNext
変数) に応じて更新する
- ゲームの状況を文字列で示す
-
return
文にある<div>
要素で手番を表示させる
export default function Board() {
/* 省略 */
let status = "プレイヤー: ";
if (xIsNext) {
status += "X";
} else {
status += "O";
}
return (
<>
<div>{status}</div>
<div className="board-row">
/* 省略 */
</div>
</>
);
動作結果を次に示します。これで、空白のマスをクリックした後に、テキストが変更されるようになりました。
条件 (三項) 演算子の利用
JavaScriptの文法的な内容になります。動作結果に関する変更はないので、勝者の表示 まで飛ばしても大丈夫です。
先ほどのコードを、条件 (三項) 演算子を用いることで短くまとめていきます。まずは、見慣れた if-else
文の構文を示します。
if (条件) {
真のときに実行する処理;
} else {
偽のときに実行する処理;
}
これを条件 (三項) 演算子によって表現すると次の構文になります。
条件 ? 真のときに返す値 : 偽のときに返す値;
詳しい内容を調べたい方は次のリファレンスをご確認ください。
従って、手番を表示するテキストの制御は、次のようなコードで表すことができます。
let status = "プレイヤー: " + (xIsNext ? "X" : "O");
余談ですが、このようにコードを省略することをショートハンドというみたいです。
勝者の表示
ゲームの決着がついたときに勝者を表示できるようにしていきます。App.js の Board
コンポーネントに次の変更を加えましょう。
- 勝者を示す
winner
変数を宣言する- 初期値を勝利判定 (
calculateWinner()
関数) の結果とする
- 初期値を勝利判定 (
- 勝利判定の結果に応じてテキストの内容を変更する
- 勝者がいる場合は、その印を表示する
- 「X」が勝ったとき、「勝者: X」
- 「O」が勝ったとき、「勝者: O」
- 勝者が決まっていない場合は、次のプレイヤーを表示する
- 勝者がいる場合は、その印を表示する
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);
const winner = calculateWinner(squares);
let status;
if (winner) {
status = "勝者: " + winner;
} else {
status = "プレイヤー: " + (xIsNext ? "X" : "O");
}
function handleClick(i) {
if (squares[i]) {
return;
}
const nextSquares = squares.slice();
if (xIsNext) {
nextSquares[i] = "X";
} else {
nextSquares[i] = "O";
}
setSquares(nextSquares);
setXIsNext(!xIsNext);
}
return (
<>
<div>{status}</div>
<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>
</>
);
}
function 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 = lines[i][0];
const b = lines[i][1];
const c = lines[i][2];
if (squares[a] && squares[a] === squares[b] && squares[a] === squares[c]) {
return squares[a];
}
}
return null;
}
動作結果を次に示します。これで、操作するプレイヤーだけでなく、勝者も表示できるようになりました。
これでゲームのシステムは完成しました!
おわりに
今回は、ゲームの状況を示すテキストを実装しました。これによって、マルバツゲームの主要な機能は完成です!お疲れ様でした。次のページにソースファイルを示します。
今後について
ここまで、マルバツゲームを開発していきましたが、まだまだ機能を追加する余地があります。例えば、公式チュートリアルにはまだ続きがあり、過去の手番に戻すタイムトラベル機能について解説されています。ご興味がある方は、上記のソースファイルを改変して次のページをご参照ください。(筆者の方でも記事にまとめるかもしれません... ← 9回目以降の記事にまとめました)
次回以降から、ゲームにタイムトラベルの機能を追加していきます。