前回作った三目並べをjQueryで書いてみようと思います。
どれくらい煩雑になるのだろう。
#数値の表示のみ
index.html
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="css/index.css" />
<script src="https://ajax.aspnetcdn.com/ajax/jQuery/jquery-3.4.1.min.js"></script>
<script src="js/index.js"></script>
</head>
<body>
<div id="root">
<div class="game">
<div class="gmae-board">
<div>
<div class="board-row">
<button class="square"></button><button class="square"></button
><button class="square"></button>
</div>
<div class="board-row">
<button class="square"></button><button class="square"></button
><button class="square"></button>
</div>
<div class="board-row">
<button class="square"></button><button class="square"></button
><button class="square"></button>
</div>
</div>
</div>
<div class="game-info">
<div>次の手番: X</div>
<div>
<!--<li><button>Go to game start</button></li>-->
<!-- <li><button>Go to move #1</button></li> -->
</div>
</div>
</div>
</div>
</body>
</html>
index.css
body {
font: 14px 'Century Gothic', Futura, sans-serif;
margin: 20px;
}
ol,
ul {
padding-left: 30px;
}
.board-row:after {
clear: both;
content: '';
display: table;
}
.status {
margin-bottom: 10px;
}
.square {
background: #fff;
border: 1px solid #999;
float: left;
font-size: 24px;
font-weight: bold;
line-height: 34px;
height: 34px;
margin-right: -1px;
margin-top: -1px;
padding: 0;
text-align: center;
width: 34px;
}
.square:focus {
outline: none;
}
.kbd-navigation .square:focus {
background: #ddd;
}
.game {
display: flex;
flex-direction: row;
}
.game-info {
margin-left: 20px;
}
以下処理だけで行けそうです。
index.js
$(function() {
$(".square").each((index, elem) => {
$(elem).text(index);
});
});
Live Serverの拡張をインストールして、以下からブラウザを起動します。
出来てました!
#XとOを入力できるようにする
基本的な設計はチュートリアルを真似します。
index.js
$(function() {
let xIsNext = true;
$(".square").click(function() {
$(this).text(xIsNext ? "X" : "O");
xIsNext = !xIsNext;
});
});
#履歴なしの完成までもっていく
index.js
//import $ from "jQuery";
$(function() {
const squares = new Array(9).fill(null);
let xIsNext = true;
const status = $(".game-info div:first-child");
$(".square").click(function() {
// 押されたsquareのインデックス
const index = $(".square").index(this);
if (calculateWinner(squares) || squares[index]) {
return;
}
squares[index] = xIsNext ? "X" : "O";
$(this).text(squares[index]);
status.text("次の手番: " + (xIsNext ? "O" : "X"));
xIsNext = !xIsNext;
});
// 勝敗判定関数(公式チュートリアルから拝借)
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, b, c] = lines[i];
if (
squares[a] &&
squares[a] === squares[b] &&
squares[a] === squares[c]
) {
return squares[a];
}
}
return null;
}
});
一旦完成
ここまでだと、Reactよりソースコード短いかな?
#履歴機能を持たせる
履歴機能を持たせて、最後まで作ります。
index.html
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="css/index.css" />
<script src="https://ajax.aspnetcdn.com/ajax/jQuery/jquery-3.4.1.min.js"></script>
<script src="js/index.js"></script>
</head>
<body>
<div id="root">
<div class="game">
<div class="gmae-board">
<div>
<div class="board-row">
<button class="square"></button><button class="square"></button
><button class="square"></button>
</div>
<div class="board-row">
<button class="square"></button><button class="square"></button
><button class="square"></button>
</div>
<div class="board-row">
<button class="square"></button><button class="square"></button
><button class="square"></button>
</div>
</div>
</div>
<div class="game-info">
<div>次の手番: X</div>
<div>
<li><button>Go to game start</button></li>
<!-- <li><button>Go to move #1</button></li> -->
</div>
</div>
</div>
</div>
</body>
</html>
jsは信じられないくらいワケわかめになりました。
もっとスマートにしたかった・・・。
(行数長かったんでコメント右に書いてます)
index.js
//import $ from "jQuery";
$(function() {
// 履歴
const history = [{ squares: new Array(9).fill(null) }];
let stepNumber = 0; // 現在表示している履歴のインデックスを表す
const status = $(".game-info div:first-child"); // 手番
const allJqSquare = $(".square"); // 全square jQueryオブジェクト
// 最初の履歴ボタン
const startButton = $(".game-info li")
.find("button:first")
.click(historyButtonClick.bind(null, 0)); // bindで引数を縛る
// square押下処理
allJqSquare.click(function() {
const index = allJqSquare.index(this); // 押されたsquareのインデックス
const current = history[stepNumber]; // 現在のsquares
const squares = current.squares;
if (calculateWinner(squares) || squares[index]) {
return;
}
const newSquares = squares.concat(); // squaresのコピー
newSquares[index] = stepNumber % 2 === 0 ? "X" : "O";
$(this).text(newSquares[index]);
status.text("次の手番: " + (stepNumber % 2 === 0 ? "O" : "X"));
// カレントのstepNumberより後ろのボタンを削除する
$(".game-info li").each((i, element) => {
if (i > stepNumber) {
$(element).remove();
}
});
// 現在のステップまで履歴も削除
for (; stepNumber + 1 < history.length; ) {
history.pop();
}
history.push({ squares: newSquares }); // 新しい要素追加
stepNumber++;
// 新たに履歴ボタンを作る
// 親のliごとクローンする
startButton
.parent()
.clone()
.appendTo(startButton.parent().parent()) // .game-infoに追加
.children("button")
.text("Go to move #" + stepNumber) // ボタン名変更
.click(historyButtonClick.bind(null, stepNumber)); // bindで引数を縛る
});
// 履歴ボタン押下処理
function historyButtonClick(sNumber) {
stepNumber = sNumber;
status.text("次の手番: " + (stepNumber % 2 === 0 ? "X" : "O")); // ここは上とは反対になる
// 全squareのテキストを書き直す
history[sNumber].squares.forEach((value, i) => {
allJqSquare.eq(i).text(value);
});
}
// 勝敗判定関数(公式チュートリアルから拝借)
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, b, c] = lines[i];
if (
squares[a] &&
squares[a] === squares[b] &&
squares[a] === squares[c]
) {
return squares[a];
}
}
return null;
}
});
#感想
履歴がないバージョンまではスラスラできたんですが、履歴のとこで死にました。
私のやり方が悪いのもあるかもしれませんが、Reactのメリットを実感しました!tbn