Spaces:
Sleeping
Sleeping
| """Math problem pool: load, sample (deterministic via seed), and verify. | |
| Per PROJECT.md §14. The placeholder ``data/problems_pool.json`` ships | |
| ~10 verifiable arithmetic problems; the real ~500-problem pool is | |
| generated on a parallel track and replaces the JSON without code | |
| changes. | |
| """ | |
| import json | |
| import random | |
| from dataclasses import dataclass, field | |
| from pathlib import Path | |
| from typing import Any, Dict, List, Optional, Union | |
| class Problem: | |
| id: int | |
| problem: str | |
| answer: int | |
| difficulty: str | |
| def to_dict(self) -> Dict[str, Any]: | |
| """JSON-serialisable form matching the §14.2 schema.""" | |
| return { | |
| "id": self.id, | |
| "problem": self.problem, | |
| "answer": self.answer, | |
| "difficulty": self.difficulty, | |
| } | |
| class ProblemPool: | |
| problems: List[Problem] = field(default_factory=list) | |
| def load(cls, path: Union[str, Path]) -> "ProblemPool": | |
| """Load a problem pool from a JSON file at ``path``.""" | |
| path = Path(path) | |
| with path.open() as f: | |
| data = json.load(f) | |
| return cls(problems=[Problem(**item) for item in data]) | |
| def sample(self, n: int = 10, seed: Optional[int] = None) -> List[Problem]: | |
| """Return ``n`` problems sampled without replacement. | |
| Deterministic when ``seed`` is given. When ``n`` exceeds the | |
| pool size, returns the full pool (clamped, not raising). | |
| """ | |
| rng = random.Random(seed) | |
| return rng.sample(self.problems, k=min(n, len(self.problems))) | |
| def __len__(self) -> int: | |
| return len(self.problems) | |
| def load_problems(path: Optional[Union[str, Path]] = None) -> ProblemPool: | |
| """Load the bundled problem pool, or a custom path if provided.""" | |
| if path is None: | |
| path = Path(__file__).parent / "data" / "problems_pool.json" | |
| return ProblemPool.load(path) | |
| def check_answer(submitted: Any, ground_truth: Any) -> bool: | |
| """Strict integer equality. | |
| Rejects type mismatches (str vs int, float vs int, bool vs int) | |
| explicitly — ``True == 1`` would otherwise pass naive ``==``. | |
| """ | |
| if type(submitted) is not int or type(ground_truth) is not int: | |
| return False | |
| return submitted == ground_truth | |