Spaces:
Running
Running
| from __future__ import annotations | |
| from dataclasses import dataclass, field | |
| from typing import List | |
| import time | |
| VALID_DIFFICULTIES = {"easy", "medium", "hard"} | |
| VALID_TYPES = {"mcq", "tf", "fill"} | |
| class Question: | |
| text: str | |
| topic: str # subject area — "Determinants" not question text | |
| options: List[str] | |
| correct_idx: int | |
| explanation: str | |
| difficulty: str | |
| q_type: str | |
| is_boss: bool = False | |
| source_excerpt: str = "" # snippet from original material for tutor context | |
| language: str = "en" | |
| def __post_init__(self): | |
| if self.difficulty not in VALID_DIFFICULTIES: | |
| raise ValueError(f"difficulty must be one of {VALID_DIFFICULTIES}, got '{self.difficulty}'") | |
| if self.q_type not in VALID_TYPES: | |
| raise ValueError(f"q_type must be one of {VALID_TYPES}, got '{self.q_type}'") | |
| if not (0 <= self.correct_idx < len(self.options)): | |
| raise ValueError(f"correct_idx {self.correct_idx} out of range for {len(self.options)} options") | |
| def correct_answer(self) -> str: | |
| return self.options[self.correct_idx] | |
| class QuizSession: | |
| quest_name: str | |
| questions: List[Question] = field(default_factory=list) | |
| current_idx: int = 0 | |
| score: int = 0 | |
| consecutive_correct: int = 0 | |
| xp_earned: int = 0 | |
| start_time: float = field(default_factory=time.time) | |
| wrong_topics: List[str] = field(default_factory=list) # topic strings, not question text | |
| def is_finished(self) -> bool: | |
| return self.current_idx >= len(self.questions) | |
| def current_question(self) -> Question | None: | |
| if self.is_finished: | |
| return None | |
| return self.questions[self.current_idx] | |
| class Quest: | |
| name: str | |
| topics: List[str] | |
| boss_topic: str | |
| difficulty: str | |
| questions: List[Question] = field(default_factory=list) | |
| unlocked: bool = True | |
| completed: bool = False # True only after user finishes the quest | |
| def has_questions(self) -> bool: | |
| return len(self.questions) > 0 | |
| def total_questions(self) -> int: | |
| return len(self.questions) | |