def places(L, grid, standby_slots, aisles):
    W, D = L["outer"]["w"], L["outer"]["d"]

    def free(x, y):   # 障害物までの余裕（m）。店の外は −1
        cy, cx = grid.cell(x, y)
        if not (0 <= cy < grid.ny and 0 <= cx < grid.nx):
            return -1.0
        return float(grid.clear_person[cy, cx])   # 場所の点は人が立つ所なので、人の余裕で見る
    P = []
    st = L["start"]
    P.append(dict(kind="FoodPass", label="受け渡し口の前（出発点）", rect=L["dish_up"][0]["rect"], point=list(st)))
    P.append(dict(kind="DishReturn", label="下げ膳の返却（受け渡し口と同じ点）", rect=L["dish_up"][0]["rect"], point=list(st)))
    e = L["entrance"]
    m = (e["a0"] + e["a1"]) / 2
    ep = {"bottom": (m, 0.5), "top": (m, D - 0.5), "left": (0.5, m), "right": (W - 0.5, m)}[e["side"]]
    P.append(dict(kind="Entrance", label="入口", point=[r2(ep[0]), r2(ep[1])]))
    kinds = {"パントリー": "Pantry", "待合": "Waiting", "レジ": "Register", "レジ内": "RegisterBack", "トイレ": "Toilet",
             "ドリンクバー": "DrinkBar", "キッチン": "Kitchen"}
    for r in L["rooms"]:
        k = kinds.get(r["label"])
        if not k:
            continue
        if k == "Toilet":
            dz = L["toilet_doors"][0]
            P.append(dict(kind=k, label="トイレの入口の前", rect=r["rect"], point=[r2((dz[0] + dz[2]) / 2), r2((dz[1] + dz[3]) / 2)]))
        elif k == "Pantry":
            P.append(dict(kind=k, label="パントリー（受け渡し口の前と同じ点）", rect=r["rect"], point=list(st)))
        elif k == "RegisterBack":
            x0, y0, x1, y1 = r["rect"]
            P.append(dict(kind=k, label="レジ内（店員が立つ所）", rect=r["rect"], point=[r2((x0 + x1) / 2), r2((y0 + y1) / 2)]))
        elif k == "Kitchen":
            continue
        elif k == "Register":
            # 客の側は、レジ内（店員の立つ所）の反対側
            back = [b["rect"] for b in L["rooms"] if b["label"] == "レジ内"]
            side = _opposite_side(r["rect"], back[0]) if back else front_point(r["rect"], free)[0]
            pt, nrm = _side_point(r["rect"], side, 0.4)
            P.append(dict(kind=k, label="レジの前（会計に立つ点）", rect=r["rect"], point=pt, front=side))
            for q in range(1, REG_QUEUE + 1):   # 並ぶ点：会計に立つ点から外へ 0.5m ずつ。障害物から0.25m未満・細い通路に入る所で打ち切る
                qx, qy = pt[0] + nrm[0] * 0.5 * q, pt[1] + nrm[1] * 0.5 * q
                if free(qx, qy) < 0.25 or _in_aisle(aisles, qx, qy):
                    break
                P.append(dict(kind="RegisterQueue", label=f"レジに並ぶ点 {q}", point=[r2(qx), r2(qy)]))
        elif k == "DrinkBar":
            side, _ = front_point(r["rect"], free)
            x0, y0, x1, y1 = r["rect"]
            horiz = side in ("bottom", "top")
            length = (x1 - x0) if horiz else (y1 - y0)
            n = max(1, int(length / 0.9))   # 前に立つ点：0.9m に1人
            pt, nrm = _side_point(r["rect"], side, 0.4)
            P.append(dict(kind=k, label="ドリンクバーの前", rect=r["rect"], point=pt, front=side))
            for q in range(n):
                f = (q + 0.5) / n
                base = (x0 + (x1 - x0) * f, y0 if side == "bottom" else y1) if horiz else (x0 if side == "left" else x1, y0 + (y1 - y0) * f)
                P.append(dict(kind="DrinkBarStand", label=f"ドリンクバーの前に立つ点 {q + 1}", point=[r2(base[0] + nrm[0] * 0.4), r2(base[1] + nrm[1] * 0.4)]))
            # 並ぶ列の付け根：ふつうは真ん中の前。真ん中の前の1つ目の点が置けないとき（障害物から0.25m未満・細い通路）は、
            # ドリンクバーの前の幅の中で0.05mずつ左右へずらし、最初に置ける所にする（2026-10-28 エイイチと決めた。
            # ⑥のドリンクバーを左へ0.8m寄せたら、真ん中の前が待機場所に近すぎて並ぶ点が消えたため。⑥は待機場所の右＝前と同じ所に来る）
            tang = (1.0, 0.0) if horiz else (0.0, 1.0)
            lo, hi = ((x0, x1) if horiz else (y0, y1))
            c0 = pt[0] if horiz else pt[1]

            def q_ok(px, py):
                return free(px, py) >= 0.25 and not _in_aisle(aisles, px, py)
            first = (pt[0] + nrm[0] * 0.9, pt[1] + nrm[1] * 0.9)
            if not q_ok(*first):
                for i in range(1, int((hi - lo) / 0.05) + 1):
                    hit = None
                    for sgn in (1, -1):
                        c = c0 + sgn * 0.05 * i
                        if lo <= c <= hi:
                            cand = (first[0] + tang[0] * sgn * 0.05 * i, first[1] + tang[1] * sgn * 0.05 * i)
                            if q_ok(*cand):
                                hit = (pt[0] + tang[0] * sgn * 0.05 * i, pt[1] + tang[1] * sgn * 0.05 * i)
                                break
                    if hit:
                        pt = [hit[0], hit[1]]
                        break
            for q in range(1, DRINK_QUEUE + 1):   # 並ぶ点：付け根から外へ。障害物から0.25m未満・細い通路に入る所で打ち切る
                qx, qy = pt[0] + nrm[0] * (0.4 + 0.5 * q), pt[1] + nrm[1] * (0.4 + 0.5 * q)
                if free(qx, qy) < 0.25 or _in_aisle(aisles, qx, qy):
                    break
                P.append(dict(kind="DrinkBarQueue", label=f"ドリンクバーに並ぶ点 {q}", point=[r2(qx), r2(qy)]))
        else:
            side, pt = front_point(r["rect"], free)
            P.append(dict(kind=k, label=r["label"] + "の前", rect=r["rect"], point=pt, front=side))
    # スタッフが待つ点：受け渡し口の前の横（待機場所と反対の側）に、パントリーの壁ぞいへ 0.6m おき（仮の規則）
    for i, pt in enumerate(staff_standby_points(L, free, aisles)):
        P.append(dict(kind="StaffStandby", label=f"スタッフが待つ点 {i + 1}", point=pt))
    for i, s in enumerate(standby_slots):
        P.append(dict(kind="RobotStandby", label=f"ロボットの待機場所 {i + 1}", rect=rect(*s), point=[r2((s[0] + s[2]) / 2), r2((s[1] + s[3]) / 2)]))
    return P



# ---------------------------------------------------------------- ロボットの道順（2026-10-22 エイイチと決めた）
