init basic tictactoe game
This commit is contained in:
11
src/tictactoe/Board.tsx
Normal file
11
src/tictactoe/Board.tsx
Normal file
@@ -0,0 +1,11 @@
|
||||
import Square from "./Square";
|
||||
|
||||
export default function Board({ squares, onClick }) {
|
||||
return (
|
||||
<div className="board">
|
||||
{squares.map((value, i) => (
|
||||
<Square key={i} value={value} onClick={() => onClick(i)} />
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
7
src/tictactoe/Square.tsx
Normal file
7
src/tictactoe/Square.tsx
Normal file
@@ -0,0 +1,7 @@
|
||||
export default function Square({ value, onClick }) {
|
||||
return (
|
||||
<button className="square" onClick={onClick}>
|
||||
{value}
|
||||
</button>
|
||||
);
|
||||
}
|
||||
52
src/tictactoe/TicTacToe.tsx
Normal file
52
src/tictactoe/TicTacToe.tsx
Normal file
@@ -0,0 +1,52 @@
|
||||
import { useState } from "react";
|
||||
import Board from "./Board";
|
||||
|
||||
export default function TicTacToe() {
|
||||
const [board, setBoard] = useState(Array(9).fill(null));
|
||||
const [xIsNext, setXIsNext] = useState(true);
|
||||
|
||||
const winner = calculateWinner(board);
|
||||
|
||||
function handleSquareClick(i: number) {
|
||||
if (board[i] || winner) return;
|
||||
|
||||
const newBoard = board.slice();
|
||||
newBoard[i] = xIsNext ? "X" : "O";
|
||||
|
||||
setBoard(newBoard);
|
||||
setXIsNext(!xIsNext);
|
||||
}
|
||||
|
||||
function reset() {
|
||||
setBoard(Array(9).fill(null));
|
||||
setXIsNext(true);
|
||||
}
|
||||
|
||||
const status = winner
|
||||
? `Winner: ${winner}`
|
||||
: `Next player: ${xIsNext ? "X" : "O"}`;
|
||||
|
||||
return (
|
||||
<div className="game-container">
|
||||
<h1>Tic Tac Toe</h1>
|
||||
<div className="status">{status}</div>
|
||||
<Board squares={board} onClick={handleSquareClick} />
|
||||
<button className="reset-btn" onClick={reset}>Reset</button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
// --- winner logic ---
|
||||
function calculateWinner(sq: any[]) {
|
||||
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 (sq[a] && sq[a] === sq[b] && sq[a] === sq[c]) {
|
||||
return sq[a];
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
53
src/tictactoe/styles.css
Normal file
53
src/tictactoe/styles.css
Normal file
@@ -0,0 +1,53 @@
|
||||
body {
|
||||
font-family: sans-serif;
|
||||
background: #f4f4f4;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
padding-top: 50px;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.game-container {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.board {
|
||||
width: 300px;
|
||||
height: 300px;
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
gap: 6px;
|
||||
margin: 20px auto;
|
||||
}
|
||||
|
||||
.square {
|
||||
background: white;
|
||||
border: 2px solid #333;
|
||||
font-size: 2rem;
|
||||
font-weight: bold;
|
||||
cursor: pointer;
|
||||
height: 100px;
|
||||
width: 100px;
|
||||
}
|
||||
|
||||
.square:hover {
|
||||
background: #eee;
|
||||
}
|
||||
|
||||
.status {
|
||||
font-size: 1.4rem;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.reset-btn {
|
||||
padding: 10px 20px;
|
||||
background: #333;
|
||||
color: white;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
.reset-btn:hover {
|
||||
background: #555;
|
||||
}
|
||||
Reference in New Issue
Block a user