Skip to content

Scoring-Logik implementieren

Überblick

Die UebungenAPIEvaluationData Klasse ist eine zentrale Datenstruktur im Hermeneus-Übungssystem, die alle relevanten Daten für die Auswertung einer absolvierten Übung sammelt und verwaltet. Sie implementiert das Composite Pattern und fungiert als Container für drei spezialisierte Datenobjekte.

Zweck und Funktionalität

Diese Klasse konsolidiert alle Ergebnisse einer Übungsauswertung in einem einheitlichen Datencontainer und bietet eine konsistente Schnittstelle für:

  • Score-Verwaltung: Berechnung und Speicherung von Punktwerten, Korrektheitsverhältnissen und Gravitas
  • Feedback-Generierung: Automatische Erstellung von nutzerfreundlichem Feedback basierend auf der Leistung
  • Review-Daten: Detaillierte Aufschlüsselung der Nutzerantworten mit Korrektheitsbewertung
  • API-Serialisierung: Einheitliche JSON-Ausgabe für Frontend-Komponenten

Architektur und Design

Komposition

Die Klasse implementiert eine Kompositions-Architektur mit drei Haupt-Datenobjekten:

php
UebungenAPIEvaluationData
├── UebungenAPIScoreData      // Score-Berechnungen und Punktwerte
├── UebungenAPIReviewData     // Überprüfte Nutzerantworten (Was war richtig oder falsch?) und Statistiken  
└── UebungenAPIFeedbackData   // Generiertes Nutzerfeedback

Abhängigkeitsmanagement

Die Klasse verwaltet intelligente Abhängigkeiten zwischen ihren Komponenten:

  • Feedback ← Score: Feedback-Texte werden automatisch auf Basis der Score-Daten generiert
  • Score ← Review: Score-Berechnungen basieren auf Review-Statistiken
  • Automatische Synchronisation: Änderungen an Score-Daten lösen Feedback-Neugenerierung aus

Wo können Entwickler einhaken?

Als Entwickler einer neuen Übungsklasse können Sie an zwei zentralen Stellen in die Score-Berechnung eingreifen:

1. Die reviewInput() Methode (PFLICHT)

php
/**
 * Diese Methode MUSS von jeder Übungsklasse implementiert werden
 * @param array $input_data Die Nutzerantworten vom Frontend
 * @return Collection Collection mit bewerteten Antworten
 */
public function reviewInput(array $input_data): Collection
{
    // Ihre Implementierung hier
}

2. Die evaluateUebung() Methode (STANDARD-IMPLEMENTIERUNG)

php
/**
 * Diese Methode kann optional überschrieben werden für spezielle Auswertungslogik
 * @param Request $request Der Request mit input_data
 * @return mixed Meist UebungenAPIEvaluationData
 */
public function evaluateUebung(Request $request = null): mixed
{
    // Standard oder eigene Implementierung
}

Wie implementiere ich Score-Berechnung in meiner Übungsklasse?

Schritt 1: Evaluable Trait einbinden

php
<?php

namespace Modules\Uebungen\MeineUebung\app\Models;

use App\Models\UebungBase;
use App\ServiceClasses\Uebungen\UebungenAPI\Traits\PropertyTraits\Evaluable;

class MeineUebung extends UebungBase
{
    use Evaluable; // Dieser Trait ist PFLICHT für Score-Berechnung
    
    // Ihre Modellogik...
}

Schritt 2: reviewInput() Methode implementieren

php
/**
 * Überprüft Nutzerantworten gegen erwartete Lösungen
 * @param array $input_data Nutzerantworten vom Frontend 
 * @return Collection Bewertete Antworten
 */
public function reviewInput(array $input_data): Collection
{
    $InputDataCollection = collect($input_data);
    $ContentDataCollection = collect($this->content_data);
    
    return $InputDataCollection->map(function ($inputElement) use ($ContentDataCollection) {
        // Finde das entsprechende Content-Element
        $contentElement = $ContentDataCollection->firstWhere('value_given', $inputElement['value_given']);
        
        // Bewerte die Antwort
        $isCorrect = $this->evaluateAnswer($inputElement, $contentElement);
        
        return [
            'value_given' => $contentElement['value_given'],
            'value_expected' => $contentElement['value_expected'], 
            'value_input' => $inputElement['value_input'],
            'correct' => $isCorrect, // WICHTIG: 1=korrekt, 0=falsch, null=unbeantwortet
            // Weitere Felder nach Bedarf...
        ];
    });
}

/**
 * Hilfsmethode für die eigentliche Antwortbewertung
 */
