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 エイイチと決めた)