Tic tac toe

DEMO
TicTacToe.jsx

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