Physical Address

304 North Cardinal St.
Dorchester Center, MA 02124

tic tac toe

How to Make Tic Tac Toe Using React

In this article, we will make a very famous game tic tac toe using react. Since tic tac toe is very famous and cool game which gives some nostalgia of our childhood memory. Also, this game is so popular among the developers, and they have made this game in many other programming languages.

As we know that JavaScript is so popular among developers, we will make this game using ReactJS. In this we will design the board for it and also, it will be two player game. We will add some logic to identify the winning conditions, and we will make a count of the wins for ‘x’ and ‘o’.

What is Tic Tac Toe Game?

Tic Tac Toe is a two-player game in which the objective is to take turns and mark the correct spaces in a 3×3 (or larger) grid. Think on your feet but also be careful, as the first player who places three of their marks in a horizontal, vertical or diagonal row wins the game. So this is the objective of this game, one player have ‘x’ and other one have ‘o’ sign.

Pre-requisites to Make Tic Tac Toe Using React

  • Basic knowledge of React Props
  • Good knowledge of React Components, hooks.
  • Basic concepts of React

Creating The Boxes

Now firstly we need to create the boxes for the game, for that we have created a component for boxes named Box.js. In this component we have passed value and onClick as the props which are come from App.js component. Initially, these have null value in each of these props.

In Box, we are adding the constant in which we are checking, if value is ‘x’ or ‘o’, if condition is true then we are adding box x, and if it is false then adding box o. So these are class names which are assigning dynamically. Hence, we have added a button, in which we are adding the value of the style constant as the class name. And we are modifying the value as onClick event gets triggered.

Then we have applied some basic CSS to this button and added some basic conditional CSS as well.

App.js

import { Box } from "./components/Box";

 function App(){  
  return (
    <div className="App">
      <Box value="X" onClick={null}/>
    </div>
  );
}

export default App;

Box.js

import React from 'react';

import "./Box.css";

export const Box = ({ value, onClick }) => {
    const style = value === "X" ? "box x" : "box o";

    return (
        <button className={style} onClick={onClick}>{value}</button>
    )
}

Box.css

.box {
  background-color: #ffffff;
  border: none;
  border-radius: 10%;
  box-shadow: 0px 0px 8px #888888;
  width: 5rem;
  height: 5rem;
  text-align: center;
  font-size: 5em;
  font-family: "Fredoka", sans-serif;
  font-weight: bold;
  line-height: 5rem;
  margin: 0.5rem;
}

.x {
  color: rgb(255, 70, 37);
}

.o {
  color: rgb(44, 135, 255);
}

.box:hover {
  box-shadow: 0px 0px 15px #888888;
}
Tic Tac Toe

Arranging The Boxes

Now we have created only one box and styled it, So we just need to add 8 more boxes to arrange them in 3×3 grid. For that we have added another component named Board, in this component we will manage the boxes. Since we are going to create the boxes through this Board component, we will remove the Box component from App.js Component and import our Board.js component and apply same props as before. In this Board component we will add the logic for Box component.