private function evaluateAnswer($inputElement, $contentElement): ?int
{
    $userAnswer = $inputElement['value_input'] ?? null;
    $expectedAnswer = $contentElement['value_expected'];
    
    // Unbeantwortet?
    if ($userAnswer === null || $userAnswer === '') {
        return null;
    }
    
    // Hier Ihre spezifische Bewertungslogik implementieren:
    
    // Beispiel 1: Einfacher String-Vergleich
    return ($userAnswer === $expectedAnswer) ? 1 : 0;
    
    // Beispiel 2: Normalisierter Vergleich
    // return (strtolower(trim($userAnswer)) === strtolower(trim($expectedAnswer))) ? 1 : 0;
    
    // Beispiel 3: Array-Vergleich (z.B. für Drag&Drop)
    // return (is_array($userAnswer) && $userAnswer === $expectedAnswer) ? 1 : 0;
    
    // Beispiel 4: Teilweise korrekte Antworten
    // return $this->calculatePartialCorrectness($userAnswer, $expectedAnswer);
}

Schritt 3: Standard evaluateUebung() verwenden ODER überschreiben

Option A: Standard-Implementierung nutzen (empfohlen):

php
public function evaluateUebung(Request $request = null): mixed
{
    // Diese Standard-Implementation führt automatisch durch:
    // 1. reviewInput() aufrufen  
    // 2. Score-Berechnungen
    // 3. Feedback-Generierung
    // 4. Gravitas vergeben
    // 5. AbsolvedRecord speichern
    
    $EvaluationData = $this->getEvaluationData($request->input_data);
    $this->rewardUser($EvaluationData);
    $this->setAbsolved($EvaluationData);
    return $EvaluationData;
}

Option B: Eigene Auswertungslogik (für spezielle Fälle):

php
public function evaluateUebung(Request $request = null): mixed
{
    // Eigene Pre-Processing-Logik hier...
    
    // Standard-Evaluation durchführen
    $EvaluationData = $this->getEvaluationData($request->input_data, $secondsElapsed);
    
    // Eigene Post-Processing-Logik hier...
    // Z.B. Score-Adjustierung basierend auf speziellen Kriterien
    if ($this->hasSpecialBonus($request)) {
        $adjustedScoreData = $this->applyBonus($EvaluationData->scoreData);
        $EvaluationData->setScoreData($adjustedScoreData);
    }
    
    // Standard-Aktionen durchführen
    $this->rewardUser($EvaluationData);
    $this->setAbsolved($EvaluationData);
    
    return $EvaluationData;
}

Erweiterte Beispiele: Custom Score-Faktoren

Beispiel: Wiederholungsanzahl in Score-Berechnung einbeziehen

Angenommen, Sie möchten einen Malus-Faktor einbauen, wenn ein Nutzer eine Übung mehrfach wiederholt. Bei jeder Wiederholung soll die erreichbare Score reduziert werden.

php
public function evaluateUebung(Request $request = null): mixed
{
    // Standard-Evaluation durchführen
    $EvaluationData = $this->getEvaluationData($request->input_data);
    
    // Anzahl bisheriger Absolvierungen für diesen User und diese Übung zählen
    $repetitionCount = $this->getRepetitionCount();
    
    // Malus-Faktor berechnen (z.B. -10% pro Wiederholung, max. -50%)
    $repetitionPenalty = min($repetitionCount * 0.1, 0.5);
    
    // Aktuelle Score-Daten holen und anpassen
    $scoreData = $EvaluationData->scoreData;
    
    // Option 1: Correct Ratio reduzieren
    $adjustedCorrectRatio = $scoreData->score_correct_ratio * (1 - $repetitionPenalty);
    $scoreData->setScoreCorrectRatio($adjustedCorrectRatio);
    
    // Option 2: Alternativ - Total Ratio direkt anpassen
    // $adjustedTotalRatio = $scoreData->score_total_ratio * (1 - $repetitionPenalty);
    // $scoreData->setScoreTotalRatio($adjustedTotalRatio);
    // $scoreData->setScoreTotalPoints((int) round($adjustedTotalRatio * 100));
    
    // Gravitas entsprechend neu berechnen
    $adjustedGravitas = $scoreData->calculateScoreGravitas($scoreData->score_total_ratio, $this);
    $scoreData->setScoreGravitas($adjustedGravitas);
    
    // Aktualisierte Score-Daten setzen (triggert automatische Feedback-Neugenerierung)
    $EvaluationData->setScoreData($scoreData);
    
    // Optional: Custom Feedback für Wiederholungen hinzufügen
    if ($repetitionCount > 0) {
        $customFeedback = "Dies ist dein " . ($repetitionCount + 1) . ". Versuch. " .
                         "Score wurde um " . ($repetitionPenalty * 100) . "% reduziert.";
        $EvaluationData->feedbackData->setGeneralFeedback($customFeedback);
    }
    
    // Standard-Aktionen durchführen
    $this->rewardUser($EvaluationData);
    $this->setAbsolved($EvaluationData);
    
    return $EvaluationData;
}

