UNPKG

@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
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