import 'dart:async'; import 'dart:math'; import 'package:flutter/material.dart'; import '../models/finddiff_models.dart'; import '../utils/hangul_utils.dart'; class FindDiffController with ChangeNotifier { late FindDiffDifficulty difficulty; late String userId; late String? userName; List _items = []; List get items => _items; int _currentRound = 0; int get currentRound => _currentRound; int _score = 0; int get score => _score; int _incorrectCount = 0; int get incorrectCount => _incorrectCount; bool _isGameCompleted = false; bool get isGameCompleted => _isGameCompleted; Timer? _timer; int _remainingTime = 0; int get remainingTime => _remainingTime; int _secondsElapsed = 0; int get secondsElapsed => _secondsElapsed; bool _isGameStarted = false; bool get isGameStarted => _isGameStarted; bool _showFeedback = false; bool get showFeedback => _showFeedback; bool _isLastAnswerCorrect = false; bool get isLastAnswerCorrect => _isLastAnswerCorrect; FindDiffType _currentRoundType = FindDiffType.color; FindDiffType get currentRoundType => _currentRoundType; final Random _random = Random(); void setUserInfo(String userId, String? userName) { this.userId = userId; this.userName = userName; } void startNewGame(FindDiffDifficulty level) { difficulty = level; _score = 0; _incorrectCount = 0; _currentRound = 1; _isGameCompleted = false; _secondsElapsed = 0; _isGameStarted = false; _showFeedback = false; _generateLevel(); notifyListeners(); } void restartGame() { startNewGame(difficulty); } void startGameTimer() { if (_isGameStarted) return; _isGameStarted = true; _startTimer(); notifyListeners(); } void _generateLevel() { _items.clear(); final int totalItems = difficulty.totalItems; final int targetIndex = _random.nextInt(totalItems); // 1. 문제 유형 결정 if (difficulty.diffType == FindDiffType.mix) { const List types = [ FindDiffType.color, FindDiffType.icon, FindDiffType.rotate, FindDiffType.category, FindDiffType.word ]; _currentRoundType = types[_random.nextInt(types.length)]; } else { _currentRoundType = difficulty.diffType; } // 2. 기본 속성 준비 IconData? baseIcon; String? baseText; String? targetText; Color baseColor = Colors.blue; double baseAngle = 0.0; // [🔥 핵심] 유형별 아이콘/데이터 소스 분리 if (_currentRoundType == FindDiffType.category) { // 카테고리 (나중에 루프에서 결정) } else if (_currentRoundType == FindDiffType.word) { // 단어 & 오타 final String originalWord = FindDiffDifficulties.baseWords[ _random.nextInt(FindDiffDifficulties.baseWords.length) ]; final String modifiedWord = HangulUtils.generateSimilarWord(originalWord); if (_random.nextBool()) { baseText = originalWord; targetText = modifiedWord; } else { baseText = modifiedWord; targetText = originalWord; } baseColor = Colors.black87; } else if (_currentRoundType == FindDiffType.icon) { // 모양 찾기 final pair = FindDiffDifficulties.iconPairs[_random.nextInt(FindDiffDifficulties.iconPairs.length)]; baseIcon = pair[0]; baseColor = Colors.black87; } else if (_currentRoundType == FindDiffType.rotate) { // [🔥 수정] 회전 모드: rotateIcons에서 선택 (원, 네모 등 제외) baseIcon = FindDiffDifficulties.rotateIcons[_random.nextInt(FindDiffDifficulties.rotateIcons.length)]; baseColor = Color.fromARGB(255, _random.nextInt(200), _random.nextInt(200), _random.nextInt(200)); } else { // 색상 모드: colorIcons에서 선택 baseIcon = FindDiffDifficulties.colorIcons[_random.nextInt(FindDiffDifficulties.colorIcons.length)]; baseColor = Color.fromARGB(255, _random.nextInt(200), _random.nextInt(200), _random.nextInt(200)); } // 카테고리 모드용 리스트 준비 List baseCatList = []; List targetCatList = []; if (_currentRoundType == FindDiffType.category) { final keys = FindDiffDifficulties.emojiCategories.keys.toList(); String baseKey = keys[_random.nextInt(keys.length)]; String targetKey; do { targetKey = keys[_random.nextInt(keys.length)]; } while (baseKey == targetKey); baseCatList = FindDiffDifficulties.emojiCategories[baseKey]!; targetCatList = FindDiffDifficulties.emojiCategories[targetKey]!; } // 3. 아이템 배치 for (int i = 0; i < totalItems; i++) { bool isTarget = (i == targetIndex); IconData? icon = baseIcon; String? textContent = baseText; Color color = baseColor; double angle = baseAngle; switch (_currentRoundType) { case FindDiffType.color: if (isTarget) { // 난이도가 높거나 믹스 모드일 경우 색상 차이를 미세하게 int offset = (difficulty.levelIndex >= 5) ? 30 : 60; color = Color.fromARGB(255, (baseColor.red + offset) % 255, (baseColor.green + offset) % 255, (baseColor.blue + offset) % 255); } break; case FindDiffType.icon: if (isTarget) { final pair = FindDiffDifficulties.iconPairs.firstWhere((p) => p.contains(baseIcon)); icon = (baseIcon == pair[0]) ? pair[1] : pair[0]; } break; case FindDiffType.rotate: if (isTarget) angle = 0.5; // 약 30도 회전 break; case FindDiffType.category: if (isTarget) { textContent = targetCatList[_random.nextInt(targetCatList.length)]; } else { textContent = baseCatList[_random.nextInt(baseCatList.length)]; } color = Colors.black; break; case FindDiffType.word: if (isTarget) { textContent = targetText; } else { textContent = baseText; } break; default: break; } _items.add(FindDiffItem( id: i, icon: icon, textContent: textContent, color: color, angle: angle, isTarget: isTarget, )); } _remainingTime = difficulty.timeLimitSeconds; } // ... (나머지 메서드 동일) ... void _startTimer() { _timer?.cancel(); _timer = Timer.periodic(const Duration(seconds: 1), (timer) { _secondsElapsed++; _remainingTime--; if (_remainingTime <= 0) { _handleAnswer(false); } notifyListeners(); }); } void onItemTapped(FindDiffItem item) { if (!_isGameStarted || _isGameCompleted || _showFeedback) return; _handleAnswer(item.isTarget); } void _handleAnswer(bool isCorrect) { _timer?.cancel(); _showFeedback = true; _isLastAnswerCorrect = isCorrect; if (isCorrect) { _score++; } else { _incorrectCount++; } notifyListeners(); Future.delayed(const Duration(milliseconds: 500), () { if (_score >= 10) { _isGameCompleted = true; } else { _showFeedback = false; _generateLevel(); _startTimer(); } notifyListeners(); }); } @override void dispose() { _timer?.cancel(); super.dispose(); } }