ipin-vr/ipin_vr/export.py

108 lines
3.3 KiB
Python
Raw Normal View History

"""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)