As a fresh graduate, I encountered Tic-Tac-Toe as a frequent interview question, particularly in frontend roles. It’s a versatile problem that effectively tests a candidate’s frontend development skills, logical thinking, and problem-solving abilities using data structures and algorithms.
I decided to implement Tic-Tac-Toe myself to solidify my understanding. While it might seem like a simple game, crafting a robust solution involves careful consideration of several factors.
I’d be happy to share my code and explain my approach. I believe that sharing knowledge is crucial for growth, and discussing solutions can lead to valuable insights and improvements.
App.jsx
import "./App.css"
import TicTacToe from "./components/TicTacToe"
const App = () => {
return (
)
}
export default App
TicTacToe.jsx
import useTicTacToe from "../hooks/useTicTacToe"
const TicTacToe = () => {
const {board, handleClick, getStatusMessage, resetGame} = useTicTacToe();
return (
{
board.map((player, i) => {
return
})
}
)
}
export default TicTacToe
Custom React hook
import { useState } from "react";
const intialGame = () => Array(9).fill(null);
const useTicTacToe = () => {
const [board, setBoard] = useState(intialGame())
const [isXNext, setIsXNext] = useState(true);
const winning_patterns = [
[0,1,2],
[3,4,5],
[6,7,8],
[0,4,8],
[2,4,6],
[0,3,6],
[1,4,7],
[2,5,8],
];
const calculateWinner = (currentBoard) => {
for(let i = 0 ; i < winning_patterns.length ; i++) {
const [a, b, c] = winning_patterns[i];
if(currentBoard[a] && currentBoard[a] === currentBoard[b] && currentBoard[a] === currentBoard[c]) {
return currentBoard[a];
}
}
return null;
}
const resetGame = () => {
setBoard(intialGame());
}
const getStatusMessage = () => {
const winner = calculateWinner(board);
if(winner) return `Player ${winner} Won 🎉`
if(!board.includes(null)) return `It's a Draw`
return `Player ${isXNext === true ? "X" : "O"} Turn`
}
const handleClick = (index) => {
const winner = calculateWinner(board);
if(winner) return null;
const newBoard = [...board];
newBoard[index] = isXNext ? "X" : "O";
setBoard(newBoard);
setIsXNext(!isXNext);
}
return {board, calculateWinner, resetGame, getStatusMessage, handleClick}
}
export default useTicTacToe;
Styling
.board {
width: 300px;
height: 300px;
display: grid;
grid-template-columns: repeat(3, 1fr);
justify-content: center;
}
.main {
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
gap: 10px;
}
.heading {
display: flex;
justify-content: center;
align-items: center;
gap: 10px;
}
.board button {
font-size: 35px;
}