@khazh/tic-tac-toe-react
Version:
A customizable Tic Tac Toe game component for React with AI opponent, configurable board size, and win conditions
163 lines • 8.01 kB
JavaScript
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
import Button from "./atoms/Button";
import { useGameState } from "../hooks/useGameState";
import { useScore } from "../hooks/useScore";
import { useAI } from "../hooks/useAI";
import { useGameMode } from "../hooks/useGameMode";
import { useBoardSize } from "../hooks/useBoardSize";
import { useWinLength } from "../hooks/useWinLength";
const TicTacToe = ({ initialBoardSize = 10, initialWinLength = 4, showConfigControls = true, className = "", style = {}, onWinner = () => { }, }) => {
const { boardSize } = useBoardSize(initialBoardSize);
const { winLength } = useWinLength(initialBoardSize, initialWinLength);
const { gameMode } = useGameMode();
const { gameState, makeMove, resetGame } = useGameState(boardSize, winLength);
const { updateScore, getTotalGames } = useScore();
// Handle AI moves
const handleAIMove = (row, col) => {
const result = makeMove(row, col);
if (result) {
updateScore(result.winner, result.isDraw);
}
};
useAI(gameMode, gameState.currentPlayer, gameState.board, gameState.winner, gameState.isDraw, gameState.config, handleAIMove);
const handleClick = (row, col) => {
const result = makeMove(row, col);
if (result) {
updateScore(result.winner, result.isDraw);
}
};
const handleReset = () => {
resetGame();
};
const getGameStatus = () => {
if (gameState.winner) {
if (gameState.winner === "X") {
onWinner?.();
}
return `Winner: ${gameState.winner}`;
}
if (gameState.isDraw)
return "It's a draw!";
return `Current player: ${gameState.currentPlayer}`;
};
const getCellSize = () => {
// Responsive cell sizing based on board size and screen width
const isMobile = window.innerWidth <= 768;
const isSmallMobile = window.innerWidth <= 480;
if (isSmallMobile) {
if (boardSize <= 4)
return 60;
if (boardSize <= 6)
return 45;
if (boardSize <= 8)
return 35;
return 28;
}
if (isMobile) {
if (boardSize <= 4)
return 70;
if (boardSize <= 6)
return 55;
if (boardSize <= 8)
return 45;
return 35;
}
// Desktop
if (boardSize <= 4)
return 80;
if (boardSize <= 6)
return 60;
if (boardSize <= 8)
return 50;
return 40;
};
const cellSize = getCellSize();
const fontSize = Math.max(1.2, 2.5 - (boardSize - 3) * 0.2);
return (_jsxs("div", { className: `tic-tac-toe-container ${className}`, style: {
textAlign: "center",
fontFamily: "Arial, sans-serif",
maxWidth: "100vw",
width: "100%",
margin: "0 auto",
padding: "1rem",
boxSizing: "border-box",
minHeight: "100vh",
display: "flex",
flexDirection: "column",
justifyContent: "center",
...style,
}, children: [_jsx("h1", { style: {
color: "#333",
marginBottom: "1rem",
fontSize: "clamp(1.5rem, 5vw, 2.5rem)",
fontWeight: "bold",
lineHeight: 1.2,
}, children: "Tic Tac Toe" }), showConfigControls && (_jsx("div", { style: { marginBottom: "1rem" }, children: _jsxs("div", { style: {
background: "#e7f3ff",
padding: "clamp(0.5rem, 2vw, 0.75rem)",
borderRadius: "0.5rem",
border: "2px solid #007bff",
marginTop: "0.5rem",
fontSize: "clamp(0.8rem, 2.5vw, 1rem)",
}, children: [_jsxs("strong", { style: { color: "#007bff" }, children: ["\uD83C\uDFAF Win Condition: ", winLength, " in a row"] }), _jsx("div", { style: {
fontSize: "clamp(0.7rem, 2vw, 0.9rem)",
color: "#666",
marginTop: "0.25rem",
}, children: winLength === 3
? "Classic Tic-Tac-Toe"
: winLength === 4
? "Connect Four Style"
: `${winLength}-in-a-Row Challenge` })] }) })), _jsx("div", { style: {
marginBottom: "1rem",
padding: "clamp(0.4rem, 2vw, 0.5rem)",
background: gameState.winner
? "#d4edda"
: gameState.isDraw
? "#fff3cd"
: "#7f8eab",
borderRadius: "0.5rem",
fontWeight: "bold",
fontSize: "clamp(0.9rem, 2.5vw, 1.1rem)",
}, children: getGameStatus() }), _jsx("div", { style: {
display: "inline-block",
background: "#fff",
padding: "clamp(0.5rem, 2vw, 1rem)",
borderRadius: "0.5rem",
boxShadow: "0 4px 6px rgba(0, 0, 0, 0.1)",
overflow: "auto",
maxWidth: "100%",
maxHeight: "70vh",
margin: "0 auto",
}, children: gameState.board.map((row, i) => (_jsx("div", { style: { display: "flex" }, children: row.map((cell, j) => (_jsx(Button, { style: {
width: cellSize,
height: cellSize,
margin: 1,
fontSize: `${fontSize}rem`,
fontWeight: "bold",
border: "2px solid #dee2e6",
background: cell ? "#e9ecef" : "#fff",
color: cell === "X" ? "#dc3545" : "#28a745",
minWidth: cellSize,
minHeight: cellSize,
padding: 0,
display: "flex",
alignItems: "center",
justifyContent: "center",
touchAction: "manipulation",
}, onClick: () => handleClick(i, j), disabled: !!cell || !!gameState.winner || !!gameState.isDraw, children: cell }, j))) }, i))) }), _jsx("div", { style: { marginTop: "1rem" }, children: _jsx(Button, { onClick: handleReset, style: {
background: "#dc3545",
color: "#fff",
fontSize: "clamp(0.9rem, 2.5vw, 1rem)",
padding: "clamp(0.6rem, 2vw, 0.8rem) clamp(1rem, 3vw, 1.5rem)",
minHeight: "44px",
}, children: "New Game" }) }), _jsxs("div", { style: {
marginTop: "1rem",
padding: "clamp(0.5rem, 2vw, 1rem)",
background: "#f8f9fa",
borderRadius: "0.5rem",
fontSize: "clamp(0.7rem, 2vw, 0.9rem)",
color: "#6c757d",
}, children: [gameMode === "ai" && (_jsxs("div", { children: [_jsx("strong", { children: "AI Mode:" }), " You play as X, AI plays as O"] })), _jsxs("div", { style: { marginTop: "0.5rem" }, children: [_jsx("strong", { children: "Board:" }), " ", boardSize, "x", boardSize, " |", " ", _jsx("strong", { children: "Win Condition:" }), " ", gameState.config.winLength, " in a row"] }), _jsxs("div", { style: { marginTop: "0.5rem" }, children: [_jsx("strong", { children: "Total Games:" }), " ", getTotalGames()] })] })] }));
};
export default TicTacToe;
//# sourceMappingURL=TicTacToe.js.map