import { useState, useEffect } from 'react';
// Main App component for the Tic-Tac-Toe game.
export default function App() {
// State for the board, an array of 9 elements (null, 'X', or 'O').
const [board, setBoard] = useState(Array(9).fill(null));
// State for the current player, true for 'X', false for 'O'.
const [xIsNext, setXIsNext] = useState(true);
// State for the winner, null if no winner yet.
const [winner, setWinner] = useState(null);
// State for the message to display.
const [status, setStatus] = useState('');
// useEffect hook to update the game status message.
useEffect(() => {
// Check for a winner every time the board state changes.
const calculatedWinner = calculateWinner(board);
if (calculatedWinner) {
setWinner(calculatedWinner);
setStatus(`Le joueur ${calculatedWinner} a gagné !`);
} else if (board.every(Boolean)) {
// Check for a draw if the board is full and there's no winner.
setStatus('Match nul !');
} else {
// Announce the next player.
setStatus(`Prochain joueur : ${xIsNext ? 'X' : 'O'}`);
}
}, [board, xIsNext]);
// Handle a click on a square.
const handleClick = (i) => {
// If the square is already filled or there is a winner, do nothing.
if (board[i] || winner) {
return;
}
// Create a copy of the board to avoid mutating state directly.
const nextBoard = board.slice();
// Fill the square with the current player's symbol.
nextBoard[i] = xIsNext ? 'X' : 'O';
// Update the board and switch players.
setBoard(nextBoard);
setXIsNext(!xIsNext);
};
// Reset the game to its initial state.
const handleReset = () => {
setBoard(Array(9).fill(null));
setXIsNext(true);
setWinner(null);
setStatus('');
};
// Function to calculate the winner based on winning lines.
const calculateWinner = (squares) => {
const 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]
];
for (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];
}
}
return null;
};
// Component for a single square on the board.
const Square = ({ value, onClick }) => {
return (
<button
className="w-24 h-24 sm:w-28 sm:h-28 lg:w-32 lg:h-32 bg-slate-800 text-white text-5xl font-bold border-2 border-slate-700 rounded-lg shadow-lg hover:bg-slate-700 transition-colors duration-200 flex items-center justify-center disabled:cursor-not-allowed"
onClick={onClick}
disabled={value !== null}
>
{value}
</button>
);
};
return (
<div className="flex flex-col items-center justify-center min-h-screen bg-gray-900 text-white font-sans p-4">
<div className="text-4xl sm:text-5xl font-extrabold mb-8 text-transparent bg-clip-text bg-gradient-to-r from-green-400 to-blue-500">
Jeu de Morpion
</div>
<div className="mb-6 text-xl sm:text-2xl font-semibold text-gray-300">
{status}
</div>
<div className="grid grid-cols-3 gap-2 sm:gap-4 mb-8">
{board.map((value, i) => (
<Square key={i} value={value} onClick={() => handleClick(i)} />
))}
</div>
<button
className="px-6 py-3 bg-gradient-to-r from-purple-600 to-indigo-600 text-white font-bold text-lg rounded-full shadow-lg hover:from-purple-700 hover:to-indigo-700 transition-transform duration-200 transform hover:scale-105 focus:outline-none focus:ring-4 focus:ring-purple-500 focus:ring-opacity-50"
onClick={handleReset}
>
Recommencer la partie
</button>
</div>
);
}
Jouez à Grégule et Dangereux le Jeu Vidéo