File size: 2,312 Bytes
2cfc662
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
"""Table geometry read straight from pooltool -- a facts layer, no rules.

Why it exists: the front-end sizes its canvas from the real table and maps
broadcast coordinates (2.54 x 1.27 m) onto the app table with a single
similarity factor, so ``/api/table`` has to return w/l/ball_r/pockets. The
previous repository took those numbers from ``PositionPlayEnv`` (the RL
environment), which is not ported here -- and hard-coding them would let
them drift away from the table specs. This module reads the same source the
environment read: ``pt.Table.default()``.

pooltool is imported LAZILY inside the function: the app imports this module
at startup while importing pooltool costs ~20s (Numba), so the call happens
on the background thread of ``app/main.py``, and the contract tests (which
stub pooltool) can import this module without pulling anything in.
"""

from __future__ import annotations

BALL_R = 0.028575        # ball radius (m) -- the pooltool default, the same
                         # number as ``poolcoach_cv.broadcast.BALL_R_M``


def pocket_name(w: float, l: float, xy) -> str:
    """Pocket name derived from its centre, same rule as the previous
    repository (``poolcoach_rl.recommend.geometry.pocket_name``). Nothing in
    the Analyzer front-end renders it -- it is kept because the field is
    part of the /api/table contract and it makes the payload readable."""
    lr = "left" if xy[0] < w / 2 else "right"
    if xy[1] < l / 3:
        return f"bottom-{lr} corner"
    if xy[1] > 2 * l / 3:
        return f"top-{lr} corner"
    return f"{lr} side"


def table_facts() -> dict:
    """``{w, l, ball_r, pockets: [{x, y, r, name}]}`` of the default table.

    Call it on a background thread (importing pooltool is heavy). Pocket
    order follows pooltool's ``table.pockets`` -- the same order the
    previous repository returned."""
    import pooltool as pt

    table = pt.Table.default()
    w, l = float(table.w), float(table.l)
    pockets = []
    for p in table.pockets.values():
        xy = (float(p.center[0]), float(p.center[1]))
        pockets.append({"x": xy[0], "y": xy[1],
                        "r": float(getattr(p, "radius", 2 * BALL_R)),
                        "name": pocket_name(w, l, xy)})
    return {"w": w, "l": l, "ball_r": BALL_R, "pockets": pockets}