"""Bank poleceń do użycia na urządzeniu (ONDEVICE §4.1).""" import argparse import json import random import sys from itertools import product from typing import Optional from .generator import Clause, Command, random_command, render from .lexicon import COLORS, LOCATIONS, OBJECTS, VERBS # Rozmiary przestrzeni: # Poziom 1: 2 × 10 × 6 = 120 unikatów # Poziom 2: 2 × 10 × 6 × 6 = 720 unikatów # Poziom 3: ~635 040 unikatów → generujemy losowo z deduplikacją def _enumerate_level1() -> list[str]: texts = [] for v, o, loc in product(VERBS, OBJECTS, LOCATIONS): texts.append(render(Command([Clause(v, o, loc, None)], 1))) return texts def _enumerate_level2() -> list[str]: texts = [] for v, o, loc, c in product(VERBS, OBJECTS, LOCATIONS, COLORS): texts.append(render(Command([Clause(v, o, loc, c)], 2))) return texts def _random_unique_level3(target: int) -> list[str]: seen: set[str] = set() results: list[str] = [] consecutive_misses = 0 while len(results) < target and consecutive_misses < 500: text = render(random_command(3)) if text not in seen: seen.add(text) results.append(text) consecutive_misses = 0 else: consecutive_misses += 1 return results def generate_bank(per_level: int, seed: Optional[int] = None) -> dict: """Zwraca słownik gotowy do zrzutu jako JSON. Dla poziomów 1 i 2 wylicza wyczerpująco wszystkie kombinacje i tasuje; dla poziomu 3 generuje losowo z deduplikacją. Jeśli przestrzeń jest mniejsza niż per_level, zwraca tyle ile możliwe. """ if seed is not None: random.seed(seed) commands: list[dict] = [] for level, pool_fn in [(1, _enumerate_level1), (2, _enumerate_level2)]: pool = pool_fn() random.shuffle(pool) for text in pool[:per_level]: commands.append({"level": level, "text": text}) for text in _random_unique_level3(per_level): commands.append({"level": 3, "text": text}) return { "meta": {"version": "1", "per_level": per_level}, "commands": commands, } def run_export(argv: list[str]) -> None: parser = argparse.ArgumentParser( prog="python -m ipin_vr export", description="Generuj bank poleceń do JSON (ONDEVICE §4.1)", ) parser.add_argument( "--per-level", type=int, default=300, metavar="N", help="liczba unikatów na poziom (domyślnie: 300)", ) parser.add_argument( "--out", default="-", metavar="PATH", help="ścieżka pliku wyjściowego (- = stdout)", ) parser.add_argument( "--seed", type=int, metavar="N", help="seed generatora losowego", ) args = parser.parse_args(argv) bank = generate_bank(per_level=args.per_level, seed=args.seed) output = json.dumps(bank, ensure_ascii=False, indent=2) if args.out == "-": print(output) else: with open(args.out, "w", encoding="utf-8") as f: f.write(output) by_level = {} for cmd in bank["commands"]: by_level[cmd["level"]] = by_level.get(cmd["level"], 0) + 1 summary = ", ".join(f"L{k}:{v}" for k, v in sorted(by_level.items())) total = len(bank["commands"]) print(f"Zapisano {total} poleceń → {args.out} ({summary})", file=sys.stderr)