Download mathly2/readiness.py from wzender/mathly: direct link, hf CLI and curl.
- Browser
- Download file 2.67 kB
-
https://huggingface.co/spaces/wzender/mathly/resolve/main/mathly2/readiness.py
- Command line
-
hf download hf://spaces/wzender/mathly/mathly2/readiness.py
-
curl -L -o readiness.py https://huggingface.co/spaces/wzender/mathly/resolve/main/mathly2/readiness.py
2.67 kB
| """The readiness number for a real test: one 0-100 number that only tests move (practice tests and simulations), never the path. | |
| Every handed-in test pulls the number toward its grade, and only up: a grade above the number closes part of the gap, a grade at or below | |
| it changes nothing. A simulation closes more of the gap than a practice test; a practice test on skills the student picked closes less | |
| (it can skip the hard ones). So the number is never above the best grades, and the way up is more good tests, best of all a simulation. | |
| number' = number + GAIN[kind] * (grade - number) when grade > number | |
| """ | |
| from __future__ import annotations | |
| GAIN = {"simulation": 0.6, "practice": 0.3, "manual": 0.15} | |
| LEVELS = [(0, "ืืชืืืืื"), (40, "ืืืจื"), (70, "ืืืขื ืฉื"), (85, "ืืืื ืื")] | |
| def label(number: int) -> str: | |
| return [name for at, name in LEVELS if number >= at][-1] | |
| def next_level(number: int) -> dict | None: | |
| """The next level above the number: {"at", "name", "left"} (points left), or None at the top.""" | |
| above = [(at, name) for at, name in LEVELS if at > number] | |
| return {"at": above[0][0], "name": above[0][1], "left": above[0][0] - number} if above else None | |
| def step(value: float, kind: str, grade: float) -> float: | |
| return value + GAIN[kind] * (grade - value) if grade > value else value | |
| def compute(results: list[tuple[str, int]]) -> dict: | |
| """`results`: the handed-in tests of one real test, oldest first, as (kind, grade) with kind simulation, practice or manual.""" | |
| value = 0.0 | |
| for kind, grade in results: | |
| value = step(value, kind, grade) | |
| number = max(0, min(100, int(value + 0.5))) | |
| best = lambda kinds: max((g for k, g in results if k in kinds), default=None) | |
| return {"number": number, "label": label(number), "next": next_level(number), | |
| "practices": sum(1 for k, _ in results if k != "simulation"), "simulations": sum(1 for k, _ in results if k == "simulation"), | |
| "practice_best": best(("practice", "manual")), "simulation_best": best(("simulation",)), | |
| "can_add": {k: max(0, int(GAIN[k] * (100 - value) + 0.5)) for k in GAIN}} # what a perfect test of each kind would add now | |
| def change(before: list[tuple[str, int]], result: tuple[str, int]) -> dict: | |
| """What one handed-in test did to the number: before, after, the gain, and whether it reached a new level.""" | |
| old, new = compute(before), compute([*before, result]) | |
| return {"before": old["number"], "after": new["number"], "gain": new["number"] - old["number"], "label": new["label"], | |
| "level_up": new["label"] != old["label"], "next": new["next"]} | |