Then in the Board.js component, we are copying same code which we have added before in the App.js for box component. We will apply map() method here so that we can add the 9 buttons. Here we have added onClick={() => value === null && onClick(idx), so that we can control player selection, by doing this we cannot change the box value by clicking it again. Then we have applied some CSS like grid property, so the boxes will be arranged in the 3×3 boxes.

App.js

import React, { useState } from "react";

import { Board } from "./components/Board";

import './App.css';

const App = () => {

  const board = ["X","X","X","X","X","X","X","X","X"]

  return (
    <div className="App">
      <Board board={board} onClick={null} />
      
    </div>
  );
}

export default App;

Board.js

import React from 'react'

import { Box } from "./Box"
import "./Board.css"

export const Board = ({ board, onClick }) => {
  return (
    <div className="board">
      {
        board.map((value, idx) => {
          return <Box value={value} onClick={() => value === null && onClick(idx)} />;
        })
      }
    </div>
  )
}

Board.css

.board {
  display: grid;
  grid-template-columns: repeat(3, 6rem);
  place-items: center;
  justify-content: center;
}
Tic Tac Toe

Adding The Game Logic

Now we need to add the game logic, before that we need to remove static constant buttons, and we will add a state hook named board in which we have added array of 9 size with null value initially. Then we have added a function handleBoxClick on onClick event, In this function, we are adding map() method to modify the value. We also declared another state hook, in which we have initially added true. Then we will return X if the value of state will be true, if it is false then we will add O. We will update the board again using setBoard hook.

Now we need to change the value every second click, so for that we have set our xPlaying state to !xPlaying which will return an alternative value every time it will trigger.

App.js

import React, { useState } from "react";

import { Board } from "./components/Board";

import './App.css';

const App = () => {

  const [xPlaying, setXPlaying] = useState(true);
  const [board, setBoard] = useState(Array(9).fill(null))
  

  const handleBoxClick = (boxIdx) => {
    // Step 1: Update the board
    const updatedBoard = board.map((value, idx) => {
      if (idx === boxIdx) {
        return xPlaying ? "X" : "O";
      } else {
        return value;
      }
    })

    setBoard(updatedBoard);

  

    
    setXPlaying(!xPlaying);
  }


  return (
    <div className="App">
     
      <Board board={board} onClick={handleBoxClick} />
      
    </div>
  );
}

export default App;
Tic Tac Toe

Detecting The Winner

Since we have done main logic like switching turns and also created board, no we need to detect the winner. For that we have added an array in which we have added winning conditions, where we have mentioned some winning conditions like if X spotted on 0,1,2 position which is the first row of the board. Then we have declared a function for checking the winner, in this function, we have added a loop till array size. And it will iterate through win conditions and check if either player satisfies them, and we will return the player which satisfy the condition. We also added a message to get winner, but it will be temporary.

import React, { useState } from "react";

import { Board } from "./components/Board";

import './App.css';

const App = () => {

  const WIN_CONDITIONS = [
    [0, 1, 2],
    [3, 4, 5],
    [6, 7, 8],
    [0, 3, 6],
    [1, 4, 7],
    [2, 5, 8],
    [0, 4, 8],
    [2, 4, 6]
  ]

  const [xPlaying, setXPlaying] = useState(true);
  const [board, setBoard] = useState(Array(9).fill(null))
  

  const handleBoxClick = (boxIdx) => {
    // Step 1: Update the board
    const updatedBoard = board.map((value, idx) => {
      if (idx === boxIdx) {
        return xPlaying ? "X" : "O";
      } else {
        return value;
      }
    })

    setBoard(updatedBoard);

    // Step 2: Check if either player has won the game
    const winner = checkWinner(updatedBoard);

    

    // Step 3: Change active player
    setXPlaying(!xPlaying);
  }

  const checkWinner = (board) => {
    for (let i = 0; i < WIN_CONDITIONS.length; i++) {
      const [x, y, z] = WIN_CONDITIONS[i];

      // Iterate through win conditions and check if either player satisfies them
      if (board[x] && board[x] === board[y] && board[y] === board[z]) {
        document.write(`winner is ${board[x]}`);
        return board[x];
        
      }
    }
  }

 

  return (
    <div className="App">
      
      <Board board={board} onClick={handleBoxClick} />
      
    </div>
  );
}

export default App;
Tic Tac Toe

Adding Score Board

Now we need to score board, for that we have added a component named ScoreBoard.js. In this, we are getting props from App.js component for scores and xPlaying to get current score and player. Then we are adding these scores in some variables, then we are just added 2 spans, in which we have added players and their corresponding scores. We also added some smaller CSS for these two spans.

Now in App.js component, we have added another state for score with default values. Then we are checking the condition, in which, if we get winner, then we are just updating the state with increased value.

import React, { useState } from "react";

import { Board } from "./components/Board";

import { ScoreBoard } from "./components/ScoreBoard";
import './App.css';

const App = () => {

  const WIN_CONDITIONS = [
    [0, 1, 2],
    [3, 4, 5],
    [6, 7, 8],
    [0, 3, 6],
    [1, 4, 7],
    [2, 5, 8],
    [0, 4, 8],
    [2, 4, 6]
  ]

  const [xPlaying, setXPlaying] = useState(true);
  const [board, setBoard] = useState(Array(9).fill(null))
  const [scores, setScores] = useState({ xScore: 0, oScore: 0 })
  

  const handleBoxClick = (boxIdx) => {
    // Step 1: Update the board
    const updatedBoard = board.map((value, idx) => {
      if (idx === boxIdx) {
        return xPlaying ? "X" : "O";
      } else {
        return value;
      }
    })

    setBoard(updatedBoard);

    // Step 2: Check if either player has won the game
    const winner = checkWinner(updatedBoard);

    if (winner) {
      if (winner === "O") {
        let { oScore } = scores;
        oScore += 1;
        setScores({ ...scores, oScore })
      } else {
        let { xScore } = scores;
        xScore += 1;
        setScores({ ...scores, xScore })
      }
    }

    // Step 3: Change active player
    setXPlaying(!xPlaying);
  }

  const checkWinner = (board) => {
    for (let i = 0; i < WIN_CONDITIONS.length; i++) {
      const [x, y, z] = WIN_CONDITIONS[i];

      // Iterate through win conditions and check if either player satisfies them
      if (board[x] && board[x] === board[y] && board[y] === board[z]) {
        
        return board[x];
      }
    }
  }

  

  return (
    <div className="App">
      <ScoreBoard scores={scores} xPlaying={xPlaying} />
      <Board board={board} onClick={handleBoxClick} />
      
    </div>
  );
}

export default App;

ScoreBoard.js

import React from 'react'

import "./ScoreBoard.css"

export const ScoreBoard = ({ scores, xPlaying }) => {
  const { xScore, oScore } = scores;

  return (
    <div className="scoreboard">
      <span className={`score x-score ${!xPlaying && "inactive"}`}>X - {xScore}</span>
      <span className={`score o-score ${xPlaying && "inactive"}`}>O - {oScore}</span>
    </div>
  )
}
Tic Tac Toe

Resetting The Board

Now we have almost done most of the things, we just need to add reset button. For that, we have added ResetButton.js component. In this, we have added a button with onClick event. Now we will move to App.js, In this we will add another state for the game over with default false value. Then we have updated the value to true after we get winner, then we also have added a function in which we have again updated the value to false, and then we have added null value to the every box of the board.

import React, { useState } from "react";

import { Board } from "./components/Board";
import { ResetButton } from "./components/ResetButton";
import { ScoreBoard } from "./components/ScoreBoard";
import './App.css';

const App = () => {

  const WIN_CONDITIONS = [
    [0, 1, 2],
    [3, 4, 5],
    [6, 7, 8],
    [0, 3, 6],
    [1, 4, 7],
    [2, 5, 8],
    [0, 4, 8],
    [2, 4, 6]
  ]

  const [xPlaying, setXPlaying] = useState(true);
  const [board, setBoard] = useState(Array(9).fill(null))
  const [scores, setScores] = useState({ xScore: 0, oScore: 0 })
  const [gameOver, setGameOver] = useState(false);

  const handleBoxClick = (boxIdx) => {
    // Step 1: Update the board
    const updatedBoard = board.map((value, idx) => {
      if (idx === boxIdx) {
        return xPlaying ? "X" : "O";
      } else {
        return value;
      }
    })

    setBoard(updatedBoard);

    // Step 2: Check if either player has won the game
    const winner = checkWinner(updatedBoard);

    if (winner) {
      if (winner === "O") {
        let { oScore } = scores;
        oScore += 1;
        setScores({ ...scores, oScore })
      } else {
        let { xScore } = scores;
        xScore += 1;
        setScores({ ...scores, xScore })
      }
    }

    // Step 3: Change active player
    setXPlaying(!xPlaying);
  }

  const checkWinner = (board) => {
    for (let i = 0; i < WIN_CONDITIONS.length; i++) {
      const [x, y, z] = WIN_CONDITIONS[i];

      // Iterate through win conditions and check if either player satisfies them
      if (board[x] && board[x] === board[y] && board[y] === board[z]) {
        setGameOver(true);
        return board[x];
      }
    }
  }

  const resetBoard = () => {
    setGameOver(false);
    setBoard(Array(9).fill(null));
  }

  return (
    <div className="App">
      <ScoreBoard scores={scores} xPlaying={xPlaying} />
      <Board board={board} onClick={gameOver ? resetBoard : handleBoxClick} />
      <ResetButton resetBoard={resetBoard} />
    </div>
  );
}

export default App;

ResetButton.js

import React from 'react';

import "./ResetButton.css";

export const ResetButton = ({ resetBoard }) => {
    return (
        <button className="reset-btn" onClick={resetBoard}>Reset</button>
    )
}
Tic Tac Toe

Full Source Code of Tic Tac Toe in React

App.js

import React, { useState } from "react";

import { Board } from "./components/Board";
import { ResetButton } from "./components/ResetButton";
import { ScoreBoard } from "./components/ScoreBoard";
import './App.css';

const App = () => {

  const WIN_CONDITIONS = [
    [0, 1, 2],
    [3, 4, 5],
    [6, 7, 8],
    [0, 3, 6],
    [1, 4, 7],
    [2, 5, 8],
    [0, 4, 8],
    [2, 4, 6]
  ]

  const [xPlaying, setXPlaying] = useState(true);
  const [board, setBoard] = useState(Array(9).fill(null))
  const [scores, setScores] = useState({ xScore: 0, oScore: 0 })
  const [gameOver, setGameOver] = useState(false);

  const handleBoxClick = (boxIdx) => {
    // Step 1: Update the board
    const updatedBoard = board.map((value, idx) => {
      if (idx === boxIdx) {
        return xPlaying ? "X" : "O";
      } else {
        return value;
      }
    })

    setBoard(updatedBoard);

    // Step 2: Check if either player has won the game
    const winner = checkWinner(updatedBoard);

    if (winner) {
      if (winner === "O") {
        let { oScore } = scores;
        oScore += 1;
        setScores({ ...scores, oScore })
      } else {
        let { xScore } = scores;
        xScore += 1;
        setScores({ ...scores, xScore })
      }
    }

    // Step 3: Change active player
    setXPlaying(!xPlaying);
  }

  const checkWinner = (board) => {
    for (let i = 0; i < WIN_CONDITIONS.length; i++) {
      const [x, y, z] = WIN_CONDITIONS[i];

      // Iterate through win conditions and check if either player satisfies them
      if (board[x] && board[x] === board[y] && board[y] === board[z]) {
        setGameOver(true);
        return board[x];
      }
    }
  }

  const resetBoard = () => {
    setGameOver(false);
    setBoard(Array(9).fill(null));
  }

  return (
    <div className="App">
      <ScoreBoard scores={scores} xPlaying={xPlaying} />
      <Board board={board} onClick={gameOver ? resetBoard : handleBoxClick} />
      <ResetButton resetBoard={resetBoard} />
    </div>
  );
}

export default App;

Box.js

import React from 'react';

import "./Box.css";

export const Box = ({ value, onClick }) => {
    const style = value === "X" ? "box x" : "box o";

    return (
        <button className={style} onClick={onClick}>{value}</button>
    )
}

Board.js

import React from 'react'

import { Box } from "./Box"
import "./Board.css"

export const Board = ({ board, onClick }) => {
  return (
    <div className="board">
      {
        board.map((value, idx) => {
          return <Box value={value} onClick={() => value === null && onClick(idx)} />;
        })
      }
    </div>
  )
}

ScoreBoard.js

import React from 'react'

import "./ScoreBoard.css"

export const ScoreBoard = ({ scores, xPlaying }) => {
  const { xScore, oScore } = scores;

  return (
    <div className="scoreboard">
      <span className={`score x-score ${!xPlaying && "inactive"}`}>X - {xScore}</span>
      <span className={`score o-score ${xPlaying && "inactive"}`}>O - {oScore}</span>
    </div>
  )
}

ResetButton.js

import React from 'react';

import "./ResetButton.css";

export const ResetButton = ({ resetBoard }) => {
    return (
        <button className="reset-btn" onClick={resetBoard}>Reset</button>
    )
}

Check out video reference here:

You may also like:

Default image
reactjsguru
Articles: 44

Leave a Reply

Your email address will not be published.