Spaces:
Running
Running
Download game/tasks.py from FineEnvs/ScottWuMath: direct link, hf CLI and curl.
- Browser
- Download file 3.6 kB
-
https://huggingface.co/spaces/FineEnvs/ScottWuMath/resolve/main/game/tasks.py
- Command line
-
hf download hf://spaces/FineEnvs/ScottWuMath/game/tasks.py
-
curl -L -o tasks.py https://huggingface.co/spaces/FineEnvs/ScottWuMath/resolve/main/game/tasks.py
3.6 kB
| """Levels and task generation. | |
| The levels follow the video: the 24 game with four cards, then "once that got too easy, you take | |
| eight cards and you make the current year", then nine cards for any four-digit number someone | |
| names. Three-digit with six cards sits between the two as a step up from 24. | |
| Every generated task is solvable: the deal is checked with the solver and redealt if it fails. | |
| """ | |
| from __future__ import annotations | |
| import datetime as _dt | |
| import random | |
| from dataclasses import dataclass | |
| from .cards import Card, cards_from_ranks, deal | |
| from .expr import Tree, steps, to_text | |
| from .solver import solve | |
| CURRENT_YEAR = _dt.date.today().year | |
| class Level: | |
| name: str | |
| title: str | |
| n_cards: int | |
| low: int | |
| high: int | |
| LEVELS = { | |
| "24": Level("24", "24", 4, 24, 24), | |
| "three-digit": Level("three-digit", "Three-digit", 6, 100, 999), | |
| "year": Level("year", "Year", 8, 1900, 2100), | |
| "four-digit": Level("four-digit", "Four-digit", 9, 1000, 9999), | |
| } | |
| DEFAULT_LEVEL = "year" | |
| def cards_for_target(target: int) -> int: | |
| """How many cards a custom target gets: 4 for up to 99, 6 for three digits, 8 for 1000-2999, then 9.""" | |
| if target < 100: | |
| return 4 | |
| if target < 1000: | |
| return 6 | |
| if target < 3000: | |
| return 8 | |
| return 9 | |
| def make_task( | |
| rng: random.Random, | |
| level: str | None = None, | |
| target: int | None = None, | |
| n_cards: int | None = None, | |
| ranks: list[int] | None = None, | |
| task_id: str | None = None, | |
| time_limit: float = 2.0, | |
| max_deals: int = 50, | |
| ) -> dict: | |
| """Deal a solvable task. | |
| With no `target`, the level picks one from its range. A given `target` keeps the level's card | |
| count, or without a level picks one by size (`cards_for_target`). Given `ranks` are dealt as | |
| they are and may have no solution (then `solution` is None). | |
| """ | |
| if level is not None and level not in LEVELS: | |
| raise ValueError(f"unknown level {level!r}; choose one of {', '.join(LEVELS)}") | |
| if target is None: | |
| lvl = LEVELS[level or DEFAULT_LEVEL] | |
| level, target = lvl.name, rng.randint(lvl.low, lvl.high) | |
| target = int(target) | |
| if not 0 <= target <= 1_000_000: | |
| raise ValueError("target must be a whole number from 0 to 1,000,000") | |
| if ranks is not None: | |
| cards = cards_from_ranks(list(ranks), rng) | |
| tree = solve([c.rank for c in cards], target, time_limit) | |
| return _task(cards, target, tree, level or "custom", task_id) | |
| n = n_cards or (LEVELS[level].n_cards if level else cards_for_target(target)) | |
| if not 2 <= n <= 12: | |
| raise ValueError("deal between 2 and 12 cards") | |
| for _ in range(max_deals): | |
| cards = deal(n, rng) | |
| tree = solve([c.rank for c in cards], target, time_limit) | |
| if tree is not None: | |
| return _task(cards, target, tree, level or "custom", task_id) | |
| raise RuntimeError(f"no solvable deal of {n} cards for {target} in {max_deals} tries") | |
| def _task(cards: list[Card], target: int, tree: Tree | None, level: str, task_id: str | None) -> dict: | |
| return { | |
| "id": task_id or f"{level}-{target}-" + "".join(c.label for c in cards), | |
| "level": level, | |
| "target": target, | |
| "cards": [c.to_dict() for c in cards], | |
| "solution": None if tree is None else to_text(tree), | |
| "solution_steps": [] if tree is None else steps(tree), | |
| } | |
| def public(task: dict) -> dict: | |
| """The task as an agent may see it: no reference solution.""" | |
| return {k: v for k, v in task.items() if k not in ("solution", "solution_steps")} | |