backend-lehrer (10 files): - game/database.py (785 → 5), correction_api.py (683 → 4) - classroom_engine/antizipation.py (676 → 5) - llm_gateway schools/edu_search already done in prior batch klausur-service (12 files): - orientation_crop_api.py (694 → 5), pdf_export.py (677 → 4) - zeugnis_crawler.py (676 → 5), grid_editor_api.py (671 → 5) - eh_templates.py (658 → 5), mail/api.py (651 → 5) - qdrant_service.py (638 → 5), training_api.py (625 → 4) website (6 pages): - middleware (696 → 8), mail (733 → 6), consent (628 → 8) - compliance/risks (622 → 5), export (502 → 5), brandbook (629 → 7) studio-v2 (3 components): - B2BMigrationWizard (848 → 3), CleanupPanel (765 → 2) - dashboard-experimental (739 → 2) admin-lehrer (4 files): - uebersetzungen (769 → 4), manager (670 → 2) - ChunkBrowserQA (675 → 6), dsfa/page (674 → 5) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
144 lines
5.4 KiB
Python
144 lines
5.4 KiB
Python
# ==============================================
|
|
# Breakpilot Drive - Game Database Models
|
|
# ==============================================
|
|
# Data models, enums, and achievement definitions.
|
|
|
|
import os
|
|
import logging
|
|
from datetime import datetime
|
|
from typing import Optional, Dict, Any
|
|
from dataclasses import dataclass
|
|
from enum import IntEnum
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
# Database URL from environment
|
|
GAME_DB_URL = os.getenv(
|
|
"DATABASE_URL",
|
|
"postgresql://breakpilot:breakpilot123@localhost:5432/breakpilot"
|
|
)
|
|
|
|
|
|
class LearningLevel(IntEnum):
|
|
"""Learning level enum mapping to grade ranges."""
|
|
BEGINNER = 1 # Klasse 2-3
|
|
ELEMENTARY = 2 # Klasse 3-4
|
|
INTERMEDIATE = 3 # Klasse 4-5
|
|
ADVANCED = 4 # Klasse 5-6
|
|
EXPERT = 5 # Klasse 6+
|
|
|
|
|
|
@dataclass
|
|
class StudentLearningState:
|
|
"""Student learning state data model."""
|
|
id: Optional[str] = None
|
|
student_id: str = ""
|
|
overall_level: int = 3
|
|
math_level: float = 3.0
|
|
german_level: float = 3.0
|
|
english_level: float = 3.0
|
|
total_play_time_minutes: int = 0
|
|
total_sessions: int = 0
|
|
questions_answered: int = 0
|
|
questions_correct: int = 0
|
|
created_at: Optional[datetime] = None
|
|
updated_at: Optional[datetime] = None
|
|
|
|
def to_dict(self) -> Dict[str, Any]:
|
|
"""Convert to dictionary."""
|
|
return {
|
|
"id": self.id,
|
|
"student_id": self.student_id,
|
|
"overall_level": self.overall_level,
|
|
"math_level": self.math_level,
|
|
"german_level": self.german_level,
|
|
"english_level": self.english_level,
|
|
"total_play_time_minutes": self.total_play_time_minutes,
|
|
"total_sessions": self.total_sessions,
|
|
"questions_answered": self.questions_answered,
|
|
"questions_correct": self.questions_correct,
|
|
"created_at": self.created_at.isoformat() if self.created_at else None,
|
|
"updated_at": self.updated_at.isoformat() if self.updated_at else None,
|
|
}
|
|
|
|
@property
|
|
def accuracy(self) -> float:
|
|
"""Calculate overall accuracy percentage."""
|
|
if self.questions_answered == 0:
|
|
return 0.0
|
|
return self.questions_correct / self.questions_answered
|
|
|
|
|
|
@dataclass
|
|
class GameSessionRecord:
|
|
"""Game session record for database storage."""
|
|
id: Optional[str] = None
|
|
student_id: str = ""
|
|
game_mode: str = "video"
|
|
duration_seconds: int = 0
|
|
distance_traveled: float = 0.0
|
|
score: int = 0
|
|
questions_answered: int = 0
|
|
questions_correct: int = 0
|
|
difficulty_level: int = 3
|
|
started_at: Optional[datetime] = None
|
|
ended_at: Optional[datetime] = None
|
|
metadata: Optional[Dict[str, Any]] = None
|
|
|
|
|
|
@dataclass
|
|
class GameQuizAnswer:
|
|
"""Individual quiz answer record."""
|
|
id: Optional[str] = None
|
|
session_id: Optional[str] = None
|
|
question_id: str = ""
|
|
subject: str = ""
|
|
difficulty: int = 3
|
|
is_correct: bool = False
|
|
answer_time_ms: int = 0
|
|
created_at: Optional[datetime] = None
|
|
|
|
|
|
@dataclass
|
|
class Achievement:
|
|
"""Achievement definition and unlock status."""
|
|
id: str
|
|
name: str
|
|
description: str
|
|
icon: str = "star"
|
|
category: str = "general" # general, streak, accuracy, time, score
|
|
threshold: int = 1
|
|
unlocked: bool = False
|
|
unlocked_at: Optional[datetime] = None
|
|
progress: int = 0
|
|
|
|
|
|
# Achievement definitions (static, not in DB)
|
|
ACHIEVEMENTS = [
|
|
# Erste Schritte
|
|
Achievement(id="first_game", name="Erste Fahrt", description="Spiele dein erstes Spiel", icon="rocket", category="general", threshold=1),
|
|
Achievement(id="five_games", name="Regelmaessiger Fahrer", description="Spiele 5 Spiele", icon="car", category="general", threshold=5),
|
|
Achievement(id="twenty_games", name="Erfahrener Pilot", description="Spiele 20 Spiele", icon="trophy", category="general", threshold=20),
|
|
|
|
# Serien
|
|
Achievement(id="streak_3", name="Guter Start", description="3 richtige Antworten hintereinander", icon="fire", category="streak", threshold=3),
|
|
Achievement(id="streak_5", name="Auf Feuer", description="5 richtige Antworten hintereinander", icon="fire", category="streak", threshold=5),
|
|
Achievement(id="streak_10", name="Unaufhaltsam", description="10 richtige Antworten hintereinander", icon="fire", category="streak", threshold=10),
|
|
|
|
# Genauigkeit
|
|
Achievement(id="perfect_game", name="Perfektes Spiel", description="100% richtig in einem Spiel (min. 5 Fragen)", icon="star", category="accuracy", threshold=100),
|
|
Achievement(id="accuracy_80", name="Scharfschuetze", description="80% Gesamtgenauigkeit (min. 50 Fragen)", icon="target", category="accuracy", threshold=80),
|
|
|
|
# Zeit
|
|
Achievement(id="play_30min", name="Ausdauer", description="30 Minuten Gesamtspielzeit", icon="clock", category="time", threshold=30),
|
|
Achievement(id="play_60min", name="Marathon", description="60 Minuten Gesamtspielzeit", icon="clock", category="time", threshold=60),
|
|
|
|
# Score
|
|
Achievement(id="score_5000", name="Punktejaeger", description="5.000 Punkte in einem Spiel", icon="gem", category="score", threshold=5000),
|
|
Achievement(id="score_10000", name="Highscore Hero", description="10.000 Punkte in einem Spiel", icon="crown", category="score", threshold=10000),
|
|
|
|
# Level
|
|
Achievement(id="level_up", name="Aufsteiger", description="Erreiche Level 2", icon="arrow-up", category="level", threshold=2),
|
|
Achievement(id="master", name="Meister", description="Erreiche Level 5", icon="medal", category="level", threshold=5),
|
|
]
|