const TicTacToe = () => {
const [board, setBoard] = useState(Array(9).fill(null));
const [playerTurn, setPlayerTurn] = useState("p1");
const [winner, setWinner] = useState(null);
const takeTurn = (ind) => {
if (winner) return;
if (board[ind]) return;
const clonedBoard = [...board];
clonedBoard[ind] = playerTurn;
setBoard(clonedBoard);
setPlayerTurn((playerTurn) => (playerTurn === "p1" ? "p2" : "p1"));
};
useEffect(() => {
// check for horizontal wins
let hasWon = false;
for (const i = 0; i < board.length; i++) {
if (i % 3 === 0) {
if (board[i] && board[i] === board[i + 1] && board[i] === board[i + 2])
hasWon = true;
}
}
// check for vertical wins
for (const i = 0; i < board.length; i++) {
if (board[i] && board[i] === board[i + 3] && board[i] === board[i + 6])
hasWon = true;
}
// check for diagonal wins
if (board[0] && board[0] === board[4] && board[0] === board[8])
hasWon = true;
if (board[2] && board[2] === board[4] && board[2] === board[6])
hasWon = true;
if (hasWon) setWinner(playerTurn === "p2" ? "p1" : "p2");
const numEmpty = board.reduce((acc, tile) => (!tile ? acc + 1 : acc), 0);
if (numEmpty === 0) setWinner("No one");
}, [board, playerTurn]);
const restart = () => {
setBoard(Array(9).fill(null));
setWinner("");
setPlayerTurn("p1");
};
const renderMark = (ind) => {
switch (board[ind]) {
case "p1":
return <CrossIcon />
case "p2":
return <CircleIcon />
default:
return <></>;
}
};
return (
<>
<DemoCont>
<GameWrapper>
{winner && (
<WinWrapper>
{winner.charAt(0).toUpperCase() + winner.slice(1)} has won!
<RestartBtn onClick={restart}/>
</WinWrapper>
)}
<Grid>
{board.map((tile, ind) => (
<Tile key={ind} status={board[ind]} onClick={() => takeTurn(ind)}>
{renderMark(ind)}
</Tile>
))}
</Grid>
</GameWrapper>
</DemoCont>
</>
);
};
export default TicTacToe;
Note: Code snippets do not include styling details unless they are the focus of the exercise.
Copyright © 2022 Explore React