Tic-tac-toe is a simple game played on a grid with three rows and three columns. Two players take turns marking the grid with “X” and “O.” The way to win the game is to get three marks in a row, either horizontally, vertically, or diagonally. It is a fun and easy game that anyone can play.
Here, we will discuss the necessary steps to implement this game in React, which will consist of extra features like a reset button and handling the case where there is a tie in the game.
In case we haven’t created a React app on our systems, we can execute the commands below, one after the other:
npx create-react-app tic-tac-toecd tic-tac-toe
Note: In the place of the
tic-tac-toe
folder name, we can write a folder name of our choice.
For more information on creating a React app, check out this link!
Now, we move on to the main parts of the code in the App.js
file where we start off initializing the state of the board with nine squares using the board
variable and store the state of each player’s turn in the xIsNext
variable.
// Initialize state for the game board and player turnconst [board, setBoard] = useState(Array(9).fill(null));//If xIsNext is true, it will be the turn of the player with the symbol 'X'. Else, it will be the player with the symbol 'O'const [xIsNext, setXIsNext] = useState(true);
Note: By default, the game will start with the player with the symbol “X.” This can be changed to start off the game with the symbol “O.”
Next, we make the function that decides the rules of the game and its winner, as shown below:
// Determines if there's a winner based on the current board configurationfunction calculateWinner(squares) {//hardcoding all winning combinationsconst 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],];// Checks all possible winning combinationsfor (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]; // Returns the winning symbol if there's a match}}return null; // Returns null if there's no winner}
This function checks the squares
array (representing the game board) against all possible winning combinations in the lines
constant to determine if there’s a winner. It returns the winning symbol (“X” or “O”). In the case of a tie, the null
value is returned.
We also make the function that is responsible for ensuring that the square isn’t already filled and that there isn’t a winner yet before updating the board state and toggling to the next player’s turn:
// Handles clicks on the board squaresconst handleClick = (index) => {// Checks if there's a winner or if the square is already filledif (calculateWinner(board) || board[index]) {return;}// Creates a new board array, updates the clicked square, and toggles the player turnconst newBoard = [...board];newBoard[index] = xIsNext ? 'X' : 'O';setBoard(newBoard);setXIsNext(!xIsNext);};
A copy of the current game board is created with the newBoard
variable using the spread operator ([...board]
). It updates the square at the clicked index (newBoard[index]
) with the current player’s symbol (“X” or “O”) based on the xIsNext
state, resulting in the game board state being updated.
Afterward, we write the code for displaying the status of the game on our screens. In other words, we display whether the game has been won by the player having the symbol “X” or “O,” or if the game is tied.
// Calculates if there's a winner based on the current board stateconst winner = calculateWinner(board);// Checks if the game is tied: all squares are filled and there's no winnerconst isTied = board.every((square) => square !== null) && !winner;let status;//displaying the winning player's symbolif (winner) {status = `Winner: ${winner}`;//displaying the "It's a tie!" message in case of a tie} else if (isTied) {status = 'It\'s a tie!';//switching between players turns if no winner is achieved at a certain point} else {status = `Player's turn: ${xIsNext ? 'X' : 'O'}`;}
Finally, we make sure that the game is rendered properly in the React app by rendering each individual square, as well as the whole board, when the players make their moves.
The code to render each tic-tac-toe square is given below:
const renderSquare = (index) => {return (<button className="square" onClick={() => handleClick(index)}>{board[index]}</button>);};
Every square button on the game board is generated using the <button>
element. Each button shows the value from the board
array and is linked to the handleClick
function for user interaction.
By taking the index
parameter as the input, it inserts the value (“X,” “O,” or null
) from the board
array at the given index
into the button text, dynamically displaying the current state of the square on the game board.
Here is the code to render the entire board where every square at each index is rendered individually:
return (<div className="game"><div className="game-board"><div className="board-row">{renderSquare(0)}{renderSquare(1)}{renderSquare(2)}</div><div className="board-row">{renderSquare(3)}{renderSquare(4)}{renderSquare(5)}</div><div className="board-row">{renderSquare(6)}{renderSquare(7)}{renderSquare(8)}</div></div><div className="game-info"><div>{status}</div><button onClick={resetBoard}>Reset Board</button></div></div>);
As mentioned above, we implement a basic function that will reset the game board at any time of the game by setting the elements of the board
array to null and reset the game with the turn of player “X.”
const resetBoard = () => {setBoard(Array(9).fill(null));setXIsNext(true);};
Once all of these code sections are implemented, we are all good to go!
All of the steps explained above can be combined in the App.js
file of our React project. See the code below to see the game in action!
This React-based tic-tac-toe game enables players to engage in a classic game of strategy and tactics using efficient state management and UI rendering. The seamless integration of game logic, state updates, and dynamic UI components allows for an intuitive gameplay experience, which React is renowned for.
Free Resources