import React, { useState, useEffect, useCallback } from 'react'; import { View, Text, StyleSheet, TouchableOpacity, Alert, SafeAreaView, StatusBar, Dimensions, } from 'react-native'; import { SimplePuzzleGame as GameClass } from './index'; import { GameDifficulty } from '../../core/types'; const { width: screenWidth } = Dimensions.get('window'); interface SimplePuzzleGameProps { gridSize?: number; difficulty?: 'easy' | 'medium' | 'hard'; onGameComplete?: (result: any) => void; onGameStart?: () => void; onMove?: (moveData: any) => void; showMenu?: boolean; autoStart?: boolean; // New props for customization title?: string; subtitle?: string; showStats?: boolean; enableHints?: boolean; enableReset?: boolean; theme?: { primaryColor?: string; secondaryColor?: string; backgroundColor?: string; textColor?: string; }; } export const SimplePuzzleGameComponent: React.FC = ({ gridSize = 3, difficulty = 'easy', onGameComplete, onGameStart, onMove, showMenu = true, autoStart = false, title = '🧩 משחק הפאזל', subtitle = 'ברוכים הבאים למשחק הפאזל המרתק!', showStats = true, enableHints = true, enableReset = true, theme = { primaryColor: '#3498db', secondaryColor: '#2ecc71', backgroundColor: '#f8f9fa', textColor: '#2c3e50' } }) => { const [currentScreen, setCurrentScreen] = useState(showMenu ? 'menu' : 'game'); const [gameInstance, setGameInstance] = useState(null); const [gameState, setGameState] = useState(null); const [isLoading, setIsLoading] = useState(false); const [gameStats, setGameStats] = useState({ moves: 0, time: 0, score: 0, isComplete: false, }); // Internal statistics that persist across games const [internalStats, setInternalStats] = useState({ totalGames: 0, bestScore: 0, bestTime: 0, totalMoves: 0, averageMoves: 0, }); // Helper functions const formatTime = (seconds: number): string => { const mins = Math.floor(seconds / 60); const secs = seconds % 60; return `${mins}:${secs.toString().padStart(2, '0')}`; }; const formatScore = (score: number): string => { return score.toLocaleString(); }; useEffect(() => { if (autoStart && !showMenu) { startNewGame(gridSize); } }, [autoStart, showMenu, gridSize]); const startNewGame = async (size: number = gridSize) => { setIsLoading(true); try { if (!GameClass) { console.error('❌ GameClass is undefined!'); Alert.alert('שגיאה', 'מחלקת המשחק לא נטענה מהספרייה'); setIsLoading(false); return; } const game = new GameClass(); console.log('🔄 GameClass', game); // Convert difficulty string to enum let gameDifficulty: GameDifficulty; switch (difficulty) { case 'easy': gameDifficulty = GameDifficulty.EASY; break; case 'medium': gameDifficulty = GameDifficulty.MEDIUM; break; case 'hard': gameDifficulty = GameDifficulty.HARD; break; default: gameDifficulty = GameDifficulty.EASY; } console.log('🔄 gameDifficulty', gameDifficulty); await game.initialize({ gameId: 'simple-puzzle', gridSize: size, difficulty: gameDifficulty, useNumbers: true, customization: { theme: { name: 'default', colors: { primary: '#3498db', secondary: '#2ecc71', accent: '#e74c3c', background: '#f8f9fa', surface: '#ffffff', text: '#2c3e50', textSecondary: '#7f8c8d', success: '#27ae60', warning: '#f39c12', error: '#e74c3c', }, fonts: { regular: 'System', bold: 'System', title: 'System', }, spacing: { xs: 4, sm: 8, md: 16, lg: 24, xl: 32, }, }, }, rules: {} } as any); // Set up event listeners with any type to bypass type checking (game as any).on('tileMove', (data: any) => { console.log('🔄 tileMove event', data); updateGameStats(game); onMove?.(data); }); (game as any).on('gameComplete', (result: any) => { console.log('🏁 Game complete!', result); // Update internal statistics const newTotalGames = internalStats.totalGames + 1; const newTotalMoves = internalStats.totalMoves + result.moves; const newAverageMoves = Math.round(newTotalMoves / newTotalGames); setInternalStats(prev => ({ totalGames: newTotalGames, bestScore: Math.max(prev.bestScore, result.score || 0), bestTime: prev.bestTime === 0 ? result.time : Math.min(prev.bestTime, result.time || 0), totalMoves: newTotalMoves, averageMoves: newAverageMoves, })); onGameComplete?.(result); if (showMenu) { Alert.alert( '🎉 כל הכבוד!', `השלמת את המשחק!\n` + `מהלכים: ${result.moves}\n` + `זמן: ${formatTime(Math.floor(result.time / 1000))}\n` + `ניקוד: ${formatScore(result.score)}`, [ { text: 'משחק חדש', onPress: () => startNewGame(size) }, { text: 'חזור לתפריט', onPress: () => setCurrentScreen('menu') }, ], ); } }); await game.start(); onGameStart?.(); setGameInstance(game); setGameState(game.getGameState()); updateGameStats(game); setCurrentScreen('game'); } catch (error) { console.error('❌ שגיאה ביצירת המשחק:', error); Alert.alert('שגיאה', 'נכשל ביצירת המשחק'); } finally { setIsLoading(false); } }; const updateGameStats = (game: any) => { const state = game.getGameState(); const currentTime = state.startTime ? Date.now() - state.startTime : 0; setGameStats({ moves: state.moves, time: currentTime, score: state.score, isComplete: state.isComplete, }); setGameState(state); }; const handleTilePress = useCallback( (row: number, col: number) => { if (!gameInstance || gameStats.isComplete) return; const canMove = gameInstance.canMoveTile({ row, col }); if (canMove) { const moveSuccess = gameInstance.moveTile({ row, col }); if (moveSuccess) { updateGameStats(gameInstance); } } }, [gameInstance, gameStats.isComplete], ); const getHint = () => { if (!gameInstance) return; const hint = gameInstance.getHint(); if (hint) { Alert.alert( '💡 רמז', `האריח הבא שצריך להזיז נמצא בעמודה ${hint.col + 1}, שורה ${ hint.row + 1 }`, [{ text: 'הבנתי', style: 'default' }], ); } else { Alert.alert('🎯', 'הפאזל כבר פתור!'); } }; const resetGame = () => { if (!gameInstance) return; Alert.alert('איפוס משחק', 'האם אתה בטוח שברצונך להתחיל מחדש?', [ { text: 'ביטול', style: 'cancel' }, { text: 'איפוס', style: 'destructive', onPress: () => { gameInstance.reset(); updateGameStats(gameInstance); }, }, ]); }; const renderTile = (tile: any, _index: number) => { if (tile.isEmpty) { return ( ); } const isInCorrectPosition = tile.position.row === tile.correctPosition.row && tile.position.col === tile.correctPosition.col; return ( handleTilePress(tile.position.row, tile.position.col)} activeOpacity={0.7} > {tile.value} ); }; const renderPuzzleBoard = () => { if (!gameState || !gameState.tiles) return null; const gridSize = Math.sqrt(gameState.tiles.length); const tileSize = Math.min((screenWidth - 80) / gridSize, 80); styles.tile.width = tileSize; styles.tile.height = tileSize; const board = Array(gridSize) .fill(null) .map(() => Array(gridSize).fill(null)); gameState.tiles.forEach((tile: any) => { board[tile.position.row][tile.position.col] = tile; }); return ( {board.map((row, rowIndex) => ( {row.map((tile, colIndex) => renderTile(tile, rowIndex * gridSize + colIndex), )} ))} ); }; const renderMenuScreen = () => ( {title} {subtitle} {showStats && internalStats.totalGames > 0 && ( 📊 הסטטיסטיקות שלך: משחקים: {internalStats.totalGames} ניקוד גבוה: {internalStats.bestScore.toLocaleString()} זמן מהיר: {internalStats.bestTime > 0 ? formatTime(Math.floor(internalStats.bestTime / 1000)) : '--:--'} ממוצע מהלכים: {internalStats.averageMoves} )} console.log('🔄 קל (3×3)')} disabled={isLoading} > קל (33×3) מתאים למתחילים startNewGame(4)} disabled={isLoading} > בינוני (4×4) אתגר בינוני startNewGame(5)} disabled={isLoading} > קשה (5×5) למומחים בלבד {isLoading && ( טוען משחק... )} 🎯 המטרה: סדרו את המספרים בסדר עולה{'\n'}✨ לחצו על אריח כדי להזיז אותו למקום הריק{'\n'}💡 השתמשו ברמזים אם אתם תקועים! ); const renderGameScreen = () => ( מהלכים {gameStats.moves} זמן {formatTime(Math.floor(gameStats.time / 1000))} ניקוד {formatScore(gameStats.score)} {renderPuzzleBoard()} {enableHints && ( 💡 רמז )} {enableReset && ( 🔄 איפוס )} {showMenu && ( setCurrentScreen('menu')} > 🏠 תפריט )} ); return currentScreen === 'menu' ? renderMenuScreen() : renderGameScreen(); }; const styles = StyleSheet.create({ container: { flex: 1, backgroundColor: '#f8f9fa', }, menuContainer: { flex: 1, padding: 20, justifyContent: 'center', alignItems: 'center', }, title: { fontSize: 32, fontWeight: 'bold', color: '#2c3e50', marginBottom: 8, textAlign: 'center', }, subtitle: { fontSize: 16, color: '#7f8c8d', marginBottom: 40, textAlign: 'center', }, menuButtons: { width: '100%', alignItems: 'center', marginBottom: 30, }, menuButton: { width: '80%', paddingVertical: 20, paddingHorizontal: 24, borderRadius: 12, marginBottom: 16, alignItems: 'center', elevation: 3, shadowColor: '#000', shadowOffset: { width: 0, height: 2 }, shadowOpacity: 0.1, shadowRadius: 4, }, easyButton: { backgroundColor: '#2ecc71', }, mediumButton: { backgroundColor: '#3498db', }, hardButton: { backgroundColor: '#e74c3c', }, menuButtonText: { color: 'white', fontSize: 18, fontWeight: 'bold', marginBottom: 4, }, menuButtonSubtext: { color: 'white', fontSize: 14, opacity: 0.9, }, loadingContainer: { padding: 20, }, loadingText: { fontSize: 16, color: '#7f8c8d', textAlign: 'center', }, infoContainer: { backgroundColor: 'white', padding: 20, borderRadius: 12, margin: 20, elevation: 2, shadowColor: '#000', shadowOffset: { width: 0, height: 1 }, shadowOpacity: 0.1, shadowRadius: 2, }, infoText: { fontSize: 14, color: '#2c3e50', textAlign: 'center', lineHeight: 20, }, statsContainer: { backgroundColor: '#ffffff', borderRadius: 12, padding: 20, marginBottom: 30, shadowColor: '#000', shadowOffset: { width: 0, height: 2 }, shadowOpacity: 0.1, shadowRadius: 4, elevation: 3, }, statsTitle: { fontSize: 18, fontWeight: 'bold', color: '#2c3e50', marginBottom: 15, textAlign: 'center', }, statsRow: { flexDirection: 'row', justifyContent: 'space-between', marginBottom: 8, }, statsText: { fontSize: 14, color: '#34495e', }, gameHeader: { backgroundColor: 'white', paddingVertical: 20, paddingHorizontal: 16, elevation: 2, shadowColor: '#000', shadowOffset: { width: 0, height: 1 }, shadowOpacity: 0.1, shadowRadius: 2, }, gameStatsContainer: { flexDirection: 'row', justifyContent: 'space-around', }, statItem: { alignItems: 'center', }, statLabel: { fontSize: 12, color: '#7f8c8d', marginBottom: 4, }, statValue: { fontSize: 18, fontWeight: 'bold', color: '#2c3e50', }, gameArea: { flex: 1, justifyContent: 'center', alignItems: 'center', padding: 20, }, puzzleBoard: { backgroundColor: 'white', padding: 10, borderRadius: 12, elevation: 4, shadowColor: '#000', shadowOffset: { width: 0, height: 2 }, shadowOpacity: 0.1, shadowRadius: 4, }, puzzleRow: { flexDirection: 'row', }, tile: { justifyContent: 'center', alignItems: 'center', margin: 2, borderRadius: 8, elevation: 2, shadowColor: '#000', shadowOffset: { width: 0, height: 1 }, shadowOpacity: 0.1, shadowRadius: 2, width: 70, height: 70, }, correctTile: { backgroundColor: '#2ecc71', }, incorrectTile: { backgroundColor: '#3498db', }, emptyTile: { backgroundColor: 'transparent', elevation: 0, shadowOpacity: 0, }, tileText: { fontSize: 20, fontWeight: 'bold', }, correctTileText: { color: 'white', }, incorrectTileText: { color: 'white', }, gameControls: { flexDirection: 'row', justifyContent: 'space-around', paddingVertical: 20, paddingHorizontal: 16, backgroundColor: 'white', elevation: 2, shadowColor: '#000', shadowOffset: { width: 0, height: -1 }, shadowOpacity: 0.1, shadowRadius: 2, }, controlButton: { paddingVertical: 12, paddingHorizontal: 16, borderRadius: 8, elevation: 2, shadowColor: '#000', shadowOffset: { width: 0, height: 1 }, shadowOpacity: 0.1, shadowRadius: 2, }, hintButton: { backgroundColor: '#f39c12', }, resetButton: { backgroundColor: '#e74c3c', }, backButton: { backgroundColor: '#95a5a6', }, controlButtonText: { color: 'white', fontSize: 14, fontWeight: 'bold', }, });