import React, { useState, useEffect } from 'react'; import { View, Text, StyleSheet, Alert, ScrollView, ActivityIndicator } from 'react-native'; import { GameContainer } from '../../components/common/GameContainer'; import { GameButton } from '../../components/common/GameHeader'; import { SimplePuzzleGame, PuzzleGameState } from './SimplePuzzleGame'; import { PuzzleBoard } from './components'; import { performanceMonitor } from '../../utils/performance'; import { gameErrorHandler, ErrorCategory, ErrorSeverity } from '../../utils/errorHandler'; import { gameDataCache } from '../../utils/cache'; import { GameEventType } from '../../core/types'; interface SimplePuzzleScreenProps { gameInstance: SimplePuzzleGame; onGameComplete: (result: any) => void; onGameExit: () => void; gridSize?: number; useNumbers?: boolean; imageUrl?: any; difficulty?: 'easy' | 'medium' | 'hard'; showHints?: boolean; enableAnimations?: boolean; playerId?: string; } /** * Enhanced puzzle game screen with advanced features */ export const SimplePuzzleScreen: React.FC = ({ gameInstance, onGameComplete, onGameExit, gridSize = 3, useNumbers, imageUrl, difficulty = 'medium', showHints = true, enableAnimations = true, playerId }) => { // Use the new image for the puzzle const puzzleImageUrl = require('../../../assets/images/GOLDA1.jpeg'); const effectiveUseNumbers = false; // Use image instead of numbers const [gameState, setGameState] = useState(gameInstance.getGameState()); const [showMenu, setShowMenu] = useState(false); const [moves, setMoves] = useState(0); const [score, setScore] = useState(0); const [isLoading, setIsLoading] = useState(true); const [error, setError] = useState(null); const [gameStartTime, setGameStartTime] = useState(0); const [bestScore, setBestScore] = useState(0); const [gameTime, setGameTime] = useState(0); const [isPaused, setIsPaused] = useState(false); // Timer effect useEffect(() => { let interval: any; if (gameStartTime > 0 && !gameState.isComplete && !isPaused) { interval = setInterval(() => { setGameTime(Math.floor((Date.now() - gameStartTime) / 1000)); }, 1000); } return () => { if (interval) clearInterval(interval); }; }, [gameStartTime, gameState.isComplete, isPaused]); useEffect(() => { // Initialize game with error handling and caching const initGame = async () => { try { setIsLoading(true); setError(null); // Try to load cached best score if (playerId) { const cachedData = await gameDataCache.getPlayerData(playerId); if (cachedData?.bestScores?.['simple-puzzle']) { setBestScore(cachedData.bestScores['simple-puzzle']); } } // Record game load time const loadStartTime = Date.now(); performanceMonitor.startGameSession('simple-puzzle'); await gameInstance.initialize({ gameId: 'simple-puzzle', difficulty: difficulty as any, customization: { theme: {} as any }, rules: {}, gridSize, useNumbers: effectiveUseNumbers, imageUrl: puzzleImageUrl }); await gameInstance.start(); const loadTime = Date.now() - loadStartTime; performanceMonitor.recordGameLoadTime('simple-puzzle', loadTime); // Verify that the game has tiles const initialState = gameInstance.getGameState(); if (!initialState.tiles || initialState.tiles.length === 0) { throw new Error('המשחק לא אותחל עם אריחים'); } updateGameState(); setGameStartTime(Date.now()); setIsLoading(false); } catch (error) { const errorMessage = error instanceof Error ? error.message : 'משחק נכשל בהתחלה'; setError(errorMessage); setIsLoading(false); await gameErrorHandler.handleError( error as Error, ErrorCategory.INITIALIZATION, ErrorSeverity.HIGH, { gameId: 'simple-puzzle' } ); } }; initGame(); // Set up event listeners const handleGameComplete = async (data: any) => { const completionTime = Math.floor((Date.now() - gameStartTime) / 1000); // Update best score if needed if (data.completed && data.score > bestScore) { setBestScore(data.score); // Cache the new best score if (playerId) { const cachedData = await gameDataCache.getPlayerData(playerId) || {}; cachedData.bestScores = cachedData.bestScores || {}; cachedData.bestScores['simple-puzzle'] = data.score; await gameDataCache.cachePlayerData(playerId, cachedData); } } // End performance monitoring const benchmark = performanceMonitor.endGameSession('simple-puzzle'); Alert.alert( data.completed ? 'כל הכבוד! 🎉' : 'נגמר הזמן ⏰', data.completed ? `פתרת את הפאזל ב-${moves} מהלכים ב-${completionTime} שניות!\nניקוד: ${data.score}\n${data.score > bestScore ? '🎊 שיא חדש!' : ''}` : 'אולי בפעם הבאה!', [ { text: 'שחק שוב', onPress: handleRestart }, { text: 'חזור', onPress: onGameExit } ] ); onGameComplete({ ...data, completionTime, benchmark }); }; const handlePlayerAction = (data: any) => { updateGameState(); if (data.action === 'tile_moved') { setMoves(data.moves); } }; const handleScoreUpdate = (newScore: number) => { setScore(newScore); }; gameInstance.on(GameEventType.GAME_COMPLETED, handleGameComplete); gameInstance.on(GameEventType.PLAYER_ACTION, handlePlayerAction); gameInstance.on(GameEventType.SCORE_UPDATED, handleScoreUpdate); return () => { gameInstance.off(GameEventType.GAME_COMPLETED, handleGameComplete); gameInstance.off(GameEventType.PLAYER_ACTION, handlePlayerAction); gameInstance.off(GameEventType.SCORE_UPDATED, handleScoreUpdate); performanceMonitor.endGameSession('simple-puzzle'); }; }, []); const updateGameState = () => { try { const renderStartTime = Date.now(); const newState = gameInstance.getGameState(); // Ensure we have tiles in the game state if (!newState.tiles || newState.tiles.length === 0) { console.warn('Puzzle game state has no tiles, reinitializing...'); handleRestart(); return; } setGameState(newState); setMoves(newState.moves); const renderTime = Date.now() - renderStartTime; performanceMonitor.recordRenderTime('simple-puzzle', renderTime); } catch (error) { console.error('Error updating game state:', error); gameErrorHandler.handleError( error as Error, ErrorCategory.GAME_LOGIC, ErrorSeverity.MEDIUM, { gameId: 'simple-puzzle' } ); } }; const handleTilePress = async (row: number, col: number) => { try { const moveStartTime = Date.now(); const success = gameInstance.moveTile({ row, col }); const moveTime = Date.now() - moveStartTime; // Record input latency performanceMonitor.recordInputLatency('simple-puzzle', moveTime); if (!success) { // Track invalid moves for analytics console.log('Invalid move attempted at:', { row, col }); } } catch (error) { await gameErrorHandler.handleError( error, ErrorCategory.USER_INPUT, ErrorSeverity.MEDIUM, { gameId: 'simple-puzzle', additionalInfo: { row, col } } ); } }; const handleRestart = async () => { try { gameInstance.reset(); updateGameState(); setMoves(0); setScore(0); setGameTime(0); setGameStartTime(Date.now()); setShowMenu(false); setIsPaused(false); // Cache game state for recovery if (playerId) { await gameDataCache.cacheGameState('simple-puzzle', { playerId, difficulty, gridSize, timestamp: Date.now() }); } } catch (error) { await gameErrorHandler.handleError( error, ErrorCategory.GAME_LOGIC, ErrorSeverity.MEDIUM, { gameId: 'simple-puzzle' } ); } }; const handleHint = () => { try { const hint = gameInstance.getHint(); if (hint) { Alert.alert('רמז 💡', `נסה להזיז את האריח בשורה ${hint.row + 1}, עמודה ${hint.col + 1}`); } else { Alert.alert('רמז 💡', 'לא נמצא רמז כרגע, המשך לנסות!'); } } catch (error) { gameErrorHandler.handleError( error, ErrorCategory.GAME_LOGIC, ErrorSeverity.LOW, { gameId: 'simple-puzzle' } ); } }; const handlePause = () => { setIsPaused(true); setShowMenu(true); }; const handleResume = () => { setIsPaused(false); setShowMenu(false); }; const getDifficultyText = () => { switch (difficulty) { case 'easy': return 'קל'; case 'medium': return 'בינוני'; case 'hard': return 'קשה'; default: return 'בינוני'; } }; const formatTime = (seconds: number) => { const mins = Math.floor(seconds / 60); const secs = seconds % 60; return `${mins.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`; }; const progress = gameState.tiles.length > 0 ? (gameState.tiles.filter(tile => tile.position.row === tile.correctPosition.row && tile.position.col === tile.correctPosition.col ).length / gameState.tiles.length) * 100 : 0; // Debug info - show if no tiles if (gameState.tiles.length === 0) { console.warn('No tiles in game state:', gameState); } // Loading screen if (isLoading) { return ( מכין את הפאזל... ); } // Error screen if (error) { return ( ⚠️ {error} { setError(null); setIsLoading(true); // Re-initialize }} variant="primary" size="large" /> ); } return ( {/* Enhanced Game Stats */} מהלכים {moves} זמן {formatTime(gameTime)} ניקוד {score} {bestScore > 0 && ( שיא {bestScore} )} {/* Puzzle Board */} gameInstance.canMoveTile(position)} useNumbers={effectiveUseNumbers} imageUrl={puzzleImageUrl} showHints={showHints && !gameState.isComplete} animateLastMove={enableAnimations} /> {/* Enhanced Game Controls */} { Alert.alert( 'התחל מחדש?', 'האם אתה בטוח שברצונך להתחיל מחדש? התקדמותך הנוכחית תאבד.', [ { text: 'ביטול', style: 'cancel' }, { text: 'התחל מחדש', onPress: handleRestart } ] ); }} variant="warning" size="small" style={styles.controlButton} /> {/* Enhanced Pause Menu */} {showMenu && ( משחק מושהה מהלכים: {moves} זמן: {formatTime(gameTime)} ניקוד: {score} {bestScore > 0 && ( שיא אישי: {bestScore} )} { setShowMenu(false); handleRestart(); }} variant="warning" size="large" style={styles.menuButton} /> )} ); }; const styles = StyleSheet.create({ scrollContainer: { flex: 1, }, gameArea: { flex: 1, alignItems: 'center', justifyContent: 'space-between', paddingVertical: 20, minHeight: 600, }, loadingContainer: { flex: 1, justifyContent: 'center', alignItems: 'center', paddingVertical: 50, }, loadingText: { marginTop: 16, fontSize: 16, color: '#666', }, errorContainer: { flex: 1, justifyContent: 'center', alignItems: 'center', paddingHorizontal: 40, paddingVertical: 50, }, errorIcon: { fontSize: 48, marginBottom: 16, }, errorText: { fontSize: 16, color: '#D32F2F', textAlign: 'center', marginBottom: 24, lineHeight: 24, }, statsContainer: { flexDirection: 'row', justifyContent: 'space-around', width: '100%', paddingHorizontal: 16, marginBottom: 20, flexWrap: 'wrap', }, statItem: { alignItems: 'center', backgroundColor: '#F8F9FA', paddingVertical: 12, paddingHorizontal: 12, borderRadius: 12, minWidth: 70, marginHorizontal: 4, marginVertical: 4, shadowColor: '#000', shadowOffset: { width: 0, height: 2 }, shadowOpacity: 0.1, shadowRadius: 3, elevation: 2, }, statLabel: { fontSize: 11, color: '#666', marginBottom: 4, fontWeight: '500', }, statValue: { fontSize: 18, fontWeight: 'bold', color: '#333', }, bestScore: { color: '#4CAF50', }, boardContainer: { flex: 1, justifyContent: 'center', alignItems: 'center', paddingVertical: 20, }, controlsContainer: { flexDirection: 'row', justifyContent: 'space-around', width: '100%', paddingHorizontal: 16, marginTop: 20, }, controlButton: { flex: 1, marginHorizontal: 4, }, pauseOverlay: { position: 'absolute', top: 0, left: 0, right: 0, bottom: 0, backgroundColor: 'rgba(0, 0, 0, 0.8)', justifyContent: 'center', alignItems: 'center', }, pauseMenu: { backgroundColor: 'white', borderRadius: 20, padding: 28, width: '85%', maxWidth: 320, alignItems: 'center', shadowColor: '#000', shadowOffset: { width: 0, height: 10 }, shadowOpacity: 0.4, shadowRadius: 20, elevation: 20, }, pauseTitle: { fontSize: 22, fontWeight: 'bold', color: '#333', marginBottom: 20, }, pauseStats: { alignItems: 'center', marginBottom: 24, padding: 16, backgroundColor: '#F5F5F5', borderRadius: 12, width: '100%', }, pauseStatText: { fontSize: 14, color: '#666', marginBottom: 4, }, menuButton: { width: '100%', marginBottom: 12, }, }); export default SimplePuzzleScreen;