62 lines
1.9 KiB
React
62 lines
1.9 KiB
React
import { useState } from 'react';
|
|
|
|
export default function TicTacToe() {
|
|
const [board, setBoard] = useState(Array(9).fill(null));
|
|
const [xIsNext, setXIsNext] = useState(true);
|
|
const winner = calculateWinner(board);
|
|
const status = winner
|
|
? `Winner: ${winner}`
|
|
: `Next player: ${xIsNext ? 'X' : 'O'}`;
|
|
|
|
function handleClick(i) {
|
|
const boardCopy = [...board];
|
|
if (winner || boardCopy[i]) return;
|
|
boardCopy[i] = xIsNext ? 'X' : 'O';
|
|
setBoard(boardCopy);
|
|
setXIsNext(!xIsNext);
|
|
}
|
|
|
|
function 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 [a, b, c] of lines) {
|
|
if (squares[a] && squares[a] === squares[b] && squares[a] === squares[c]) {
|
|
return squares[a];
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
const renderSquare = (i) => (
|
|
<button className="square" onClick={() => handleClick(i)}>
|
|
{board[i]}
|
|
</button>
|
|
);
|
|
|
|
const statusStyle = { marginBottom: '1rem', fontSize: '1.2rem' };
|
|
const boardStyle = { display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gap: '4px', width: '300px', margin: '0 auto' };
|
|
const squareStyle = { background: '#fff', border: '1px solid #999', fontSize: '2rem', width: '100%', height: '80px', display: 'flex', alignItems: 'center', justifyContent: 'center', cursor: 'pointer' };
|
|
|
|
return (
|
|
<div style={{ padding: '2rem', fontFamily: 'sans-serif' }}>
|
|
<h1>Tic Tac Toe</h1>
|
|
<div style={statusStyle}>{status}</div>
|
|
<div style={boardStyle}>
|
|
{[0, 1, 2, 3, 4, 5, 6, 7, 8].map(i => (
|
|
<div key={i} style={squareStyle}>
|
|
{renderSquare(i)}
|
|
</div>
|
|
))}
|
|
</div>
|
|
{winner && (
|
|
<button onClick={() => { setBoard(Array(9).fill(null)); setXIsNext(true); }}>
|
|
Play Again
|
|
</button>
|
|
)}
|
|
</div>
|
|
);
|
|
}
|