83 lines
2.9 KiB
Dart
83 lines
2.9 KiB
Dart
import 'dart:math';
|
|
import '../models/cognitive_type.dart';
|
|
import '../models/assessment_data.dart';
|
|
|
|
class BrainTrainingService {
|
|
final Random _random = Random();
|
|
|
|
/// 사용자 취약점을 분석하여 맞춤형 게임 3개를 추천합니다.
|
|
List<BrainGameType> recommendGames(Map<CognitiveArea, int>? scores) {
|
|
if (scores == null || scores.isEmpty) {
|
|
// 기록이 없으면 골고루 추천 (기억, 계산, 주의)
|
|
return [
|
|
BrainGameType.sequence,
|
|
BrainGameType.mathQuiz,
|
|
BrainGameType.schulte,
|
|
];
|
|
}
|
|
|
|
// 1. 점수 기반 취약점 분석 (점수가 높을수록 위험/취약)
|
|
Map<CognitiveArea, double> riskRatios = {};
|
|
Map<CognitiveArea, int> totalCountByArea = {};
|
|
|
|
for (var q in rawAssessmentQuestions) {
|
|
totalCountByArea[q.area] = (totalCountByArea[q.area] ?? 0) + 1;
|
|
}
|
|
|
|
scores.forEach((area, score) {
|
|
int total = totalCountByArea[area] ?? 1;
|
|
riskRatios[area] = score / total;
|
|
});
|
|
|
|
var sortedRisks = riskRatios.entries.toList()
|
|
..sort((a, b) => b.value.compareTo(a.value));
|
|
|
|
CognitiveArea primaryWeakness = sortedRisks[0].key;
|
|
CognitiveArea secondaryWeakness = sortedRisks.length > 1 ? sortedRisks[1].key : primaryWeakness;
|
|
|
|
List<BrainGameType> recommendation = [];
|
|
|
|
// 2. 추천 리스트 생성
|
|
// (1) 가장 취약한 영역의 게임
|
|
recommendation.add(_getGameForArea(primaryWeakness));
|
|
|
|
// (2) 두 번째 취약한 영역의 게임 (중복 방지)
|
|
BrainGameType secondGame = _getGameForArea(secondaryWeakness);
|
|
if (!recommendation.contains(secondGame)) {
|
|
recommendation.add(secondGame);
|
|
} else {
|
|
recommendation.add(_getRandomGameExcluding(recommendation));
|
|
}
|
|
|
|
// (3) 랜덤 게임 (밸런스)
|
|
recommendation.add(_getRandomGameExcluding(recommendation));
|
|
|
|
return recommendation;
|
|
}
|
|
|
|
/// 영역별 게임 랜덤 선택 (2개 중 1개)
|
|
BrainGameType _getGameForArea(CognitiveArea area) {
|
|
switch (area) {
|
|
case CognitiveArea.memory:
|
|
return _random.nextBool() ? BrainGameType.sequence : BrainGameType.cardFlip;
|
|
|
|
case CognitiveArea.calculation:
|
|
return _random.nextBool() ? BrainGameType.mathQuiz : BrainGameType.sudoku;
|
|
|
|
case CognitiveArea.attention:
|
|
return _random.nextBool() ? BrainGameType.colorMatch : BrainGameType.schulte; // 슐테(숫자찾기)
|
|
|
|
case CognitiveArea.perception:
|
|
return _random.nextBool() ? BrainGameType.findDiff : BrainGameType.tracing; // 따라그리기
|
|
|
|
case CognitiveArea.language:
|
|
return _random.nextBool() ? BrainGameType.readAloud : BrainGameType.dictation; // 읽기/쓰기
|
|
}
|
|
}
|
|
|
|
BrainGameType _getRandomGameExcluding(List<BrainGameType> exclude) {
|
|
var candidates = BrainGameType.values.where((g) => !exclude.contains(g)).toList();
|
|
if (candidates.isEmpty) return BrainGameType.sudoku;
|
|
return candidates[_random.nextInt(candidates.length)];
|
|
}
|
|
} |