Spaces:
Sleeping
Sleeping
File size: 5,108 Bytes
78738de | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 | """Quét seed bàn mẫu "thoáng" cho app — BRIEF 31/07/2026 việc B.5.
Sinh bàn 9 bi ngẫu nhiên (ĐÚNG generator ``_gen_table`` của eval_fullrack —
import, không copy), rồi TỰ CHƠI bằng chính zone V2 trong sim: mỗi cú lấy
top-1 của ``recommend_v2``, áp ``balls_final``, lặp tới khi ăn bi 9 (thắng)
hoặc hết đường. Seed nào chạy HẾT BỘ mới vào danh sách; app runtime chỉ bốc
ngẫu nhiên trong danh sách đó (``app/static/demo_boards.json``).
Sim tất định ⇒ seed đạt là đạt mãi — VỚI ĐÚNG BẢN TIÊU CHÍ NÀY (design §8
V2, 31/07/2026). Đổi tiêu chí là phải quét lại; trường ``criteria`` trong
JSON tồn tại để lần đổi đó không im lặng.
KHÔNG PHẢI EVAL (BRIEF bối cảnh 11b): đây là curation cho demo/UX. Mọi phép
đo sau này dùng seed riêng của script eval như cũ — file này không được dùng
chung với chúng, kẻo "tỉ lệ chạy hết" của demo bị đọc nhầm thành số đo.
Số PHẢI BÁO trong HANDOFF: quét bao nhiêu seed, đạt bao nhiêu — tỉ lệ này
chính là số "hết đường tự nhiên" trên bàn ngẫu nhiên (Bối cảnh 4).
python scripts/gen_demo_boards.py --want 10 --max-seeds 100
"""
from __future__ import annotations
import argparse
import json
import sys
import time
from pathlib import Path
ROOT = Path(__file__).resolve().parents[1]
sys.path.insert(0, str(ROOT / "src"))
sys.path.insert(0, str(ROOT)) # import scripts.eval_fullrack
OUT = ROOT / "app" / "static" / "demo_boards.json"
MAX_SHOTS = 12 # ván 9-ball tối đa 9 cú; dư là có gì đó sai
def self_play(env_h, balls):
"""Tự chơi bằng V2. Trả (ok, n_shots, reason)."""
import numpy as np
from poolcoach_rl.recommend import recommend_v2
cur = {bid: np.asarray(xy, dtype=np.float64) for bid, xy in balls.items()}
for i in range(MAX_SHOTS):
res = recommend_v2(cur, env_h=env_h, alternatives=0, n_render=0)
if not res.shots:
return False, i, f"het duong o cu {i + 1} (target {res.target})"
s = res.shots[0]
if s.win:
return True, i + 1, "an bi 9"
cur = {bid: np.asarray(xy, dtype=np.float64)
for bid, xy in s.balls_final.items() if xy is not None}
if not any(b != "cue" for b in cur):
# hết bi mà chưa win — bàn không có bi 9? không xảy ra với full
return False, i + 1, "het bi ma khong win"
return False, MAX_SHOTS, "qua 12 cu — vong lap bat thuong"
def main():
ap = argparse.ArgumentParser()
ap.add_argument("--want", type=int, default=10,
help="số bàn đạt cần gom đủ thì dừng")
ap.add_argument("--max-seeds", type=int, default=100,
help="trần số seed quét (chặn thời gian chạy)")
ap.add_argument("--start-seed", type=int, default=1000,
help="seed đầu; CỐ Ý xa dải seed của các script eval "
"(eval dùng 7/42/123...) — bối cảnh 11b")
args = ap.parse_args()
import numpy as np
from poolcoach_rl.envs import PositionPlayEnv
from poolcoach_rl.envs.position_env import BALL_R
from poolcoach_rl.recommend import warmup
from scripts.eval_fullrack import _gen_table
env_h = PositionPlayEnv()
print("[demo] warmup JIT (~40s lan dau)...", flush=True)
warmup(env_h)
boards, scanned = [], 0
t0 = time.time()
for seed in range(args.start_seed, args.start_seed + args.max_seeds):
if len(boards) >= args.want:
break
scanned += 1
rng = np.random.default_rng(seed)
balls = _gen_table(rng, env_h.w, env_h.l, BALL_R, full=True)
ok, n, reason = self_play(env_h, balls)
print(f"[demo] seed {seed}: {'DAT' if ok else 'rot'} "
f"({n} cu, {reason})", flush=True)
if ok:
boards.append({
"seed": seed,
"n_shots": n,
"balls": {bid: [round(float(xy[0]), 6), round(float(xy[1]), 6)]
for bid, xy in balls.items()},
})
out = {
"criteria": "ZonePlanner V2 - design S8, chot 31/07/2026 "
"(loc i-v, xep roll_len -> |d-1m| -> enumerate)",
"note": "Curation cho demo/UX, KHONG phai eval (BRIEF 31/07 boi canh "
"11b). Doi tieu chi la phai quet lai bang "
"scripts/gen_demo_boards.py.",
"generator": "scripts.eval_fullrack._gen_table, seed ghi tung bang",
"scanned": scanned,
"passed": len(boards),
"boards": boards,
}
OUT.write_text(json.dumps(out, ensure_ascii=False, indent=1),
encoding="utf-8")
el = time.time() - t0
print(f"\n[demo] quet {scanned} seed -> {len(boards)} dat "
f"({100.0 * len(boards) / max(scanned, 1):.0f}%) trong {el:.0f}s")
print(f"[demo] ghi {OUT}")
return 0 if boards else 1
if __name__ == "__main__":
sys.exit(main())
|