/**
 * Hilfsmethode: Zählt bisherige Absolvierungen dieser Übung für den aktuellen User
 */
private function getRepetitionCount(): int
{
    if (!auth()->user()) {
        return 0;
    }
    
    return DB::table('uebungen_absolved')
        ->where('user_id', auth()->user()->id)
        ->where('uebung_id', $this->base_uebung->id)
        ->count();
}

Weitere Custom Score-Faktoren Beispiele

Beispiel: Schwierigkeitsgrad-basierte Boni:

php
// Bonus für schwierige Übungen
if ($this->difficulty_level >= 4) {
    $difficultyBonus = 0.1; // +10% für schwere Übungen
    $adjustedTotalRatio = min($scoreData->score_total_ratio * (1 + $difficultyBonus), 1.0);
    $scoreData->setScoreTotalRatio($adjustedTotalRatio);
}

Beispiel: Zeitbasierte Anpassungen:

php
// Extra-Bonus für sehr schnelle Bearbeitung
if ($scoreData->score_time_ratio > 1.5) { // 50% schneller als Durchschnitt
    $speedBonus = 0.05; // +5% Speed-Bonus
    $adjustedCorrectRatio = min($scoreData->score_correct_ratio * (1 + $speedBonus), 1.0);
    $scoreData->setScoreCorrectRatio($adjustedCorrectRatio);
}

Beispiel: Lernfortschritt-Integration:

php
// Malus für Nutzer mit hohem Vokabelstand (sollen mehr gefordert werden)
$userVocabLevel = $this->getUserVocabularyLevel();
if ($userVocabLevel > 80) { // Fortgeschrittene Lerner
    $expertPenalty = 0.05; // -5% für Fortgeschrittene
    $adjustedCorrectRatio = $scoreData->score_correct_ratio * (1 - $expertPenalty);
    $scoreData->setScoreCorrectRatio($adjustedCorrectRatio);
}

Wichtige Hinweise für Entwickler

  1. Rückgabeformat von reviewInput():

    • Muss eine Laravel Collection sein
    • Jedes Element MUSS ein 'correct' Feld enthalten
    • Werte für 'correct': 1 (korrekt), 0 (falsch), null (unbeantwortet)
  2. Automatische Score-Berechnung:

    • Der Evaluable Trait berechnet automatisch: score_correct_ratio, score_time_ratio, score_total_ratio, score_gravitas
    • Basis: Ihre reviewInput() Ergebnisse und Konfigurationswerte (cfg_max_gravitas, cfg_avg_time_seconds)
  3. Feedback-Generierung:

    • Wird automatisch basierend auf Score-Daten erstellt
    • Kann in UebungenAPIFeedbackData manuell angepasst werden
  4. Zeit-Messung:

    • Frontend kann seconds_elapsed mitschicken für Zeit-basierte Bewertung
    • Wird automatisch in Score-Berechnung einbezogen wenn cfg_avg_time_seconds gesetzt ist

Was passiert automatisch im Hintergrund?

Wenn Sie nur reviewInput() implementieren, übernimmt das System automatisch:

  1. Review-Statistiken: Zählung korrekter/falscher/unbeantworteter Fragen
  2. Score-Berechnungen: Korrektheitsverhältnis, Zeitbonus, Gesamtscore, Gravitas
  3. Feedback-Generierung: Nutzerfreundliche Rückmeldungen basierend auf Leistung
  4. Datenkonsolidierung: Alles wird in UebungenAPIEvaluationData verpackt
  5. JSON-Serialisierung: Frontend-kompatible Ausgabe

Klassen-Referenz

Konstruktor

php
public function __construct(
    UebungenAPIScoreData $scoreData,
    UebungenAPIReviewData $reviewData, 
    UebungenAPIFeedbackData $feedbackData,
    ?array $config = ['hasGravitas' => true, 'hasTime' => true]
)

Parameter:

  • $scoreData: Objekt mit berechneten Score-Werten (Korrektheit, Zeit, Gesamtscore, Gravitas)
  • $reviewData: Objekt mit überprüften Nutzerantworten und aggregierten Statistiken
  • $feedbackData: Objekt mit generierten Feedback-Texten
  • $config: Konfiguration für Feedback-Features (optional)

Konfigurationsoptionen:

  • hasGravitas (bool): Aktiviert/deaktiviert Gravitas-bezogenes Feedback
  • hasTime (bool): Aktiviert/deaktiviert Zeit-bezogenes Feedback

Öffentliche Methoden

setScoreData()

php
public function setScoreData(UebungenAPIScoreData $scoreData): static

