React hooksで⚪︎×ゲーム
by wintyo
HTML
<div id="app"></div>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/lodash.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/classnames/2.2.6/index.min.js" integrity="sha512-PMVw2HzV4gXtPe+BpvOQRQe9HtKcU4jA4N9ilRq+paTcz/ERKCt4d9hqXlslfsKOydknA4Y4JsiQexm/1W8zIA==" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/prop-types/15.7.2/prop-types.js" integrity="sha512-Ttnt6nUh/1oV+4T/KWkG/ORvlIEOZohMCT/GIzelxTceoIreR2A1r6zmgFnEvi7GgstoDblmpMO/Gi9CXKTqGQ==" crossorigin="anonymous"></script>
SCSS
.game {
display: flex;
&__item {
& + & {
margin-left: 20px;
}
}
}
.board {
border: solid 1px #000;
width: 200px;
&__line {
display: flex;
& + & {
border-top: solid 1px #000;
}
}
}
.board-item {
position: relative;
flex: 1 1 0;
&.-clickable {
cursor: pointer;
}
& + & {
border-left: solid 1px #000;
}
&::before {
display: block;
padding-top: 100%;
content: '';
}
&__content {
position: absolute;
font-size: 50px;
line-height: 1;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
}
React
const { useState } = React;
const SIZE = 3;
const PLAYERS = ['X', '◯'];
/**
* 最初の盤面データを生成する
* @param size - 縦横それぞれの方向の個数
* @return 盤面データ
*/
const createInitialBoardData = (size) => {
return Array(size).fill().map(() => Array(size).fill(null));
};
/**
* 勝者の判定をする
* @param boardData - 盤面データ
* @return 勝者(nullの場合はまだ未決定)
*/
const judgeWinner = (boardData) => {
// 横ラインの勝者判定
for (let i = 0; i < boardData.length; i++) {
const putPlayer = boardData[i][0];
// 始めが誰も置いていない場合は調べても無駄なのでスキップ
if (putPlayer == null) {
continue;
}
const isThePlayerWon = boardData[i]
.every((player) => player === putPlayer);
if (isThePlayerWon) {
return putPlayer;
}
}
// 縦ラインの勝者判定
for (let j = 0; j < boardData[0].length; j++) {
const putPlayer = boardData[0][j];
// 始めが誰も置いていない場合は調べても無駄なのでスキップ
if (putPlayer == null) {
continue;
}
const isThePlayerWon = _.times(boardData[0].length)
.map((i) => boardData[i][j])
.every((player) => player === putPlayer);
if (isThePlayerWon) {
return putPlayer;
}
}
// 右下ラインの勝者判定
{
const putPlayer = boardData[0][0];
if (putPlayer != null) {
const isThePlayerWon = _.times(boardData.length)
.map((i) => boardData[i][i])
.every((player) => player === putPlayer);
if (isThePlayerWon) {
return putPlayer;
}
}
}
// 右上ラインの勝者判定
{
const putPlayer = boardData[boardData.length - 1][0];
if (putPlayer != null) {
const isThePlayerWon = _.times(boardData.length)
.map((i) => boardData[boardData.length - 1 - i][i])
.every((player) => player === putPlayer);
if (isThePlayerWon) {
return putPlayer;
}
}
}
// 誰も見つけられなかったらnullを返す
return null;
};
/**
* 盤面のコンポーネント
*/
const Board = (props) => {
return (
<div className="board">
{props.table.map((row, i) => (
<div key={i} className="board__line">
{row.map((col, j) => (
...