Files
mindflux/src/main/java/com/example/mindflux/service/ProgressService.java
T
AliceDarkest d718a09561
mindflux-ci / build (push) Successful in 23s
Make progress data-driven and build Knowledge Core
2026-07-13 22:31:57 +02:00

128 lines
5.1 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package com.example.mindflux.service;
import com.example.mindflux.dto.GameProgress;
import com.example.mindflux.dto.GameStats;
import com.example.mindflux.dto.ProgressData;
import com.example.mindflux.dto.WeeklyActivity;
import org.springframework.stereotype.Service;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Comparator;
import java.time.temporal.TemporalAdjusters;
import java.time.DayOfWeek;
@Service
public class ProgressService {
/** Spiel-Kennung -> Anzeigename, in Dashboard-Reihenfolge. */
private static final Map<String, String> GAMES = new LinkedHashMap<>();
static {
GAMES.put("mindmatch", "MindMatch");
GAMES.put("techtacular", "TechTacular");
GAMES.put("devlab", "DevLab");
GAMES.put("syntax-saga", "SyntaxSaga");
GAMES.put("codeescape", "SystemEscape");
GAMES.put("serviceclash", "ServiceClash");
GAMES.put("bughunter", "BugHunter");
GAMES.put("networker", "NetWorker");
}
private final GameScoreService gameScoreService;
public ProgressService(GameScoreService gameScoreService) {
this.gameScoreService = gameScoreService;
}
/** XP pro Level: Level n ist erreicht ab (n-1) * 1000 Gesamt-XP. */
static final int XP_PER_LEVEL = 1000;
/** Echter Gesamtfortschritt aus game_scores: XP = Summe aller Scores, Level linear. */
public ProgressData getOverallProgress(String username) {
long totalXp = gameScoreService.totalScore(username);
int level = (int) (totalXp / XP_PER_LEVEL) + 1;
long nextLevelAt = (long) level * XP_PER_LEVEL;
int withinLevel = (int) (totalXp - (long) (level - 1) * XP_PER_LEVEL);
ProgressData data = new ProgressData();
// Näherung: moves = je nach Spiel gelöste Aufgaben bzw. richtige Antworten
// (bei MindMatch sind es Zug-Versuche – bewusst in Kauf genommen).
data.setCorrectAnswers((int) Math.min(gameScoreService.totalMoves(username), Integer.MAX_VALUE));
data.setCurrentXp((int) Math.min(totalXp, Integer.MAX_VALUE));
data.setXpForNextLevel((int) Math.min(nextLevelAt, Integer.MAX_VALUE));
data.setUserLevel(level);
data.setProgressPercent(Math.round(withinLevel * 100f / XP_PER_LEVEL));
data.setStreakDays(computeStreak(gameScoreService.playDaysDesc(username), LocalDate.now()));
return data;
}
/**
* Tages-Streak: Anzahl zusammenhängender Spieltage bis heute. Ein Tag Karenz –
* wer heute noch nicht gespielt hat, behält die Serie von gestern.
*/
static int computeStreak(List<LocalDate> playDaysDesc, LocalDate today) {
if (playDaysDesc.isEmpty()) {
return 0;
}
LocalDate anchor = playDaysDesc.get(0);
if (anchor.isBefore(today.minusDays(1))) {
return 0;
}
int streak = 0;
LocalDate expected = anchor;
for (LocalDate day : playDaysDesc) {
if (day.equals(expected)) {
streak++;
expected = expected.minusDays(1);
} else {
break;
}
}
return streak;
}
/** Echter Spiel-Fortschritt pro Spiel aus der Datenbank (game_scores). */
public List<GameProgress> getGameProgress(String username) {
List<GameProgress> result = new ArrayList<>();
for (Map.Entry<String, String> entry : GAMES.entrySet()) {
GameStats stats = gameScoreService.getStats(username, entry.getKey());
result.add(toGameProgress(entry.getValue(), stats));
}
return result;
}
/** Aktuelle Wochenwerte, jeweils Montag bis Sonntag. */
public WeeklyActivity getCurrentWeekActivity(String username) {
LocalDate monday = LocalDate.now().with(TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY));
return gameScoreService.weeklyActivity(username, monday);
}
/** Die tatsächlich gespielten Spiele, nach ihrem Highscore sortiert. */
public List<GameProgress> getTopGames(String username, int limit) {
List<GameProgress> games = getGameProgress(username).stream()
.filter(game -> game.getPlays() > 0)
.sorted(Comparator.comparingInt(GameProgress::getHighscore).reversed()
.thenComparing(Comparator.comparingInt(GameProgress::getPlays).reversed()))
.limit(limit)
.toList();
int topScore = games.stream().mapToInt(GameProgress::getHighscore).max().orElse(1);
games.forEach(game -> game.setProgressPercent(Math.round(game.getHighscore() * 100f / topScore)));
return games;
}
private GameProgress toGameProgress(String displayName, GameStats stats) {
GameProgress game = new GameProgress();
game.setName(displayName);
game.setHighscore(stats.getHighscore());
game.setPlays((int) stats.getPlays());
game.setLastPlayed(stats.getLastPlayed());
// Fortschritt auf der Score-Skala (max ~1500 Punkte -> 100 %).
game.setProgressPercent(Math.min(100, Math.round(stats.getHighscore() / 15.0f)));
return game;
}
}