Aktualisiert die Score-Daten und triggert automatisch die Neugenerierung aller abhängigen Feedback-Texte.

Verwendung:

php
$evaluationData->setScoreData($newScoreData);
// Feedback wird automatisch neu generiert

jsonSerialize() / toArray()

php
public function jsonSerialize(): array
public function toArray(): array

Serialisiert alle Evaluationsdaten in ein strukturiertes Array für JSON-Ausgabe.

Ausgabestruktur:

php
[
    'feedbackData' => [
        'generalFeedback' => '...',
        'correctnessFeedback' => '...',
        'timeFeedback' => '...',
        'pointsFeedback' => '...',
        'gravitasFeedback' => '...'
    ],
    'scoreData' => [
        'score_correct_ratio' => 0.85,
        'score_time_ratio' => 1.1,
        'score_total_ratio' => 0.94,
        'score_total_points' => 94,
        'score_gravitas' => 8
    ],
    'reviewData' => [
        'ReviewedInputData' => Collection,
        'ReviewStats' => [...]
    ],
    'config' => [
        'hasGravitas' => true,
        'hasTime' => true
    ]
]

Abhängige Datenobjekte im Detail

UebungenAPIScoreData

Verwaltet alle score-relevanten Berechnungen:

Eigenschaften:

  • score_correct_ratio: Verhältnis korrekter Antworten (0.0 - 1.0)
  • score_time_ratio: Zeit-Faktor basierend auf Bearbeitungsgeschwindigkeit
  • score_total_ratio: Gesamtbewertung als Verhältnis
  • score_total_points: Gesamtpunkte (total_ratio × 100)
  • score_gravitas: Erreichte Gravitas-Punkte

Wichtige Methoden:

  • calculateScores(): Berechnet alle Score-Werte
  • calculateCorrectRatio(): Ermittelt Korrektheitsverhältnis
  • calculateScoreGravitas(): Berechnet Gravitas basierend auf Gesamtscore

UebungenAPIReviewData

Enthält detaillierte Analyse der Nutzerantworten:

Eigenschaften:

  • ReviewedInputData: Collection mit bewerteten Einzelantworten
  • ReviewStats: Aggregierte Statistiken

Review-Statistiken:

php
'ReviewStats' => [
    'total_answers' => 10,
    'total_answers_correct' => 7,
    'total_answers_semi_correct' => 1,
    'total_answers_incorrect' => 2,
    'total_answers_unanswered' => 0
]

UebungenAPIFeedbackData

Generiert nutzerfreundliche Feedback-Texte:

Feedback-Kategorien:

  • generalFeedback: Allgemeine Bewertung der Leistung
  • correctnessFeedback: Feedback zur inhaltlichen Korrektheit
  • timeFeedback: Bewertung der Bearbeitungszeit (falls aktiviert)
  • pointsFeedback: Feedback zu erreichten Punkten
  • gravitasFeedback: Feedback zu Gravitas-Punkten (falls aktiviert)

Automatische Generierung: Das Feedback wird basierend auf Score-Daten automatisch generiert und kann bei Bedarf manuell überschrieben werden.

Verwendungsszenarien

Standard-Auswertung

php
// Erstellung der Evaluationsdaten nach Übungsabsolvierung
$scoreData = new UebungenAPIScoreData($reviewData);
$scoreData->calculateScores($uebungModel, $secondsElapsed);

$feedbackData = new UebungenAPIFeedbackData($scoreData, true, true);
$evaluationData = new UebungenAPIEvaluationData(
    $scoreData, 
    $reviewData, 
    $feedbackData
);

// Direkte JSON-Ausgabe für API-Response
return response()->json($evaluationData);

Score-Aktualisierung

php
// Nachträgliche Score-Anpassung
$newScoreData = $scoreData->setScoreCorrectRatio(0.9);
$evaluationData->setScoreData($newScoreData);
// Feedback wird automatisch neu generiert

Konfigurierte Feedback-Optionen

php
// Evaluation ohne Zeit-Feedback für zeitunabhängige Übungen
$config = ['hasGravitas' => true, 'hasTime' => false];
$evaluationData = new UebungenAPIEvaluationData(
    $scoreData, 
    $reviewData, 
    $feedbackData, 
    $config
);

Integration in die UebungenAPI

Die Klasse ist integraler Bestandteil des Evaluable Trait-Systems:

  1. Auswertungsprozess: Das spezifische Übungsmodel implementiert evaluateUebung()
  2. Datensammlung: Score-, Review- und Feedback-Daten werden erstellt
  3. Konsolidierung: UebungenAPIEvaluationData sammelt alle Teilergebnisse
  4. API-Response: Einheitliche JSON-Struktur für Frontend-Komponenten