---
title: "サービスロボット導入シミュレーション Log#22 | ファミレス6店で、配膳ロボット2台は同じ所で詰まった"
slug: six-stores-fix-the-rules
date: 2026-10-29
day: 402
meta_description: "Unityの3Dで再現した6つのファミレスで配膳ロボットを2台にすると、どの店でも待機場所と受け渡し口のまわりで詰まった。19卓の店では1台が試算どおり、2台目は待ちを延ばした。"
tags: [サービスロボット導入シミュレーション, 配膳ロボット, 飲食店, Unity, シミュレーション, 店の形, 店舗レイアウト]
series: "導入シミュレーション"
---

Unity の3Dで再現した6つのファミレスで配膳ロボットを2台にすると、どの店でも、ロボットの待機場所と料理の受け渡し口のまわりに止まりが集まりました（30秒以上の止まりのうち25〜57%）。店ごとに図面を直しても同じ所で詰まるので、直す先は1店ずつの配置ではなく、待機場所をどこに置くかといった「店の形を作る決まり」のほうだと分かりました。

配膳ロボットを入れると店がどう変わるかを、2つのやり方で調べています。1つはサイトの試算で、卓までの距離・料理の数・スタッフの人数から待ち時間を計算します。もう1つは [Unity](https://unity.com/ja)（ゲームを作る道具）で作った3Dのファミレスで、お客さん・スタッフ・ロボットを1人ずつ動かすシミュレーションです。どちらも、コードで作った同じ「店の形」（卓・壁・通路の配置のデータ）を読みます。実在の店ではなく、仮の店です。

今回で、用意した6つの店の形をすべて3Dの店に建て終えました。最後の店は「② 定番の郊外型」です。昔働いていたファミレスの見取り図を記憶から起こし、決まりに合わせて直した19卓・88席の小さな店で、角テーブル・丸テーブル・長テーブルがあります。ほかの5店はボックス席だけだったので、②の14卓には椅子と座る位置のデータがなく、3Dの店では客が座れませんでした。まずこれを作りました。

建てて1回ずつ回すと、ロボット2台の回で、丸テーブル2つの間（1.1m）にロボットが止まり、もう1台が抜けられずに60秒動けなくなるのが8回出ました。記憶の店はかなり昔のものなので、回れない所は変えてよいと決め、右の丸テーブルを1.0m右へ寄せて間を2.1mにしました。建て直した確かめでは8回が0回になり、そのまま30回の夜に進みました。

| やったこと | なぜ | 結果 |
|---|---|---|
| 角テーブル・丸テーブル・長テーブルに椅子と座る位置を作った | 3Dの店で、②の14卓に客が座れなかった | 椅子58・座る位置88。卓の数・距離は6店とも変わらない |
| ②を3Dの店に建て、1回ずつ回した | 建てられるか、どこで止まるかを見るため | 建った。2台で、丸テーブルの間の60秒の止まりが8回 |
| 右の丸テーブル（T06）を右へ1.0m寄せた | 間が1.1mで、止まったロボットの横に0.24mしか残らない | 横に1.06m残る。確かめで8回→0回 |
| ②の試算だけ計算し直した | 卓までの距離が5卓で変わった | 2台の入店待ち 1.60→1.17分 |
| ②を種10個ずつ、計30回回した | 1回ずつでは来る客の数がぶれるため | 1台は試算どおり。2台は1台より待ちが延びた |
| 6店の夜を並べた | どの店にも出る詰まりを見分けるため | 待機場所と受け渡し口のまわりが25〜57% |

②の30回の結果は次のとおりです（種10個の中央値。右は試算）。

| | ロボット0台 | 1台 | 2台 |
|---|---|---|---|
| 入店待ち（分） | 1.96 / 2.65 | 1.69 / 1.69 | 2.10 / 1.17 |
| 料理の待ち（分） | 0.89 / 0.61 | 1.04 / 0.94 | 1.04 / 0.39 |
| 会計待ち（分） | 1.13 / 1.41 | 1.06 / 1.30 | 1.34 / 1.12 |
| 60秒動けなくなった（1回あたり） | 0 | 0 | 12.5 |

1台は、入店待ちが試算とぴったり同じ1.69分でした。2台にすると、試算では1.17分に縮むのに、3Dの店では2.10分に延びました。2台の回の30秒以上の止まり192回の内訳は、入口の右の待合のまわり56回、待機場所の中54回、受け渡し口のまわり32回です。待合のまわりは、お客さんが多く来た種だけで出ていて、案内を待つお客さんがロボットの通り道に立っていました。

6店の夜を並べると、待機場所の中と受け渡し口から2.5m以内の止まりは、③38%・⑦31%・④25%・⑤30%・⑥57%・②45%でした。**6店とも、待機場所を受け渡し口のすぐ横（受け渡し口の点から待機場所の端まで0.95〜1.7m）に置くという同じ決め方で作っているので、店ごとにドリンクバーやレジや卓を動かしても、この詰まりは消えません。** 次は、待機場所・待合・スタッフが待つ点を、店ごとではなく店の形を作る決まりとして考え直します。

この記事の後半は作業ログです。②の椅子の作り方、3Dの店での1回ずつの確かめ、丸テーブルを動かす案の比べ、試算の計算し直し、30回の結果、6店の並べ直しまでを、コード・依頼文・報告・出力とあわせて載せます。

配膳ロボットを自分の店に入れたらどうなるかは、このシリーズの試算をもとにした別のページで試せます。

【バナー】serving-robot-one-less-staff


## 作業ログ ― ②の14卓には椅子がなく、Unity で客が座れなかった

④⑤⑥と進めてきた「サイトの店の形を Unity に建てる」作業の最後が、②（定番の郊外型・記憶の店）です。建てる前に、サイトの店の形から Unity 用に書き出している JSON（`public/sim/layouts/unity/p0_memory.json`）を見ると、19卓のうち14卓の `parts`（天板・ベンチ・椅子・座る位置）が null でした。

### Unity は、ゲームを作る道具で、3Dの店を動かしている

[Unity](https://unity.com/ja) は、米国の Unity Technologies が作っているゲームエンジン（ゲームを作るための道具）です。3Dの空間に床や壁や人を置き、物理の計算をしながら動かせます。このシリーズでは、ファミレスの店を3Dで建て、お客さん・スタッフ・配膳ロボットを1人ずつ動かして、待ち時間や詰まりを測っています。

この記事で使う言葉は、次のとおりです。

| 言葉 | 意味 |
|---|---|
| 店の形 | 卓・壁・部屋・通路・ロボットが止まる位置のデータ。サイトのコード（`tools/sim_layouts/`）で作り、Unity はそれを読んで店を建てる。Unity で形を作らない |
| NavMesh | 人やロボットが歩ける床の面。Unity が店の形から作り、その上で道を引く |
| 種（乱数の種） | お客さんが来る時刻・人数などを決めるくじの番号。同じ種なら同じお客さんが来る。種0〜9の10個で回すと、混み方の違う10通りが見られる |
| 夜 | 条件と種を並べて、画面を出さずにまとめて回すこと（ロボット0・1・2台 × 種10個で30回） |
| 台帳 | 3Dの店の回ごとの記録を1行ずつ足していく CSV（`unity_ledger_v1.csv`）。追記だけで、前の行は書き換えない |
| 30秒以上の止まり・動けなくなった | ロボットが30秒以上止まった回数と、そのうち60秒止まって作りの逃がし弁で動かされた回数 |

このプロジェクトでの使い方は、サイトの試算を正とし、試算と同じ店の形・同じ条件で3Dの店を回して、通路で起きること（止まる回数・立ち往生）を測ることです。数字は完全には合わない前提で、向きと大きさで比べます。

### ②の角テーブル・丸テーブル・長テーブルは、部品の作り方がまだなかった

②は記憶の店から起こしたので、ほかの5店（ボックス席・2人席・L字ソファの6人席だけ）にはない卓があります。

| 卓の種類 | 卓 | 部品 |
|---|---|---|
| 4人の角テーブル（t4） | T03・T04・T07・T08・T11・T12・T14〜T17・T19 の11卓 | なし（null） |
| 4人の丸テーブル（r4） | T05・T06 の2卓 | なし（null） |
| 6人の長テーブル（long6） | T13 の1卓 | なし（null） |
| L字ソファの6人席（booth6L） | T01・T02・T09・T10・T18 の5卓 | あり |

部品がないと、Unity は卓の場所に箱を置くだけで、客が座る位置がありません。サイトの店の形の README にも「まだないもの」として書いてありました。部品の作り方はサイトの決まり（`unity_export.py`）で、Unity で手で作らないことにしているので、サイトの側で作ります。

### 記憶の店の4人席は、椅子2脚ずつの向かい合わせだった

角テーブルの椅子の並べ方は、記憶の店の実物に合わせることにしました。選んだのは「2脚ずつ向かい合わせ」です。そのうえで、椅子を置く2辺は、ロボットが止まる辺を含まない組にしました。ロボットは椅子のない天板の端に横付けし、両側の人が手を伸ばして料理を取る形です。

例外が1つあります。下の壁ぎわの4卓（T14・T16・T17・T19）は、壁との間が0.4mしかなく、壁側に座れません。ここは座れる2辺（左右）に椅子を置き、ロボットが止まる辺の横に椅子が来ます。丸テーブルも同じ置き方にし、天板は直径0.8mの丸、6人の長テーブルは図のとおり上下にスツール3つずつ（引かない）にしました。

- ねらい：②の19卓すべてに客が座れるようにし、Unity でほかの店と同じ規則で建てられるようにする
- 変わったこと：部品のない卓 14 → 0。椅子とスツール 58、座る位置 88（席数と同じ）。卓の数・止まる位置・距離は6店とも変わらない（測った値）
- 見込める効果：ほかの店と同じ形の記録で②を比べられる。角テーブルの店（ボックス席のない店）を次に作るときも、同じ規則で椅子を置ける

【画像】LOG402_01_store2_chairs.png ②の19卓に椅子を置いた図。橙の丸が角テーブル・丸テーブル・長テーブルの椅子とスツール、赤い点はロボットが止まる位置。下の壁ぎわの4卓は、止まる辺の横に椅子が来る

### 卓の部品を作る関数 unity_export.py の free_parts・long6_parts・table_parts（足した版）

```python
FREE_CHAIR_R = 0.2       # ②の角テーブル・丸テーブルの椅子の半径
FREE_TOP_GAP = 0.25      # 椅子の側の外形の辺から天板の縁まで（椅子は天板の下に0.15m入る）
STOOL_R = 0.22           # ②の6人の長テーブルのスツールの半径（図と同じ）
OUT = {"left": (-1, 0), "right": (1, 0), "bottom": (0, -1), "top": (0, 1)}


def free_parts(t, side, spot_sides):
    """②の4人の角テーブル（t4）・丸テーブル（r4）：椅子は2脚ずつ向かい合わせ（2026-10-29 エイイチの記憶）。
    椅子を置く2辺は、ロボットが止まる辺を含まない組（ロボットは天板の端に横付け）。
    ただしその組の片方に席に着く点がない（壁との間が狭くて座れない）ときだけ、座れる方の組にする（止まる辺の横に椅子が来る）"""
    x, y, w, h = t["x"], t["y"], t["w"], t["h"]
    cx, cy = x + w / 2, y + h / 2
    pref = ("top", "bottom") if side in ("left", "right") else ("left", "right")
    other = ("left", "right") if pref == ("top", "bottom") else ("top", "bottom")
    pair = pref if all(s in spot_sides for s in pref) or not all(s in spot_sides for s in other) else other
    cr, g = FREE_CHAIR_R, FREE_TOP_GAP
    chairs = []
    for s in pair:
        nx, ny = OUT[s]
        for f in (0.25, 0.75):
            if nx:
                px, py = (x + cr if nx < 0 else x + w - cr), y + h * f
            else:
                px, py = x + w * f, (y + cr if ny < 0 else y + h - cr)
            chairs.append(dict(rect=rect(px - cr, py - cr, px + cr, py + cr), pullable=True, pull_dir=[nx, ny], center=[r2(px), r2(py)]))
    if t["type"] == "r4":
        d = 0.8   # 丸い天板の直径（top は外接する正方形。top_shape で丸と示す）
        top = rect(cx - d / 2, cy - d / 2, cx + d / 2, cy + d / 2)
    elif pair == ("left", "right"):
        top = rect(x + g, y + 0.05, x + w - g, y + h - 0.05)
    else:
        top = rect(x + 0.05, y + g, x + w - 0.05, y + h - g)
    seats = [c.pop("center") for c in chairs]
    out = dict(top=top, benches=[], chairs=chairs, seat_points=seats, chair_sides=list(pair))
    if t["type"] == "r4":
        out["top_shape"] = "circle"
    return out


def long6_parts(t):
    """②の6人の長テーブル：天板3.2m×0.7m、上下にスツール3つずつ（図と同じ位置）。スツールは引かない"""
    cx, cy = t["x"] + t["w"] / 2, t["y"] + t["h"] / 2
    top = rect(cx - 1.6, cy - 0.35, cx + 1.6, cy + 0.35)
    chairs, seats = [], []
    for dy in (-0.75, 0.75):
        for dx in (-1.0, 0.0, 1.0):
            px, py = cx + dx, cy + dy
            chairs.append(dict(rect=rect(px - STOOL_R, py - STOOL_R, px + STOOL_R, py + STOOL_R), pullable=False, pull_dir=None, stool=True))
            seats.append([r2(px), r2(py)])
    return dict(top=top, benches=[], chairs=chairs, seat_points=seats, chair_sides=["bottom", "top"])


def table_parts(t, FT, side=None, spot_sides=()):
    if t["type"] == "booth":
        return booth_parts(t, FT)
    if t["type"] == "t2":
        return t2_parts(t, FT)
    if t["type"] == "booth6L":
        return lsofa_parts(t)
    if t["type"] in ("t4", "r4"):
        return free_parts(t, side, spot_sides)
    if t["type"] == "long6":
        return long6_parts(t)
    return None
```

### 部品を作る前に席に着く点を出すようにした unity_export.py の build（直した版）

椅子を置く辺を決めるのに「席に着く点がある辺」を使うので、`seat_spots` を先に呼ぶ順番に変えました。

```python
def build(L, analysis_tables, grid, dist, dist_pass, sides, standby_slots, FT, meta):
    aisles = find_aisles(L)
    aisle_entrances(aisles, grid, dist, dist_pass)
    tables = []
    for t, a, sd in zip(L["tables"], analysis_tables, sides):
        spots = seat_spots(sd, grid)
        parts = table_parts(t, FT, a.get("side"), {s["side"] for s in spots})
        stop = a.get("stop")
        ai = None
        if stop:
            for x in aisles:
                r = x["rect"]
                if r[0] - 0.05 <= stop[0] <= r[2] + 0.05 and r[1] - 0.05 <= stop[1] <= r[3] + 0.05:
                    ai = x["id"]
                    break
        tables.append(dict(id=t["id"], type=t["type"], seats=t["seats"], footprint=rect(t["x"], t["y"], t["x"] + t["w"], t["y"] + t["h"]),
                           category=a["category"], stop=stop, side=a.get("side"), dist=a.get("dist"), aisle=ai,
                           parts=parts, spots=spots))
    walls = [dict(label=w["label"], rect=w["rect"], height=HEIGHTS["partition"] if w.get("joint") or w["label"] in ("仕切り", "目隠し") else
                  (HEIGHTS["toilet_wall"] if w["label"] == "トイレの壁" else HEIGHTS["wall"])) for w in L["walls"]]
    st = (meta or {}).get("settings") or {}
    model = (meta or {}).get("robot_model") or {}
    routes = build_routes(L, analysis_tables, grid, st.get("normal_width", 1.0), model.get("pass_width", 0.8)) if st else None
    return dict(meta=dict(meta, heights=HEIGHTS, rules=__doc__.strip()), routes=routes,
                name=L["name"], outer=L["outer"], outline=L.get("outline"), entrance=L["entrance"],
                floor=floor_rects(L), outer_walls=outer_walls(L), walls=walls,
                rooms=[dict(label=r["label"], kind=r["kind"], rect=r["rect"], **WALKABLE.get(r["label"], {"walkable": False}))
                       for r in L["rooms"] if r["kind"] != "outside"],
                doors=L.get("doors", []), robot_keepout=[dict(label="会計の列（ロボットは通らない）", rect=list(r)) for r in L.get("robot_keepout", [])], aisles=aisles, tables=tables, places=places(L, grid, standby_slots, aisles))
```

### 家具の寸法 famires_v3.py の FURNITURE_TYPES（足した版）

```python
FURNITURE_TYPES = {
    "booth": dict(desc="ボックス席。向かい合うベンチ2つと間のテーブル。座る側（開いた側）は長い2辺。短い2辺はベンチの背",
                  bench_depth=0.55, table_depth=0.75, length=1.85, bench_length={"4": 1.2, "6": 1.8},
                  axis={"v": "ベンチが上下（座る側は左右）", "h": "ベンチが左右（座る側は上下）"}),
    "t2": dict(desc="2人席。壁側がベンチ、通路側が椅子。止まってよいのは椅子の側と、テーブルの横（ベンチの横は使わない）",
               footprint=[0.8, 1.4], table=[0.7, 0.6], bench_depth=0.45, chair_radius=0.18),
    "booth6L": dict(desc="L字ソファの6人席。ソファの内側の角にテーブル（約0.75m×1.2m）。止まってよいのは、内側の角の開いた2辺と、"
                         "そこからソファの端に沿って lsofa_end_reach（端の席の人が受け取れる所）まで",
                    sofa_depth_ratio={"band": 0.45, "column": 0.55}),
    "t4": dict(desc="②の4人の角テーブル（外形1.2m四方）。椅子は2脚ずつ向かい合わせ。止まってよいのは4辺（椅子はロボットが止まる辺を含まない組に置く）",
               footprint=[1.2, 1.2], chair_radius=0.2),
    "r4": dict(desc="②の4人の丸テーブル（外形1.1m四方・天板の直径0.8m）。椅子は t4 と同じ置き方。止まってよいのは4辺",
               footprint=[1.1, 1.1], top_diameter=0.8, chair_radius=0.2),
    "long6": dict(desc="②の6人の長テーブル（天板3.2m×0.7m）。上下にスツール3つずつ。止まってよいのは4辺",
                  footprint=[3.2, 1.94], table=[3.2, 0.7], stool_radius=0.22),
    "walls": dict(height_m_仮={"壁": 2.7, "仕切り": 1.2, "トイレの壁": 2.7}),
}
```

### 確かめの仕組みに足した確かめ test_famires_v3.py（②の部品）

```python
# ---- ②の角テーブル・丸テーブル・長テーブルの椅子（2026-10-29）
L = v.prepare(famires_p0.p0_memory())
ctx = {}
res, _ = v.analyze(L, v.SETTINGS["res"], ctx)
U = ux.build(L, res, ctx["grid"], ctx["d_norm"], ctx["d_pass"], ctx["sides"], v.standby_slots(L["robot_standby"]), v.FURNITURE_TYPES, {})
free = [t for t in U["tables"] if t["type"] in ("t4", "r4", "long6")]
expect("②：全部の卓に部品があり、座る位置の数が席数と同じ",
       all(t["parts"] and len(t["parts"]["seat_points"]) == t["seats"] for t in U["tables"]))
expect("②：角テーブル・丸テーブルの椅子は2脚ずつ向かい合わせ（向かい合う2辺に2脚ずつ）",
       all(len(t["parts"]["chairs"]) == 4 and set(t["parts"]["chair_sides"]) in ({"left", "right"}, {"top", "bottom"})
           for t in free if t["type"] != "long6"))
expect("②：椅子とスツールは卓の外形の内側",
       all(t["footprint"][0] - 1e-9 <= c["rect"][0] and c["rect"][2] <= t["footprint"][2] + 1e-9 and
           t["footprint"][1] - 1e-9 <= c["rect"][1] and c["rect"][3] <= t["footprint"][3] + 1e-9 for t in free for c in t["parts"]["chairs"]))
spot_sides = {t["id"]: {s["side"] for s in t["spots"]} for t in free}
expect("②：椅子を置く辺には、どれも席に着く点がある", all(set(t["parts"]["chair_sides"]) <= spot_sides[t["id"]] for t in free))
expect("②：ロボットが止まる辺に椅子があるのは、その向きの組では座れない卓だけ",
       all(t["side"] not in t["parts"]["chair_sides"] or not ({"top", "bottom"} if t["side"] in ("left", "right") else {"left", "right"}) <= spot_sides[t["id"]]
           for t in free if t["type"] != "long6"))
```

### 卓ごとの椅子の置き方を出したスクリプト check_chairs.py

```python
"""②の角テーブル・丸テーブル・長テーブルに椅子を置いた結果を、卓ごとに出して図にする（2026-10-29）。
使い方: python3 check_chairs.py <tools/sim_layouts のフォルダ> <出力.png>"""
import sys, json
sys.path.insert(0, sys.argv[1])
import famires_v3 as v, famires_p0, unity_export as ux
import matplotlib; matplotlib.use("Agg")
import matplotlib.pyplot as plt
from matplotlib.patches import Rectangle, Circle
from matplotlib import font_manager as fm
FONT = "/usr/share/fonts/opentype/noto/NotoSansCJK-Regular.ttc"
fm.fontManager.addfont(FONT); plt.rcParams["font.family"] = fm.FontProperties(fname=FONT).get_name()
L = v.prepare(famires_p0.p0_memory()); ctx = {}
res, err = v.analyze(L, v.SETTINGS["res"], ctx)
U = ux.build(L, res, ctx["grid"], ctx["d_norm"], ctx["d_pass"], ctx["sides"], v.standby_slots(L["robot_standby"]), v.FURNITURE_TYPES, {})
for t in U["tables"]:
    if t["type"] in ("t4", "r4", "long6"):
        p = t["parts"]; sp = {s["side"] for s in t["spots"]}
        print(t["id"], t["type"], "stop", t["side"], "spots", sorted(sp), "chairs", p["chair_sides"], "seats", len(p["seat_points"]),
              "stop-side-has-chair", t["side"] in p["chair_sides"])
fig, ax = plt.subplots(figsize=(13, 10.5))
for r in U["rooms"]:
    x0, y0, x1, y1 = r["rect"]; ax.add_patch(Rectangle((x0, y0), x1 - x0, y1 - y0, fc="#eceef2", ec="#999", lw=0.6))
    ax.text((x0 + x1) / 2, (y0 + y1) / 2, r["label"], ha="center", va="center", fontsize=7, color="#555")
for w in U["walls"] + [dict(rect=r) for r in U["outer_walls"]]:
    x0, y0, x1, y1 = w["rect"]; ax.add_patch(Rectangle((x0, y0), x1 - x0, y1 - y0, fc="#7d8590", ec="none"))
for t in U["tables"]:
    p = t["parts"]; x0, y0, x1, y1 = t["footprint"]
    ax.add_patch(Rectangle((x0, y0), x1 - x0, y1 - y0, fc="none", ec="#ccc", lw=0.5, ls="--"))
    for b in p["benches"]: ax.add_patch(Rectangle((b[0], b[1]), b[2] - b[0], b[3] - b[1], fc="#d6d9df", ec="#555", lw=0.6))
    tp = p["top"]
    if p.get("top_shape") == "circle": ax.add_patch(Circle(((tp[0] + tp[2]) / 2, (tp[1] + tp[3]) / 2), (tp[2] - tp[0]) / 2, fc="white", ec="#222", lw=1))
    else: ax.add_patch(Rectangle((tp[0], tp[1]), tp[2] - tp[0], tp[3] - tp[1], fc="white", ec="#222", lw=1))
    for c in p["chairs"]:
        r = c["rect"]; col = "#f08c00" if t["type"] in ("t4", "r4", "long6") else "#888"
        ax.add_patch(Circle(((r[0] + r[2]) / 2, (r[1] + r[3]) / 2), (r[2] - r[0]) / 2, fc=col, ec="#333", lw=0.5, alpha=0.85))
    if t["stop"]: ax.add_patch(Circle(tuple(t["stop"]), 0.13, fc="#e8590c", ec="white", lw=0.8, zorder=5))
    ax.text(x0, y1 + 0.08, t["id"], fontsize=7, color="#333")
ax.set_xlim(-0.5, 24.5); ax.set_ylim(-0.5, 19.6); ax.set_aspect("equal"); ax.axis("off")
ax.set_title("② 定番の郊外型：椅子の置き方（橙の丸＝椅子・スツール、赤い点＝ロボットが止まる位置）", fontsize=11)
plt.tight_layout(); plt.savefig(sys.argv[2], dpi=110)
```

#### check_chairs.py の出力

```text
T03 t4 stop bottom spots ['bottom', 'left', 'right', 'top'] chairs ['left', 'right'] seats 4 stop-side-has-chair False
T04 t4 stop bottom spots ['bottom', 'left', 'right', 'top'] chairs ['left', 'right'] seats 4 stop-side-has-chair False
T05 r4 stop right spots ['bottom', 'left', 'right', 'top'] chairs ['top', 'bottom'] seats 4 stop-side-has-chair False
T06 r4 stop bottom spots ['bottom', 'left', 'right', 'top'] chairs ['left', 'right'] seats 4 stop-side-has-chair False
T07 t4 stop right spots ['bottom', 'left', 'right', 'top'] chairs ['top', 'bottom'] seats 4 stop-side-has-chair False
T08 t4 stop right spots ['bottom', 'left', 'right', 'top'] chairs ['top', 'bottom'] seats 4 stop-side-has-chair False
T11 t4 stop bottom spots ['bottom', 'left', 'right', 'top'] chairs ['left', 'right'] seats 4 stop-side-has-chair False
T12 t4 stop right spots ['bottom', 'left', 'right', 'top'] chairs ['top', 'bottom'] seats 4 stop-side-has-chair False
T13 long6 stop right spots ['bottom', 'left', 'right', 'top'] chairs ['bottom', 'top'] seats 6 stop-side-has-chair False
T14 t4 stop right spots ['left', 'right', 'top'] chairs ['left', 'right'] seats 4 stop-side-has-chair True
T15 t4 stop top spots ['left', 'right', 'top'] chairs ['left', 'right'] seats 4 stop-side-has-chair False
T16 t4 stop left spots ['left', 'right', 'top'] chairs ['left', 'right'] seats 4 stop-side-has-chair True
T17 t4 stop left spots ['left', 'right', 'top'] chairs ['left', 'right'] seats 4 stop-side-has-chair True
T19 t4 stop left spots ['left', 'right', 'top'] chairs ['left', 'right'] seats 4 stop-side-has-chair True
```

### 6店の店の形を作り直した famires_v3.py の出力（版 dffc100b269c）

```text
[OK] p0_memory: {'name': '② 定番の郊外型', 'seats': 88, 'tables': 19, 'model': 'BellaBot', 'pass_width': 0.8, 'normal_width': 1.0, 'robot_tables': 19, 'robot_seats': 88, 'narrow_tables': 0, 'narrow_seats': 0, 'human_tables': 0, 'human_seats': 0, 'robot_dist_mean': 8.6, 'robot_dist_max': 13.78, 'human_walk_total': 0.0, 'human_walk_max': None}  マス目の差: []
[OK] p1_efficient_corner: {'name': '③ 効率重視型・入口が左下の角', 'seats': 160, 'tables': 42, 'model': 'BellaBot', 'pass_width': 0.8, 'normal_width': 1.0, 'robot_tables': 42, 'robot_seats': 160, 'narrow_tables': 0, 'narrow_seats': 0, 'human_tables': 0, 'human_seats': 0, 'robot_dist_mean': 10.6, 'robot_dist_max': 20.14, 'human_walk_total': 0.0, 'human_walk_max': None}  マス目の差: []
[OK] p2_efficient_narrow: {'name': '④ 効率重視型・狭い店・入口が右の壁', 'seats': 88, 'tables': 28, 'model': 'BellaBot', 'pass_width': 0.8, 'normal_width': 1.0, 'robot_tables': 28, 'robot_seats': 88, 'narrow_tables': 0, 'narrow_seats': 0, 'human_tables': 0, 'human_seats': 0, 'robot_dist_mean': 8.5, 'robot_dist_max': 13.92, 'human_walk_total': 0.0, 'human_walk_max': None}  マス目の差: []
[OK] p3_relaxed_center: {'name': '⑤ ゆったり型・入口が正面の中央', 'seats': 200, 'tables': 46, 'model': 'BellaBot', 'pass_width': 0.8, 'normal_width': 1.0, 'robot_tables': 46, 'robot_seats': 200, 'narrow_tables': 0, 'narrow_seats': 0, 'human_tables': 0, 'human_seats': 0, 'robot_dist_mean': 12.5, 'robot_dist_max': 18.8, 'human_walk_total': 0.0, 'human_walk_max': None}  マス目の差: []
[OK] p4_relaxed_side: {'name': '⑥ ゆったり型・入口が左の壁', 'seats': 158, 'tables': 38, 'model': 'BellaBot', 'pass_width': 0.8, 'normal_width': 1.0, 'robot_tables': 38, 'robot_seats': 158, 'narrow_tables': 0, 'narrow_seats': 0, 'human_tables': 0, 'human_seats': 0, 'robot_dist_mean': 10.7, 'robot_dist_max': 18.38, 'human_walk_total': 0.0, 'human_walk_max': None}  マス目の差: []
[OK] p5_crammed: {'name': '⑦ ③の列の間の通路を95cmに（卓と席数は③と同じ）', 'seats': 160, 'tables': 42, 'model': 'BellaBot', 'pass_width': 0.8, 'normal_width': 1.0, 'robot_tables': 18, 'robot_seats': 64, 'narrow_tables': 24, 'narrow_seats': 96, 'human_tables': 0, 'human_seats': 0, 'robot_dist_mean': 10.8, 'robot_dist_max': 20.17, 'human_walk_total': 0.0, 'human_walk_max': None}  マス目の差: []
```

#### 確かめの仕組みを確かめた test_famires_v3.py の出力（版 dffc100b269c）

```text
OK  80cmの通路はBellaBotで通れる（マス目0.025・ずらし0.0）
OK  77cmの通路はBellaBotで通れない（マス目0.025・ずらし0.0）
OK  75cmの通路はServiで通れる（マス目0.025・ずらし0.0）
OK  80cmの通路はBellaBotで通れる（マス目0.025・ずらし0.013）
OK  77cmの通路はBellaBotで通れない（マス目0.025・ずらし0.013）
OK  75cmの通路はServiで通れる（マス目0.025・ずらし0.013）
OK  80cmの通路はBellaBotで通れる（マス目0.025・ずらし0.031）
OK  77cmの通路はBellaBotで通れない（マス目0.025・ずらし0.031）
OK  75cmの通路はServiで通れる（マス目0.025・ずらし0.031）
OK  80cmの通路はBellaBotで通れる（マス目0.0125・ずらし0.0）
OK  77cmの通路はBellaBotで通れない（マス目0.0125・ずらし0.0）
OK  75cmの通路はServiで通れる（マス目0.0125・ずらし0.0）
OK  80cmの通路はBellaBotで通れる（マス目0.0125・ずらし0.013）
OK  77cmの通路はBellaBotで通れない（マス目0.0125・ずらし0.013）
OK  75cmの通路はServiで通れる（マス目0.0125・ずらし0.013）
OK  80cmの通路はBellaBotで通れる（マス目0.0125・ずらし0.031）
OK  77cmの通路はBellaBotで通れない（マス目0.0125・ずらし0.031）
OK  75cmの通路はServiで通れる（マス目0.0125・ずらし0.031）
OK  横向きのボックスの左右（ベンチの背）は座る側の候補にしない
OK  縦向きのボックスの上下（ベンチの背）は座る側の候補にしない
OK  店の外にはみ出した卓を見つける
OK  トイレの入口の前の壁を見つける
OK  トイレの壁でへだてた1mの席は違反にしない
OK  壁がなければ、トイレからちょうど1mの席を見つける
OK  卓に食い込んだ壁を見つける
OK  ゆったり型の仕切り（背もたれの上）は違反にしない
OK  座る側の前をふさがれた卓を見つける
OK  出発点がふさがれていたら止める
OK  待合がないのを見つける
OK  ⑦は③と同じ卓の数・種類・席数
OK  L字席（flip=False・mirror=False）の止まってよい辺は、開いた角とソファの端0.6mまで
OK  L字席（flip=False・mirror=True）の止まってよい辺は、開いた角とソファの端0.6mまで
OK  L字席（flip=True・mirror=False）の止まってよい辺は、開いた角とソファの端0.6mまで
OK  L字席（flip=True・mirror=True）の止まってよい辺は、開いた角とソファの端0.6mまで
OK  ⓪T02 の止まる位置は、開いた角か、そこからソファの端に沿って0.6m以内
OK  ⓪の待機場所は、1台ずつ受け渡し口の前まで出られる
OK  2人席（ベンチがbottom）は、ベンチの側とベンチの横を止まる辺にしない
OK  2人席（ベンチがtop）は、ベンチの側とベンチの横を止まる辺にしない
OK  2人席（ベンチがleft）は、ベンチの側とベンチの横を止まる辺にしない
OK  2人席（ベンチがright）は、ベンチの側とベンチの横を止まる辺にしない
OK  直す前の⓪の待機場所（2.2×0.7mに3台）を見つける
OK  待機場所の台数 100 を見つける
OK  待機場所の台数 0 を見つける
OK  待機場所の台数 -1 を見つける
OK  待機場所の台数 '3' を見つける
OK  待機場所の台数 2.5 を見つける
OK  待機場所の台数 True を見つける
OK  待機場所の前をふさぐと、真ん中の台だけ「出られない」を見つける
OK  待機場所の前と両横をふさぐと、3台とも「出られない」を見つける
OK  反例1：レジとレジ内を消すと見つける
OK  反例2：トイレの壁をほぼ全部外すと「切れ目」を見つける
OK  反例3：トイレの入口の前を「トイレの壁」という名前の壁でふさいでも見つける
OK  反例4：家具の真ん中に置いた接合扱いの仕切りを見つける
OK  反例5：待機場所100台を見つける
OK  反例6：⓪の建物の外を消すと、輪郭と合わないのを見つける
OK  反例7：輪郭を2m四方にすると見つける
OK  ⓪の輪郭から欠けを消すと、建物の外と合わないのを見つける
OK  今の店 p0_memory は決まりを守っている
OK  今の店 p1_efficient_corner は決まりを守っている
OK  今の店 p2_efficient_narrow は決まりを守っている
OK  今の店 p3_relaxed_center は決まりを守っている
OK  今の店 p4_relaxed_side は決まりを守っている
OK  今の店 p5_crammed は決まりを守っている
OK  ベンチの背に立つ仕切りは認める
OK  ベンチの背でも0.08mより深い食い込みは認めない
OK  トイレの目隠し：中心の線だけ当たる短い壁では違反にする（4本の線）
OK  トイレの目隠し：4本とも当たる壁なら違反にしない
OK  線分が厚さ2mmの壁を横切るのを見つける
OK  線分の端が壁に触れるだけなら、通ったとみなさない
OK  線分が壁から離れていれば、通ったとみなさない
OK  201番目だけ見通せる止まる位置も見つける
[OK] p2_efficient_narrow: {'name': '④ 効率重視型・狭い店・入口が右の壁', 'seats': 88, 'tables': 28, 'model': 'BellaBot', 'pass_width': 0.8, 'normal_width': 1.0, 'robot_tables': 28, 'robot_seats': 88, 'narrow_tables': 0, 'narrow_seats': 0, 'human_tables': 0, 'human_seats': 0, 'robot_dist_mean': 8.5, 'robot_dist_max': 13.92, 'human_walk_total': 0.0, 'human_walk_max': None}  マス目の差: []
OK  成功したときは、layout・analysis・summary に同じ版の番号が入る
[NG] p2_efficient_narrow: ④ 効率重視型・狭い店・入口が右の壁
   - 入口まわり: レジがない

違反があるので、/tmp/tmpq_0c7kz3 には何も書いていない（前の版のまま）
OK  違反があると止まり、出力先のファイルは前の版のまま（作業用のフォルダも残らない）
[OK] p2_efficient_narrow: {'name': '④ 効率重視型・狭い店・入口が右の壁', 'seats': 88, 'tables': 28, 'model': 'BellaBot', 'pass_width': 0.8, 'normal_width': 1.0, 'robot_tables': 28, 'robot_seats': 88, 'narrow_tables': 0, 'narrow_seats': 0, 'human_tables': 0, 'human_seats': 0, 'robot_dist_mean': 8.5, 'robot_dist_max': 13.92, 'human_walk_total': 0.0, 'human_walk_max': None}  マス目の差: []

出力先へ入れ替える途中で失敗したので、/tmp/tmpq_0c7kz3 を前の版に戻した
OK  入れ替えの途中で失敗すると、出力先は前の版に戻る（作業用のフォルダも残らない）
OK  反例A：トイレの壁の1cmの切れ目を見つける
OK  反例B：トイレの入口の内側の1cmのふさぎを見つける
OK  反例C：トイレの入口の前の奥行き0.1mを見つける
OK  反例D：輪郭の幅1cmの切れ込み（建物の外なし）を見つける
OK  輪郭に斜めの辺があれば止める
OK  出入り口Aを壁でふさぐと見つける
OK  p1：細い通路は3本で、幅はどれも1.2m
OK  p1：卓の数・止まる位置・距離が analysis と同じ
OK  p1：細い通路を通る卓は、止まる位置がその通路の区画の中
OK  p1：細い通路の入口は、受け渡し口の前から行ける端
OK  p1：全部の卓に部品（天板・座る位置）があり、座る位置の数が席数と同じ
OK  p1：場所の点がそろっている
OK  p1：スタッフが待つ点・並ぶ点・立つ点は、障害物から0.2m以上離れ、細い通路に入らない
OK  p1：席に着く点は障害物から0.2m以上離れ、どの卓にも1つ以上ある
OK  p1：レジ内は通れる部屋（スタッフだけ）、ほかの部屋は通れない箱
OK  p1：受け渡し口から全卓・卓から卓の全組に道順がある
OK  p1：ふだんの道か狭い道かは、試算の卓の分け方と同じ（robot→normal、narrow→narrow）
OK  p1：道順は受け渡し口の前から始まり、止まる位置で終わる
OK  p1：道順のどの区間も、その幅で通れるマス目だけを通る
OK  p1：会計に立つ点・並ぶ点は、ロボットの道から0.75m以上
OK  p1：会計の列が1つあり、ロボットは通れず、人は通れる
OK  p1：会計に立つ点・並ぶ点は会計の列の中
OK  p5：細い通路は3本で、幅はどれも0.95m
OK  p5：卓の数・止まる位置・距離が analysis と同じ
OK  p5：細い通路を通る卓は、止まる位置がその通路の区画の中
OK  p5：細い通路の入口は、受け渡し口の前から行ける端
OK  p5：全部の卓に部品（天板・座る位置）があり、座る位置の数が席数と同じ
OK  p5：場所の点がそろっている
OK  p5：スタッフが待つ点・並ぶ点・立つ点は、障害物から0.2m以上離れ、細い通路に入らない
OK  p5：席に着く点は障害物から0.2m以上離れ、どの卓にも1つ以上ある
OK  p5：レジ内は通れる部屋（スタッフだけ）、ほかの部屋は通れない箱
OK  p5：受け渡し口から全卓・卓から卓の全組に道順がある
OK  p5：ふだんの道か狭い道かは、試算の卓の分け方と同じ（robot→normal、narrow→narrow）
OK  p5：道順は受け渡し口の前から始まり、止まる位置で終わる
OK  p5：道順のどの区間も、その幅で通れるマス目だけを通る
OK  p5：会計に立つ点・並ぶ点は、ロボットの道から0.75m以上
OK  p5：会計の列が1つあり、ロボットは通れず、人は通れる
OK  p5：会計に立つ点・並ぶ点は会計の列の中
OK  ②：全部の卓に部品があり、座る位置の数が席数と同じ
OK  ②：角テーブル・丸テーブルの椅子は2脚ずつ向かい合わせ（向かい合う2辺に2脚ずつ）
OK  ②：椅子とスツールは卓の外形の内側
OK  ②：椅子を置く辺には、どれも席に着く点がある
OK  ②：ロボットが止まる辺に椅子があるのは、その向きの組では座れない卓だけ
OK  p1：地図を読み戻すと、マス目の数が同じ
OK  p1：地図を2回作ると同じ文字列（毎回同じ）
OK  p1：障害物までの距離は、計算の値と0.5mm以内
OK  p1：試算でふだんの道が通れるマスは、地図でも2（待機場所を床にした分だけ増える）
OK  p1：会計の列のマスは、地図では通れない
OK  p1：地図の上でも、ふだんの道で行ける卓は試算の robot の卓と同じ、狭い道でだけ行ける卓は narrow の卓と同じ
OK  p1：どの待機場所の真ん中にも、受け渡し口の前から地図の上で行ける（通れる幅の道）
OK  p5：地図を読み戻すと、マス目の数が同じ
OK  p5：地図を2回作ると同じ文字列（毎回同じ）
OK  p5：障害物までの距離は、計算の値と0.5mm以内
OK  p5：試算でふだんの道が通れるマスは、地図でも2（待機場所を床にした分だけ増える）
OK  p5：会計の列のマスは、地図では通れない
OK  p5：地図の上でも、ふだんの道で行ける卓は試算の robot の卓と同じ、狭い道でだけ行ける卓は narrow の卓と同じ
OK  p5：どの待機場所の真ん中にも、受け渡し口の前から地図の上で行ける（通れる幅の道）
OK  p0：地図を読み戻すと、マス目の数が同じ
OK  p0：地図を2回作ると同じ文字列（毎回同じ）
OK  p0：障害物までの距離は、計算の値と0.5mm以内
OK  p0：試算でふだんの道が通れるマスは、地図でも2（待機場所を床にした分だけ増える）
OK  p0：会計の列のマスは、地図では通れない
OK  p0：地図の上でも、ふだんの道で行ける卓は試算の robot の卓と同じ、狭い道でだけ行ける卓は narrow の卓と同じ
OK  p0：どの待機場所の真ん中にも、受け渡し口の前から地図の上で行ける（通れる幅の道）
OK  会計の列がないと、②は会計に立つ点の近くをロボットが通り、確かめに引っかかる
OK  ボックス席の列は、すき間なく並んだものだけをまとめる

すべて OK
```

### 前の版と比べ、版の番号と説明文のほかは変わっていないことを確かめたスクリプト check_gen_only.py

```python
"""前の版と新しい版の店の形（public/sim/layouts）を比べ、版の番号（generation）を除いて何が変わったかを出す（2026-10-29）。
使い方: python3 check_gen_only.py <前の layouts のフォルダ> <新しい layouts のフォルダ>"""
import json, glob, os, sys
B, A = sys.argv[1], sys.argv[2]
def strip(o):
    if isinstance(o, dict): return {k: strip(v) for k, v in o.items() if k != "generation"}
    if isinstance(o, list): return [strip(v) for v in o]
    return o
print("generation", json.load(open(B + "/summary.json"))[0]["generation"], "->", json.load(open(A + "/summary.json"))[0]["generation"])
for f in sorted(glob.glob(B + "/**/*.json", recursive=True)):
    rel = os.path.relpath(f, B); a = strip(json.load(open(f))); b = strip(json.load(open(os.path.join(A, rel))))
    if a == b:
        print("同じ（版の番号だけ）", rel); continue
    if isinstance(a, dict):
        ks = [k for k in a if a.get(k) != b.get(k)]
        line = f"違う {rel}: {ks}"
        if "meta" in ks: line += f"  meta の中: {[k for k in a['meta'] if a['meta'][k] != b['meta'].get(k)]}"
        if "tables" in ks and isinstance(a["tables"], list):
            ta = {t.get("id", i): t for i, t in enumerate(a["tables"])}; tb = {t.get("id", i): t for i, t in enumerate(b["tables"])}
            line += f"  卓: {[i for i in ta if ta[i] != tb.get(i)]}"
        print(line)
    else:
        print("違う", rel, "(list)", [i for i, (x, y) in enumerate(zip(a, b)) if x != y])
```

#### check_gen_only.py の出力（2e9fc773050a → dffc100b269c）

```text
generation 2e9fc773050a -> dffc100b269c
違う p0_memory.json: ['meta']  meta の中: ['furniture_types']
違う p0_memory_analysis.json: ['meta']  meta の中: ['furniture_types']
違う p1_efficient_corner.json: ['meta']  meta の中: ['furniture_types']
違う p1_efficient_corner_analysis.json: ['meta']  meta の中: ['furniture_types']
違う p2_efficient_narrow.json: ['meta']  meta の中: ['furniture_types']
違う p2_efficient_narrow_analysis.json: ['meta']  meta の中: ['furniture_types']
違う p3_relaxed_center.json: ['meta']  meta の中: ['furniture_types']
違う p3_relaxed_center_analysis.json: ['meta']  meta の中: ['furniture_types']
違う p4_relaxed_side.json: ['meta']  meta の中: ['furniture_types']
違う p4_relaxed_side_analysis.json: ['meta']  meta の中: ['furniture_types']
違う p5_crammed.json: ['meta']  meta の中: ['furniture_types']
違う p5_crammed_analysis.json: ['meta']  meta の中: ['furniture_types']
同じ（版の番号だけ） summary.json
違う unity/p0_memory.json: ['meta', 'tables']  meta の中: ['rules']  卓: ['T03', 'T04', 'T05', 'T06', 'T07', 'T08', 'T11', 'T12', 'T13', 'T14', 'T15', 'T16', 'T17', 'T19']
同じ（版の番号だけ） unity/p0_memory_map.json
違う unity/p1_efficient_corner.json: ['meta']  meta の中: ['rules']
同じ（版の番号だけ） unity/p1_efficient_corner_map.json
違う unity/p2_efficient_narrow.json: ['meta']  meta の中: ['rules']
同じ（版の番号だけ） unity/p2_efficient_narrow_map.json
違う unity/p3_relaxed_center.json: ['meta']  meta の中: ['rules']
同じ（版の番号だけ） unity/p3_relaxed_center_map.json
違う unity/p4_relaxed_side.json: ['meta']  meta の中: ['rules']
同じ（版の番号だけ） unity/p4_relaxed_side_map.json
違う unity/p5_crammed.json: ['meta']  meta の中: ['rules']
同じ（版の番号だけ） unity/p5_crammed_map.json
```

### 店の形の README.md に足した行（椅子の決まり）

```diff
diff --git a/tools/sim_layouts/README.md b/tools/sim_layouts/README.md
index ecb0db7..81ddaea 100644
--- a/tools/sim_layouts/README.md
+++ b/tools/sim_layouts/README.md
@@ -34,7 +34,10 @@
 - ロボットの道順（`routes`）：受け渡し口の前→各卓の止まる位置（`from_pass`）と、卓→卓（`between`。"T01|T02" は T01 から T02、逆向きは点を逆にたどる）。ふだん走らせる幅の道で行けるならその道、行けなければ通れる幅の道（試算と同じ規則。`use` が normal か narrow。試算の卓の分け方と一致することをテストで確かめる）。マス目の最短の道を、通れる範囲でまっすぐにつないだ曲がり角の点の並び。2026-10-22 から Unity のロボットはこの点を順にたどっていたが、2026-10-24 から下の地図の上で自分で道を引く形に変える（線に縛ると、行きと帰りが同じ線になり、ロボットどうしが正面から出会って回り込めなかったため）。道順は、回り込みで延びた距離を測る物差しと、前の動き方に戻す切り替えのために残す
 - ロボットの地図（`unity/{名前}_map.json`。2026-10-24）：試算が卓までの距離を測るのと同じ2.5cmのマス目で、マスごとに「ふだんの道（1.0m）が通れる＝2／通れる幅（0.8m）の道だけ通れる＝1／通れない＝0」（`free_class`）と、いちばん近い障害物までの距離（`clear_mm`）を入れたもの。分け方は試算と同じ式（`Grid.free`）。会計の列は通れない。待機場所は床として入れる（止まっているロボットは Unity で動くものとして扱う。待機場所の真ん中は壁から0.4m前後なので1のマス）。Unity のロボットはこの上で自分で道を引く（行き先までふだんの道で行けるならその道だけ、行けなければ狭い道も使う。試算と同じ規則）。地図だけで試算の卓の分け方（robot・narrow）が再現できることをテストで確かめる。中身は gzip で縮めた base64（読み方は `unity_export.unpack_map`）
 - 会計の列（`robot_keepout`）：ロボットの道にしない矩形。人は通れるので、Unity では部屋や壁として建てない（道順はこれをよけて作ってある）
-- まだないもの：② の4人席・丸テーブル・6人の長テーブルの椅子と座る位置（parts が null）、人がロボットをよける逃げ場（refuges）
+- ②の4人の角テーブル・丸テーブル（2026-10-29 エイイチの記憶）：椅子は2脚ずつ向かい合わせ。椅子を置く2辺は、ロボットが止まる辺を含まない組（ロボットは天板の端に横付け）。その組の片方に席に着く点がない（壁ぎわで座れない）ときだけ、もう一方の組にする（下の壁ぎわの T14・T16・T17・T19 は、止まる辺の横に椅子が来る）。椅子は半径0.2m・外形の内側で、外へ引ける。丸テーブルの天板は直径0.8m（`top` は外接する正方形、`top_shape: "circle"`）
+- ②の6人の長テーブル：天板3.2m×0.7m、上下にスツール3つずつ（半径0.22m・図と同じ位置）。スツールは引かない（`pullable: false`・`stool: true`）
+- 卓の数・止まる位置・距離は変わらない（椅子は外形の内側に置くだけ）。版 2e9fc773050a → dffc100b269c（②の部品と説明が増えただけで、6店とも数字は同じ。サイトの試算は計算し直していない）
+- まだないもの：人がロボットをよける逃げ場（refuges）
 
 ## 動かし方
 
```

### ②を Unity で回す条件：スタッフ2人・1時間に19組・ロボット0・1・2台

Unity で回す条件は、ほかの店と同じ決め方にしました。スタッフは選べる人数（1・2・3人）の真ん中の2人、混み具合は普通の1時間19組、ロボット0・1・2台、上げ膳だけ、1往復で3卓、レジ1つです。Unity が読む条件のファイル（`serving-robot-params.json`）の `export_params.py` に②を足し、条件は15件から18件になりました。前の15件と共通の値は変わっていません。試算での②の入店待ちは、0台2.68分・1台2.44分・2台1.60分で、小さい店で余裕があり、ロボットの効きは小さい店です。

サイトへの反映は p2m-site の commit b0f1b0c（31ファイル）です。公開後、`https://pixelstomotors.com/sim/serving-robot-params.json` の版の番号が dffc100b269c・条件18件になったことを確かめました。


## 作業ログ ― Unity に②を建て、1回ずつ回した（依頼23）

### Claude Code と依頼箱で、Mac の Unity を動かしている

[Claude Code](https://www.anthropic.com/claude-code) は、Anthropic の AI（Claude）が、パソコンの中でコードを読み書きし、コマンドを動かす道具です。このプロジェクトでは、Unity の店のコードを書いて回すのは Mac の Claude Code の役目で、設計とサイトの試算はこの会話の Claude が受け持っています。

その間の受け渡しが「依頼箱」です。依頼の文（Markdown）を iCloud の `依頼箱/新規/` に置くと、Mac の見張り係が Claude Code を起動して依頼を実行し、`依頼箱/結果/` に報告を書き戻します。終わると Mac で音が鳴ります。依頼の文には、始める前に確かめること（Unity が閉じているか・外付けの SSD がつながっているか・台帳が退避と同じか）と、違ったら手を止めて報告することを毎回書きます。台帳（回の記録の CSV）は、依頼の前に Claude が KIOXIA の archive に写して退避しています（631行・md5 41c8ceff63036168a9d2940fb1e8c4ba）。

### 依頼文：②を建てて確かめる（20261029_23）

```markdown
---
作業フォルダ: /Users/shimazueiichi/Robotics_UX/ServiceSim
上限時間: 180
---
# 依頼：② 定番の郊外型（fam_p0・記憶の店）を Unity に建て、1回ずつ回して確かめる（2026-10-29）

エイイチの決定：⑥はここで区切り（LOG398）。④⑤⑥ → ② の順の最後、②へ進む。今回は②だけ。

サイト（正）はもう直した（p2m-site commit b0f1b0c。店の形の版 2e9fc773050a → dffc100b269c）。
- ②の角テーブル（t4）・丸テーブル（r4）・6人の長テーブル（long6）の椅子と座る位置を作った。前は `parts` が null で、客が座れなかった
  - t4・r4：椅子は2脚ずつ向かい合わせ（エイイチの記憶）。椅子を置く2辺（`parts.chair_sides`）は、ロボットが止まる辺を含まない組。下の壁ぎわの T14・T16・T17・T19 だけは壁側に座れないので、止まる辺の横に椅子が来る。椅子は半径0.2m・外形の内側・外へ引ける（`pullable: true`・`pull_dir`）
  - r4 の天板は直径0.8mの丸（`top` は外接する正方形、`top_shape: "circle"`）
  - long6：天板3.2m×0.7m、上下にスツール3つずつ（半径0.22m）。スツールは引かない（`pullable: false`・`pull_dir: null`・`stool: true`）
  - `benches` は空
- 卓の数・止まる位置・距離・道順・地図は6店とも変わっていない。③④⑤⑥⑦は版の番号と meta の説明文（rules・furniture_types）だけが変わった
- `public/sim/serving-robot-params.json`：Unity で回す店に fam_p0 を足した。unity_conditions 15件 → 18件。前の15件・common・unity_rules は前と同じ。meta.layout_generation は dffc100b269c
- ②の3条件：スタッフ2人・19組/時・ロボット0・1・2台・上げ膳・1往復3卓（0台は trays 1）・レジ1つ。19卓・88席
- 試算では、②の入店待ちは0台 2.7・1台 2.4・2台 1.6分、会計待ちは3条件とも1.3分前後。小さい店で余裕があり、ロボットの効きは小さい
- 図面で分かっていて、直さずに残したこと（Unity で見る。これだけで手を止めなくてよい）
  - 仕切り壁（y 8.6〜9.0）の右端とパントリーの壁の間が1.5m（x 8.0〜9.5）。奥の8卓（T01〜T08・36席）へ行くロボットと、トイレへ行く客が全部ここを通る。ロボット2台が同時にすれ違うには1.6m要る
  - 待機場所（x 12.2〜14.6・y 5.1〜5.9）が受け渡し口の点（10.9, 5.45）から1.3m（③⑦④⑥と同じ形）
  - 受け渡し口は上（パントリーの上の端）にもあるが、ロボットとスタッフの出発点は下だけ（今までの店と同じ扱い）
- 台帳の退避は Claude が済ませた：`/Volumes/KIOXIA/r2r2r-data/service_sim/unity/archive/unity_ledger_v1_pre_p0check_20261029/unity_ledger_v1.csv`（631行・md5 41c8ceff63036168a9d2940fb1e8c4ba）

## 始める前に確かめること（違えば手を止めて報告）

1. Unity エディタが起動していない（起動していたら閉じずに報告して終わる）
2. /Volumes/KIOXIA がマウントされている。鍵ファイル unity_ledger_v1.lock がない
3. 台帳の md5 が上の退避と同じ
4. ServiceSim の保留が 0
5. https://pixelstomotors.com/sim/serving-robot-params.json の meta.layout_generation が dffc100b269c、unity_conditions が18件（違えば数分おきに取り直す。30分たっても違えば報告して終わる）

## やること

1. サイトの params と、②③④⑤⑥⑦の店の形（`public/sim/layouts/unity/` の p0・p1・p2・p3・p4・p5 の `.json` と `_map.json`）を、今までと同じやり方でプロジェクトに写す（手で値を写さない）。generation が dffc100b269c でそろっているか確かめる。③④⑤⑥⑦は、前の写しと版の番号・meta の説明文以外が同じであることを確かめる
2. ②を今までの店と同じコード・同じ規則で建てる（地図の上で自分で道を引く動き方・すれ違い入・待機場所へ戻る 入・案B 切・店員優先のよけ方・逃がし弁・モニター、すべて今の標準のまま）
   - 卓の部品は JSON の `parts` から建てる。今のコードが t4・r4・long6 を知らない場合は、`parts` の読み方を店に関係なく使える形に広げてよい（`top_shape: "circle"` は丸い天板、`stool: true` は背のないスツール、`pullable: false` は引かない）。②のためだけの手直しはしない
   - ②の店の形のせいで建てられない・回らないところ（届かない卓、待機場所・レジ・並ぶ点が置けない、NavMesh の切れ目、建物の輪郭がL字で外壁が切れるなど）があっても、Unity 側で形を直さない。場所と理由を「決めてほしいこと」に書く（直すならサイトが先）
3. make_queue.py で `--stores fam_p0` が使えることを確かめる。**指定しないときは今までどおり ③⑦の60回**。judge_night.py は変えない（②は基準データがないので「基準なし」になってよい）
4. check-in して、画面なしの実行ファイルを作り直す（保留 0）
5. 確かめの3回を回す：② × ロボット0・1・2台 × 種0、今の標準のまま。ラベル `p0check`。同時に回す本数は4のまま
   - 台帳には3行が足される（追記だけ）。終わったら行数（631 → 634 のはず）と、先頭631行の md5 が退避と同じかを確かめる
6. make_queue の dry-run で、何も指定しないとき③⑦の60回のままであることを確かめる（台帳に書かない）
7. 作業フォルダに queue の一時ファイルを残さない

## 変えないもの

- 店の回し方・人とロボットの動き・速さ・Stiffness などの物理の設定・同時に回す本数（N=4）
- 台帳の列（59列）と今までの行。今までの night/ と出力の記録
- 本番の夜は回さない（②の夜は、確かめの結果をエイイチが見てから決める）

## 報告

依頼箱の結果に加えて、claude_code_reports に 20261029_HHMM_p0_build_check.txt として書く（場所：~/Library/Mobile Documents/com~apple~CloudDocs/デスクトップ/ADAPT DESIGN/じぶんの/PixelstoMotors/デジタルツイン学習R2R2R/サービスロボット導入シミュレーション/unity/claude_code_reports/）。

- 始める前の確かめ5つの結果
- 入れた cs 番号・build_id と保留の有無・変えたファイル（卓の部品の読み方を広げたなら、何をどう広げたか）
- ②を建てて分かったこと（卓の数19・椅子とスツールと座る位置が全卓に建ったか・止まる位置・待機場所・レジ・スタッフが待つ点・並ぶ点（レジとドリンクバー）・トイレの入口が置けたか、置けなかった所）
- 3回それぞれ：最後まで回ったか・全員帰ったか・実時間・入れた組の数・入店待ち・そのうち席は空いているのに待った時間・料理の待ち・会計待ち・ロボットが運んだ皿の割合・往復の数・30秒以上の止まり（1往復あたり）・動けなくなった（60秒）・卓を空けた・瞬間移動・打ち切り。試算の同じ条件の値（params の site_result）と並べる。差の理由の調べはしなくてよい
- 2台の回の30秒以上の止まりの場所と理由：受け渡し口の点から 2.5 m 以内の数（待機場所での止まりを除いた数も）／仕切りの右端のすき間のまわり（x 7.5〜9.5・y 8.0〜9.6）の数／奥の区画（x が 9.5 m より左で、y が 9.0 m より上）の数／ドリンクバーのまわり（x 13.0〜21.5・y 2.6〜4.5）の数／入口・レジのまわり（x 9.0〜14.0・y が 3.8 m より下）の数
- 仕切りの右端のすき間（x 8.0〜9.5・y 8.6〜9.0）で、ロボットどうし・ロボットと人が向かい合って待った回数（分かる範囲でよい）
- 台帳の行数と先頭631行の md5
- dry-run で③⑦が60回のままか
- **エイイチが画面で②を見る手順**（Unity を開いてから、どのシーン・メニューで②の、どの条件を流せるか。短く）
- 決めてほしいこと（なければ「なし」）
```

### Unity 側で足したのは、丸い天板とスツールを読むための2つの項目だった

作業中、Unity の変更を見る画面（Unity Version Control の差分）が開きました。Claude Code が `StorePlan.cs` に足したのは、椅子が背のないスツールかどうか（`stool`）と、天板が丸いかどうか（`tableRound`）の2つの項目です。依頼で「`parts` の読み方を店に関係なく使える形に広げてよい」とした範囲で、ほかの店の作りや回し方には触れていません。

【画像】LOG402_02_unity_storeplan_diff.png Unity Version Control の差分の画面。StorePlan.cs に、背のないスツールかを表す stool と、天板が丸いかを表す tableRound の2つの項目が足されている

### 報告：20261029_1732_p0_build_check.txt

```text
====================================================================
② 定番の郊外型（fam_p0・記憶の店）を建てて、1回ずつ回して確かめた
依頼：20261029_23_店2を建てて確かめる.md
2026-10-29 17:32　check-in：cs:39　build_id cs39_20261029_1717（保留 0）
====================================================================

結論

  ・始める前の確かめ5つは、すべて合格だった。
  ・公開版（版 dffc100b269c）の params と ②③④⑤⑥⑦の店の形を写した。版はすべてそろっていた。
    ③④⑤⑥⑦は前の写しと「版の番号と meta.rules（説明文）」以外同じ。params は fam_p0 と条件3件（15〜17 番）が足されただけ。
  ・②は今までと同じコードで建った。ただし、今のコードが知らなかったもの（t4・r4・long6、丸い天板、スツール、
    新しい裏の部屋の名前）を読めるように、読み方を店に関係なく広げた（3 章）。②のためだけの手直しはしていない。
  ・卓 19・席 88 が JSON・summary.json と一致。合わないもの なし。確かめ A も全卓・待機場所3つとも道が引けた。
  ・確かめの3回（② × 0・1・2台 × 種0）は3回とも completed・全員帰った。打ち切りは 2台の回で 1。
  ・2台の回の 30 秒以上の止まり 17 のうち 9 が奥の区画（うち 8 が丸テーブル T05・T06 のあいだ）、7 が待機場所1の中。
    仕切りの右端のすき間では 30 秒以上の止まりは 0。
  ・台帳 631 → 634 行（追記だけ）。先頭 631 行の md5 は退避と同じ。
  ・何も指定しない make_queue は③⑦の60回のまま。


====================================================================
1. 始める前の確かめ（5つとも合格。17:00 ごろ）
====================================================================

  1. Unity エディタ：起動していない（Unity Hub だけが起動していた）
  2. /Volumes/KIOXIA：マウントされている。unity_ledger_v1.lock：なし
  3. 台帳 unity_ledger_v1.csv：631 行・md5 41c8ceff63036168a9d2940fb1e8c4ba（退避と同じ）
  4. ServiceSim の保留：0（cs:38 head）
  5. 公開中の serving-robot-params.json：meta.layout_generation dffc100b269c・unity_conditions 18 件（1回目の取得で合った）


====================================================================
2. 写したもの（やること 1）
====================================================================

  写し元：https://pixelstomotors.com/sim/（2026-10-29 17:05 に curl で取得）
    控え：unity/site_copy_dffc100b269c/（params・summary.json・unity/ の6店の JSON と地図・README.txt）
  版の番号：params の layout_generation、6店の JSON と地図の meta.generation、summary.json がすべて dffc100b269c
  プロジェクトの前の写し（cs:38）との違い
    p1・p5・p2・p3・p4 の JSON：meta.generation と meta.rules（説明文）だけ違う。それ以外の違い 0
      （meta.furniture_types はこの5店の JSON には無く、違いも無い）
    p1・p5・p2・p3・p4 の地図：meta.generation だけ違う
    summary.json：6店の generation だけ違う
    params：meta.layout_generation・stores.fam_p0・unity_conditions の 15〜17 番が足されただけ。
            前の 0〜14 番・common・unity_rules は同じ
  どれも cp でそのまま写した（手で値を写していない）。p0 の JSON と地図は新しく足した。


====================================================================
3. 入れた cs・build_id・変えたファイル
====================================================================

  check-in：cs:39（保留 0。回したあとも 0）
  画面なしの実行ファイル：build_id cs39_20261029_1717 / unity_cs ServiceSim/cs:39 / pending_changes 空
                         Build Finished, Result: Success・error CS 0

  変えたファイル（すべて cs:39）
    足した
      Assets/ServiceSim/Store/Layouts/p0_memory.json・p0_memory_map.json（＋.meta）   公開版の写し
      Assets/ServiceSim/Store/StoreLayout_p0_memory.asset（＋.meta）   ⑥の .asset を写し、JSON・地図・名前・写し元を差し替えた
    写し直した
      Assets/ServiceSim/Experiment/serving-robot-params.json
      Assets/ServiceSim/Store/Layouts/summary.json・p1/p2/p3/p4/p5 の JSON と地図
    ②を足した（⑥を足したときと同じ形。名前と番号の差し替えだけ）
      Editor/ServiceSimSetup.cs       P0LayoutPath・HeadlessRun.layouts に②
      Editor/ServiceSimSiteRun.cs     ②の3条件（unity_conditions の 15・16・17）
      Editor/ServiceSimJsonStore.cs   「② p0_memory を建てて確かめる」・版と試算の値の確かめに②
      Editor/ServiceSimMapPlanner.cs  「② 確かめ A」
      Scenes/ServiceSim_Family.unity  HeadlessRun.layouts に②（1行）
    読み方を広げた（店に関係なく使える形）
      Store/JsonStoreLayout.cs
        ・卓の種類：t4・r4 → 島の卓（IslandTable）、long6 → 大人数席（LargeTable）。
          種類の名前を当てるだけで、形は今までどおり parts（top・benches・chairs・seat_points）から建てる
        ・parts.top_shape："circle" なら丸い天板（無い・"rect" なら今までどおり四角。ほかの値は建てずに止める）
        ・chairs[].stool：true ならスツール。pullable:false・pull_dir:null はもともと読めていた（引かない・向き 0）
        ・部屋：知らないラベルでも kind が "back" で walkable でなければ、裏の通れない部屋（事務所）として箱にする。
          ②の「こおり」「冷凍庫」「保存庫」「社員トイレ」「更衣室」「冷蔵庫」「物置」がこれに当たる。
          キッチンのモニターの置き場所がずれないよう、キッチン（Kitchen）にはしない
      Store/StorePlan.cs     PlanSeat.tableRound・PlanBox.round・PlanChair.stool を足した
      Store/StoreBuilder.cs  丸い天板は、同じ四角に内接する円柱にする（見た目も当たりも丸。BoxCollider を外して凸の MeshCollider）。
                             スツールは名前を Stool にする（今の椅子も背のない箱なので、形は椅子と同じ）
    今までの店（③④⑤⑥⑦）には丸い天板・スツール・知らない部屋が無いので、建つものは変わらない。

  手で戻したもの（check-in していない）
    建てて確かめる処理で ProjectSettings/NavMeshAreas.asset と Mat_RobotKeepout.mat が変更ありになったので cm undo で戻した（④⑤⑥と同じ）。

  make_queue.py・night_runner.py・judge_night.py は変えていない。
  .asset の細い通路の幅は⑥の写しのまま 1.5 m（②は細い通路 0 本なので JSON からは合わせない。使われない値）。


====================================================================
4. ②を建てて分かったこと（JSON Store「② を建てて確かめる」・Map Planner「② 確かめ A」）
====================================================================

  数         卓：Unity 19 / JSON 19 / summary.json 19 で一致。席 88 で一致。細い通路 0 本。外寸 24 × 19.2 m
             地図のマスの数は JSON の counts と一致。合わないもの：なし
  建物の輪郭  L字（左上が欠ける）。床 2 枚・外壁 7 本を JSON のまま建てた。外壁の切れ目はない
             （焼いた NavMesh は、ロボット用・人用とも「つながっていない面」0 m2）
  卓の部品    椅子 52 脚（t4 11 卓・r4 2 卓 × 4 脚）＋スツール 6 つ（long6）＝ 58（Unity の数え方は「椅子」）。ほかに booth6L 5 卓のベンチ。
             座る位置 88 / 88（全卓）。席に着く点 57。丸い天板 2（T05・T06）
  止まる位置  19 か所すべてロボット用の NavMesh の上（乗らない 0）。地図でも 19 卓すべて通れるマス
  道順       受け渡し口から全 19 卓、すべての区間がつながった。JSON の dist との差は平均 −0.27 m・最大 0.59 m（T01）。
             30% を超えた卓 0。狭い道を使う卓 0
  席         入口 (11.0, 0.5) から全 19 卓の席に着く点まで歩ける（入れない卓 0）
  場所の点    25 か所すべて NavMesh に乗った（乗らない 0）。置けなかった所はない
               受け渡し口・返却口・パントリー (10.9, 5.45)／入口 (11.0, 0.5)／待合の前 (13.3, 0.9)／トイレの入口の前 (8.75, 16.4)
               レジ 1 (11.05, 1.8)・レジに並ぶ点 3 (11.05, 1.3 / 0.8 / 0.3)・レジの内側 (11.05, 3.3)
                 レジの内側は人用・ロボット用とも受け渡し口から 2.16 m で行ける
               ドリンクバー（立つ点 1：(19.0, 3.55)／並ぶ点 3：(19.9 / 20.4 / 20.9, 3.55)）
               ロボットの待機場所 3：(12.6, 5.5)・(13.4, 5.5)・(14.2, 5.5)。地図では3つとも「ふだんの道」のマス
               スタッフが待つ点 6：x 9.25・y 6.31〜9.39（スタッフ2人）
  確かめ A   引けない卓 0 / 19。待機場所3つとも道が引けた。長さの比 最小 0.979 / 平均 1.017 / 最大 1.047

  気づいたこと（直していない。調べてもいない）
    ・席の確かめ（通る半径 0.25 m）で T19 の右の席に着く点 (23.7, 1.0) が NavMesh に乗らない（右の外壁まで 0.3 m）。
      人用（半径 0.2 m）の「席に入れない卓」は 0 で、回でも T19 に座れなかった記録はない
    ・レジの内側：南北の歩ける幅 0.52 m で、確かめが「入口が 0.7 m 未満」と出す（レジ内の奥行き 0.8 m）。
      回でレジの内側に入れなかった人は 0（register_back_intruders 0）。会計の位置がずれた回は 1台 1・2台 1
  書き出し（unity/screens/）
    20261029_p0_memory_json_check.txt / _table_dist.csv
    20261029_1712 ごろの map_planner_checkA_p0.txt


====================================================================
5. 確かめの3回（② × 0・1・2台 × 種0・すれ違い入・待機場所へ戻る入・案B切・ラベル p0check・同時 4 本）
====================================================================

  python3 tools/make_queue.py --stores fam_p0 --seeds 0 --label p0check --out /tmp/p0c/queue_p0check.json
  python3 tools/night_runner.py --queue /tmp/p0c/queue_p0check.json --parallel 4 --night 20261029
      --label p0check --record-name 20261029_p0check
  出力 20261029_p0check_cs39_fam_p0_r{0,1,2}_s0_passon_sbret
  記録 night/20261029_p0check/（runner 終了コード 0・completed 3・失敗 0）
  judge.md：基準なし 3（②の基準データがないため。依頼のとおり）

  左が Unity、右が試算（params の site_result）。単位は分。割合は 0〜1
                                   0台                 1台                 2台
  最後まで回ったか                 completed           completed           completed
  全員帰ったか                     はい                はい                はい
  実時間                           2.4 分              2.5 分              2.5 分
  （参考）店の時間                 164.1 分            163.7 分            164.0 分
  入れた組の数                     31 / 37.4           31 / 38.7           31 / 37.5
  入店待ち                         1.33 / 2.68         1.21 / 2.44         1.45 / 1.60
   うち席は空いているのに待った     0 / 1.13            0 / 0.56            0 / 0.35
  料理の待ち                       0.68 / 0.60         0.95 / 0.94         0.94 / 0.40
  会計待ち                         0.80 / 1.31         0.72 / 1.30         1.16 / 1.25
  ロボットが運んだ皿の割合         0 / 0               0.987 / 0.979       0.974 / 1.000
  往復の数                         0                   63                  73
  30秒以上の止まり                 0                   1                   17
   （1往復あたり）                 0                   0.016               0.233
  動けなくなった（60秒）           0                   0                   12
  卓を空けた（逃がし弁）           0                   0                   0
  瞬間移動                         3                   8                   15
  打ち切り                         0                   0                   1
  （参考）あきらめた               3                   4                   12
  （参考）冷めた皿の割合           0 / 0.0003          0.026 / 0.009       0.065 / 0
  （参考）待機場所へ戻った／出た   0 / 0               63 / 63             72 / 72（戻れず受け渡し口へ 0）
  （参考）ドリンクバーで並んだ／あきらめた  52 / 2     56 / 4              51 / 4
  ※ 0台の瞬間移動 3 はロボットのいない回なので、人の側のもの

  目立つ点（差の理由は調べていない。依頼のとおり）
    ・入れた組の数が3回とも 31 組で、試算（37〜39 組）より少ない（⑤⑥と同じ傾向）
    ・2台の回は料理の待ち 0.94 分（試算 0.40）、30 秒以上の止まり 17・動けなくなった 12 で、1台の回より悪い
    ・1台の回の 30 秒以上の止まりは 1 だけ（T06 の椅子の前・30.4 秒・回り込んで動き出した）


====================================================================
6. 2台の回の 30 秒以上の止まり（17 回）の場所と理由
====================================================================

  受け渡し口の点 (10.9, 5.45) から 2.5 m 以内              7 回（すべて「もう1台のロボット」）
   うち待機場所での止まりを除いた数                        0 回
     （7 回とも待機場所1の四角（x 12.2〜13.0・y 5.1〜5.9）の中、(12.27〜12.39, 5.41〜5.51)。
      うち 4 回が 60 秒の「動けなくなった」、2 回は「よける場所へ動いた」、1 回は「自分で動き出した」）
  仕切りの右端のすき間のまわり（x 7.5〜9.5・y 8.0〜9.6）  0 回
  奥の区画（x < 9.5・y > 9.0）                             9 回
    8 回は丸テーブル T05 と T06 のあいだ（(5.36, 12.41) に 1号機 3 回・(5.85, 11.98) に 2号機 5 回）。
      すべて 60 秒の「動けなくなった」。理由は椅子（T05・T06 の椅子）4・もう1台のロボット 4
      （店の時間 15〜24 分の間に続けて起きた。T05 の止まる位置は (5.36, 12.81)、T06 は (6.79, 11.86)）
    1 回は (7.57, 13.28)：もう1台のロボット・44 秒・回り込んで動き出した
  ドリンクバーのまわり（x 13.0〜21.5・y 2.6〜4.5）         0 回
  入口・レジのまわり（x 9.0〜14.0・y < 3.8）                1 回（(13.49, 1.69)：人が立ち止まっていた・44 秒・自分で動き出した）
  理由ごと（17 回）：もう1台のロボット 12・椅子・荷物・ベビーカー 4・人が立ち止まっていた 1
  動けなくなった 12 ＝ T05・T06 のあいだ 8 ＋ 待機場所1 4

  ロボットどうしが向かい合って止まった（face_stop）：25 回（待機場所 18・通路 7・受け渡し口 0）、いちばん長いもので 244 秒（待機場所）


====================================================================
7. 仕切りの右端のすき間（x 8.0〜9.5・y 8.6〜9.0）で向かい合って待った回数（まわり y 8.3〜9.3 で数えた。分かる範囲）
====================================================================

                                       1台       2台
  ロボットどうしのすれ違い（passes）     0         1（「幅が足りず今の決まりへ」）
  スタッフがロボットに道をゆずって待った  0         5（Staff01 2 回・Staff02 3 回。1.35〜7.8 秒）
  ロボットが止まった（30 秒未満も含む）  13        14
    1台：スタッフとすれ違った 10・お客さんとすれ違った 2（最長 8 秒）・人が立ち止まっていた 1
    2台：スタッフとすれ違った 8・人が立ち止まっていた 2・お客さんとすれ違った 2・もう1台のロボット 2（0.65 秒・3.45 秒）
  人どうしで詰まった（people_jams）      0         1（体を横に向けて抜けた・1 秒）
  客が 60 秒であきらめた（give_ups）      0         1
  ロボットと人の接触（contacts）         1（客）    1（スタッフ）
  どれも 30 秒未満で、ここで「動けなくなった」ものはない。


====================================================================
8. 台帳
====================================================================

  行数：631 → 634（3 行足した。追記だけ。3行とも unity_cs ServiceSim/cs:39・layout_generation dffc100b269c）
  先頭 631 行の md5：41c8ceff63036168a9d2940fb1e8c4ba（退避と同じ）
  列は今までどおり（59 列）。鍵ファイルは残っていない


====================================================================
9. make_queue（台帳には書いていない）
====================================================================

  --stores fam_p0 --seeds 0 --label p0check → fam_p0_s2_r{0,1,2}_a19 の 3 回
    （0台 trays 1・1台と2台 trays 3・レジ 1・すれ違い入・待機場所へ戻る入・案B切）。make_queue.py はコードを変えずに使えた
  何も指定しない（/tmp に作った）
    → fam_p1・fam_p5 × 0・1・2 台 × 種 0〜9 ＝ 60 回。
       night/20261102/queue.json（v5 の夜）と、回の並びと中身が同じ（label を除く）
  作業フォルダに queue の一時ファイルは置いていない（/tmp/p0c/ にだけ作った）。最後の保留 0（cs:39 head）。


====================================================================
10. エイイチが画面で②を見る手順
====================================================================

  1. Unity Hub から ServiceSim（/Users/shimazueiichi/Robotics_UX/ServiceSim）を開き、
     シーン Assets/ServiceSim/Scenes/ServiceSim_Family.unity を開く
  2. 建てるだけで見る：ServiceSim → JSON Store → ② p0_memory を建てて確かめる
  3. 回して見る：ServiceSim → Site Run → ② スタッフ2人・ロボット0台 / 1台 / 2台
     Play に入って回り、終わると自動で抜ける。すれ違い入・待機場所へ戻る入・案B切（今の標準）。
     種は ExperimentPlan の trialSeed。出力は KIOXIA に出る（台帳には書かない）
  ※ 丸テーブル T05・T06 のあいだの止まりを見るなら 2台の回の店の時間 15〜24 分ごろ。
     待機場所1での止まりは 43 分・53 分・96〜99 分・125〜130 分ごろ


====================================================================
11. 決めてほしいこと
====================================================================

  1. ②の夜を回すかどうか（依頼のとおり、本番の夜は回していない）。
  2. 2台の回で、丸テーブル T05・T06 のあいだに 2台が続けて入り、8 回 60 秒の「動けなくなった」になった
     （椅子 4・もう1台のロボット 4）。T05 の止まる位置 (5.36, 12.81) と T06 の止まる位置 (6.79, 11.86) が近く、
     引いた椅子も効いているように見える。このまま夜を回すか、先にサイトで卓の並びか止まる位置を見直すか。
  3. 待機場所1の中での止まり 7（すべてもう1台のロボット。4 回は 60 秒）。③⑦④⑥と同じ「待機場所が受け渡し口の前の近く」の形。
  4. 入れた組の数が 31 組で、試算（37〜39 組）より少ない（⑤⑥と同じ傾向）。
  5. 卓の部品の読み方の広げ方（3 章）でよいか。特に、知らない名前の裏の部屋を「kind = back なら事務所の箱」にしたこと
     （サイトの JSON に部屋の種類を足してもらう方がよければ、そちらに合わせて戻す）。
  6. 4 章の気づいたこと（T19 の右の席に着く点が壁から 0.3 m、レジの内側の南北 0.52 m）を調べるかどうか。
     どちらも回は最後まで回っているが、店の形のことなので、直すならサイトが先。
```

### 依頼箱の結果：20261029_23_店2を建てて確かめる_20261029_1704.md

```markdown
# 結果：20261029_23_店2を建てて確かめる

- 状態：完了
- 始めた時刻：2026-10-29 17:04
- 終わった時刻：2026-10-29 17:33（30分）
- 作業フォルダ：/Users/shimazueiichi/Robotics_UX/ServiceSim
- この続きを Claude Code で話すとき：作業フォルダで `claude --resume 5e0d11db-6205-4c89-814d-f8a518aa5999`
- 止められた操作：1件（いちばん下に一覧）

## Claude Code の報告

やったこと
- 始める前の確かめを5つ行い、5つとも合っていました。Unity エディタは起動しておらず（Unity Hub だけ）、KIOXIA はつながっていて鍵ファイルはありませんでした。台帳の md5 は退避と同じ、保留は 0、公開中の params は版 dffc100b269c・条件18件でした。
- サイトの params と6店の形（p0〜p5 の JSON と地図）、summary.json を cp でそのまま写しました。控えは unity/site_copy_dffc100b269c/ に置いています。版はすべて dffc100b269c でそろっていました。③④⑤⑥⑦は、前の写しと「版の番号と meta.rules（説明文）」以外は同じでした。params は fam_p0 と条件3件（15〜17 番）が足されただけで、前の15件・common・unity_rules は同じでした。
- ②を、④⑤⑥を足したときと同じ形で足しました。今のコードが知らなかった部分は、店に関係なく読めるように広げました。
  - 卓の種類 t4・r4・long6
  - 丸い天板（`top_shape: "circle"`）。見た目も当たりも丸くしました
  - スツール（`stool: true`）
  - 名前を知らない裏の部屋（冷凍庫・物置など）は、`kind` が back で人が入れなければ事務所の箱として建てる
- 建てたあと、check-in して cs:39 にし、画面なしの実行ファイルを作り直しました（build_id cs39_20261029_1717、保留 0）。そのあと②の0・1・2台・種0の3回を、ラベル p0check・同時4本で回しました。
- make_queue の `--stores fam_p0` は、コードを変えずにそのまま使えました。
- 何も指定しない make_queue を /tmp に作って確かめると、③⑦の60回のままでした。10月28日の夜（night/20261102）の queue と、回の並びも中身も同じです（label を除く）。
- queue の一時ファイルは /tmp/p0c/ にだけ作り、作業フォルダには残していません。

結果
- **②を建てた結果：** 卓19・席88で、JSON・summary.json と一致しました。合わないものはありません。
  - 椅子52脚とスツール6つ、座る位置88は全卓に建ちました。
  - 止まる位置は19か所すべて NavMesh の上にあり、受け渡し口から全卓へ道がつながりました。
  - 待機場所3つ・レジ・レジに並ぶ点3・ドリンクバーの立つ点と並ぶ点・スタッフが待つ点6・トイレの入口も、すべて置けました。置けなかった所はありません。
  - L字の外壁に切れ目はなく、NavMesh の「つながっていない面」は 0 m2 でした。
  - 確かめ A では、引けない卓 0/19、待機場所3つとも道が引けました。
- **3回の結果：** 3回とも最後まで回り、全員帰りました。実時間は 2.4・2.5・2.5 分です。左が Unity、右が試算です（単位は分）。

| | 0台 | 1台 | 2台 |
|---|---|---|---|
| 入れた組の数 | 31 / 37.4 | 31 / 38.7 | 31 / 37.5 |
| 入店待ち | 1.33 / 2.68 | 1.21 / 2.44 | 1.45 / 1.60 |
| うち席は空いているのに待った | 0 / 1.13 | 0 / 0.56 | 0 / 0.35 |
| 料理の待ち | 0.68 / 0.60 | 0.95 / 0.94 | 0.94 / 0.40 |
| 会計待ち | 0.80 / 1.31 | 0.72 / 1.30 | 1.16 / 1.25 |
| ロボットが運んだ皿の割合 | 0 / 0 | 0.987 / 0.979 | 0.974 / 1.000 |
| 往復の数 | 0 | 63 | 73 |
| 30秒以上の止まり（1往復あたり） | 0 | 1（0.016） | 17（0.233） |
| 動けなくなった（60秒） | 0 | 0 | 12 |
| 卓を空けた | 0 | 0 | 0 |
| 瞬間移動 | 3 | 8 | 15 |
| 打ち切り | 0 | 0 | 1 |

- **2台の回の30秒以上の止まり17回の場所：**
  - 受け渡し口の点から2.5 m 以内：7回。7回とも待機場所1の中なので、待機場所を除くと0回です。
  - 仕切りの右端のすき間のまわり：0回。
  - 奥の区画：9回。そのうち8回は丸テーブル T05 と T06 のあいだで、8回とも60秒の「動けなくなった」です。理由は椅子4回、もう1台のロボット4回でした。
  - ドリンクバーのまわり：0回。
  - 入口・レジのまわり：1回。
- **仕切りの右端のすき間で向かい合って待った回数（2台の回）：** ロボットどうしのすれ違い1回、スタッフがロボットに道をゆずって待った5回（1.35〜7.8秒）でした。どれも30秒未満です。
- **台帳：** 631 → 634 行で、追記だけでした。先頭631行の md5 は 41c8ceff63036168a9d2940fb1e8c4ba で、退避と同じです。
- **judge.md：** 3回とも「基準なし」です（②の基準データがないため）。
- **エイイチが画面で②を見る手順：**
  1. Unity Hub から ServiceSim を開き、シーン `ServiceSim_Family.unity` を開く。
  2. 建てるだけ見るときは、ServiceSim → JSON Store → 「② p0_memory を建てて確かめる」。
  3. 回して見るときは、ServiceSim → Site Run → 「② スタッフ2人・ロボット0台／1台／2台」。
  4. T05・T06 のあいだの止まりは、2台の回の店の時間15〜24分ごろに見えます。

変えたファイル（cs:39）
- 足したもの：`Store/Layouts/p0_memory.json`・`p0_memory_map.json`（と .meta）、`Store/StoreLayout_p0_memory.asset`（と .meta）
- 写し直したもの：`Experiment/serving-robot-params.json`、`Store/Layouts/summary.json`、p1〜p5 の JSON と地図
- ②を足したもの：`Editor/ServiceSimSetup.cs`・`ServiceSimSiteRun.cs`・`ServiceSimJsonStore.cs`・`ServiceSimMapPlanner.cs`、`Scenes/ServiceSim_Family.unity`
- 読み方を広げたもの：`Store/JsonStoreLayout.cs`・`StorePlan.cs`・`StoreBuilder.cs`
- 建てる確かめで変わった `NavMeshAreas.asset` と `Mat_RobotKeepout.mat` は cm undo で戻しました。make_queue・night_runner・judge_night は変えていません。
- 報告ファイル：claude_code_reports/20261029_1732_p0_build_check.txt

決めてほしいこと
1. ②の本番の夜を回すかどうか（今回は回していません）。
2. 2台の回で、丸テーブル T05・T06 のあいだで60秒動けなくなったのが8回ありました。2つの卓の止まる位置が近く、引いた椅子も効いているように見えます。このまま夜を回すか、先にサイトで卓の並びか止まる位置を見直すか。
3. 待機場所1の中での止まりが7回あり、そのうち4回が60秒でした。③⑦④⑥と同じ「待機場所が受け渡し口の近く」の形です。
4. 入れた組の数が31組で、試算の37〜39組より少ないです（⑤⑥と同じ傾向）。
5. 読み方の広げ方でよいか。特に、名前を知らない裏の部屋を「kind が back なら事務所の箱」にした点です。サイトの JSON に部屋の種類を足す方がよければ、そちらに合わせます。
6. 建てたときに気づいた2点を調べるかどうか。直すならサイトが先です。
   - T19 の右の席に着く点が、壁から0.3 m でロボット用の確かめに乗りません。人用の確かめは通っています。
   - レジの内側の南北の幅が0.52 m で、確かめが「入口が0.7 m 未満」と出します。回でレジの内側に入れなかった人は0です。

## 止められた操作

- {"tool_name": "Bash", "tool_use_id": "toolu_01TB6PgYRTnYuMUkPuzbBNjF", "tool_input": {"command": "U=\"$HOME/Library/Mobile Documents/com~apple~CloudDocs/デスクトップ/ADAPT DESIGN/じぶんの/PixelstoMotors/デジタルツイン学習R2R2R/サービスロボット導入シミュレーション/unity\"; D=\"$U/site_copy_dffc100b269c\"; P=/Users/shimazueiichi/Robotics_UX/ServiceSim/Assets/ServiceSim\ncat > \"$D/README.txt\" <<'EOF'\nhttps://pixelstomotors.com/sim/ から 2026-10-29 17:05 に取った（p2m-site commit b0f1b0c の公開、版 dffc100b269c）\n  serving-robot-params.json\n  
```

### 1台はきれいに回り、2台は丸テーブルの間で動けなくなった

②は Unity で手直しなしに建ちました（卓19・席88・止まる位置19か所すべて NavMesh の上）。3回とも最後まで回り、入店待ちは0台1.33分・1台1.21分・2台1.45分です。1台の回は30秒以上の止まりが1回だけでした。

2台の回は、30秒以上の止まりが17回、60秒動けなくなったのが12回で、1台の回より悪くなりました。12回のうち8回が、丸テーブル T05 と T06 の間です。理由は椅子4回・もう1台のロボット4回でした。

建てる前の図面の点検で、奥の8卓（36席）へ行く道がすべて通る「仕切り壁の右端とパントリーの間の1.5m」を、詰まりやすい所として挙げていました。2台のロボットがすれ違うには1.6m要るためです。確かめの1回では、ここの30秒以上の止まりは0回で、人がよけて数秒待つだけで抜けていました（あとの30回の夜では16回出ています）。60秒動けなくなったのは、図面の点検で気にしていなかった丸テーブルの間でした。


## 作業ログ ― 丸テーブル T06 を右へ1.0m寄せた

直し方を決める前に、Unity の結果を受けて方針を決めました。

> 先にサイトで丸テーブルの並びを見直してから夜を回す（記憶の店といってもかなり昔なので無理そうなレイアウトなら変えていいよ）

### T05 に止まったロボットの横には、0.24mしか残っていなかった

上の区画の卓は、左右2列 × 3段に並んでいます。左の列と右の列の間は、どの段も1.0〜1.1mです。T05（左の丸テーブル）に料理を置くロボットは、T05 の右の辺、つまり丸テーブル2つの間に止まります。止まったロボットの体（幅0.5m）の横に残るのは0.24mだけで、上の段（T03・T04）へこの間を通って行くロボットは抜けられません。さらに T06 の左の椅子はこの間の側にあり、客が座るときに引くと、もっと狭くなります。

### 寄せ方の案を、決まり・止まる位置・距離で比べたスクリプト round_options.py

案は2つ比べました。A は T06 だけを右へ0.7m、B は T06 と下の段の T08 を右へ0.7m です。

```python
"""②の丸テーブルまわりの直し方の案（今・A：T06を右へ0.7m・B：T06とT08を右へ0.7m）を、決まり・止まる位置・距離・道順で比べる（2026-10-29）。
使い方: python3 round_options.py <tools/sim_layouts のフォルダ> <出力フォルダ/>"""
import sys, json, copy
sys.path.insert(0, sys.argv[1])
import famires_v3 as v, famires_p0, unity_export as ux
OUT = sys.argv[2]
opts = {"now": {}, "A": {"T06": 0.7}, "B": {"T06": 0.7, "T08": 0.7}}
res_all = {}
for name, mv in opts.items():
    L = v.prepare(famires_p0.p0_memory())
    for t in L["tables"]:
        if t["id"] in mv: t["x"] = round(t["x"] + mv[t["id"]], 3)
    viol = v.check_rules(L)
    if viol: print(name, "VIOL", viol); continue
    ctx = {}
    res, err = v.analyze(L, v.SETTINGS["res"], ctx)
    resb, errb = v.analyze(L, v.SETTINGS["check_res"])
    conv = [a["id"] for a, b in zip(res, resb) if a["category"] != b["category"]]
    U = ux.build(L, res, ctx["grid"], ctx["d_norm"], ctx["d_pass"], ctx["sides"], v.standby_slots(L["robot_standby"]), v.FURNITURE_TYPES, {})
    R = ux.build_routes(L, res, ctx["grid"], v.SETTINGS["normal_width"], v.ROBOT_MODELS[v.SETTINGS["model"]]["pass_width"])
    U["routes"] = R
    vr = v.check_register_clear(U)
    s = v.summarize(L, res)
    print(name, "err", err, "conv", conv, "reg", vr, "mean", s["robot_dist_mean"], "max", s["robot_dist_max"], "cats", s["robot_tables"], s["narrow_tables"], s["human_tables"])
    for t in U["tables"]:
        if t["id"] in ("T05", "T06", "T07", "T08", "T03", "T04"):
            print("  ", t["id"], t["footprint"], "stop", t["stop"], t["side"], "dist", t["dist"], "chairs", t["parts"]["chair_sides"])
    json.dump(U, open(OUT + f"U_{name}.json", "w"), ensure_ascii=False)
    res_all[name] = [r.get("dist") for r in res]
json.dump(res_all, open(OUT + "dists.json", "w"))
```

#### round_options.py の出力

```text
now err [] conv [] reg [] mean 8.6 max 13.78 cats 19 0 0
   T03 [4.0, 15.0, 5.2, 16.2] stop [np.float64(5.038), np.float64(14.212)] bottom dist 12.56 chairs ['left', 'right']
   T04 [6.0, 15.0, 7.2, 16.2] stop [np.float64(7.038), np.float64(14.238)] bottom dist 11.41 chairs ['left', 'right']
   T05 [3.65, 12.65, 4.75, 13.75] stop [np.float64(5.363), np.float64(12.812)] right dist 11.03 chairs ['top', 'bottom']
   T06 [5.85, 12.65, 6.95, 13.75] stop [np.float64(6.788), np.float64(11.862)] bottom dist 9.05 chairs ['left', 'right']
   T07 [3.6, 9.6, 4.8, 10.8] stop [np.float64(5.312), np.float64(10.638)] right dist 10.71 chairs ['top', 'bottom']
   T08 [5.8, 9.6, 7.0, 10.8] stop [np.float64(7.788), np.float64(9.763)] right dist 6.63 chairs ['top', 'bottom']
A err [] conv [] reg [] mean 8.5 max 13.78 cats 19 0 0
   T03 [4.0, 15.0, 5.2, 16.2] stop [np.float64(5.038), np.float64(14.212)] bottom dist 12.15 chairs ['left', 'right']
   T04 [6.0, 15.0, 7.2, 16.2] stop [np.float64(6.163), np.float64(14.212)] bottom dist 11.77 chairs ['left', 'right']
   T05 [3.65, 12.65, 4.75, 13.75] stop [np.float64(5.538), np.float64(12.812)] right dist 10.62 chairs ['top', 'bottom']
   T06 [6.55, 12.65, 7.65, 13.75] stop [np.float64(7.488), np.float64(11.862)] bottom dist 8.76 chairs ['left', 'right']
   T07 [3.6, 9.6, 4.8, 10.8] stop [np.float64(5.312), np.float64(10.638)] right dist 10.71 chairs ['top', 'bottom']
   T08 [5.8, 9.6, 7.0, 10.8] stop [np.float64(7.788), np.float64(9.763)] right dist 6.63 chairs ['top', 'bottom']
B err [] conv [] reg [] mean 8.6 max 14.19 cats 19 0 0
   T03 [4.0, 15.0, 5.2, 16.2] stop [np.float64(5.038), np.float64(14.212)] bottom dist 12.56 chairs ['left', 'right']
   T04 [6.0, 15.0, 7.2, 16.2] stop [np.float64(6.163), np.float64(14.212)] bottom dist 12.18 chairs ['left', 'right']
   T05 [3.65, 12.65, 4.75, 13.75] stop [np.float64(5.538), np.float64(12.812)] right dist 11.03 chairs ['top', 'bottom']
   T06 [6.55, 12.65, 7.65, 13.75] stop [np.float64(7.488), np.float64(11.862)] bottom dist 8.76 chairs ['left', 'right']
   T07 [3.6, 9.6, 4.8, 10.8] stop [np.float64(5.588), np.float64(10.638)] right dist 10.61 chairs ['top', 'bottom']
   T08 [6.5, 9.6, 7.7, 10.8] stop [np.float64(8.488), np.float64(9.763)] right dist 6.24 chairs ['top', 'bottom']
```

B は、T08 に料理を置くロボットが、T08 の右（パントリーの壁ぞい）に止まります。奥の区画へ行く道はすべてこの壁ぞいを通るので、止まったロボットの横に0.76mしか残らず、ロボットの通れる幅（0.8m）を下回ります。奥の8卓への一本道をふさぐことになるので、B はやめました。

### 丸テーブルの間を通る道を数えたスクリプト gap_routes.py

```python
"""今の並びと案A（T06を右へ0.7m）で、受け渡し口から T01〜T06 への道と、卓から卓への道が、丸テーブル2つの間を通るかを数える（2026-10-29）。
使い方: python3 gap_routes.py <round_options.py の出力フォルダ/>"""
import json, sys
D = sys.argv[1]
for n, gap in (("now", (4.75, 5.85)), ("A", (4.75, 6.55))):
    U = json.load(open(D + f"U_{n}.json"))
    fp = U["routes"]["from_pass"]
    for tid in ("T01", "T02", "T03", "T04", "T05", "T06"):
        pts = fp[tid]["points"]
        thru = any(gap[0] < p[0] < gap[1] and 12.65 < p[1] < 13.75 for p in pts)
        print(n, tid, "len", fp[tid]["length"], "thru_gap", thru, [(round(p[0], 1), round(p[1], 1)) for p in pts][-5:])
    c = sum(1 for k, r in U["routes"]["between"].items() if any(gap[0] < p[0] < gap[1] and 12.65 < p[1] < 13.75 for p in r["points"]))
    print(n, "between routes through gap", c)
```

#### gap_routes.py の出力

```text
now T01 len 13.191 thru_gap False [(7.1, 11.3), (3.4, 12.2), (3.2, 12.4), (3.2, 12.6), (3.2, 13.4)]
now T02 len 11.831 thru_gap False [(9.0, 5.9), (8.3, 10.2), (7.2, 11.3), (7.1, 11.3), (3.4, 11.3)]
now T03 len 12.049 thru_gap False [(5.5, 12.3), (5.4, 12.4), (5.4, 12.6), (5.2, 14.0), (5.0, 14.2)]
now T04 len 10.918 thru_gap False [(9.0, 5.8), (9.0, 5.9), (7.7, 13.7), (7.2, 14.2), (7.0, 14.2)]
now T05 len 10.569 thru_gap True [(7.2, 11.3), (5.5, 12.3), (5.4, 12.4), (5.4, 12.6), (5.4, 12.8)]
now T06 len 8.749 thru_gap False [(9.3, 5.5), (9.0, 5.8), (9.0, 5.9), (8.3, 10.3), (6.8, 11.9)]
now between routes through gap 18
A T01 len 13.191 thru_gap False [(7.1, 11.3), (3.4, 12.2), (3.2, 12.4), (3.2, 12.6), (3.2, 13.4)]
A T02 len 11.831 thru_gap False [(9.0, 5.9), (8.3, 10.2), (7.2, 11.3), (7.1, 11.3), (3.4, 11.3)]
A T03 len 11.694 thru_gap False [(7.2, 11.3), (6.1, 12.3), (6.1, 12.4), (5.1, 14.1), (5.0, 14.2)]
A T04 len 11.448 thru_gap False [(6.1, 12.3), (6.1, 12.4), (6.1, 12.5), (6.1, 14.1), (6.2, 14.2)]
A T05 len 10.279 thru_gap True [(9.0, 5.8), (9.0, 5.9), (8.3, 10.2), (7.2, 11.3), (5.5, 12.8)]
A T06 len 8.411 thru_gap False [(9.3, 5.5), (9.0, 5.8), (9.0, 5.9), (8.1, 11.2), (7.5, 11.9)]
A between routes through gap 31
```

A にすると、上の段の T03・T04 へ行く道がどちらも丸テーブルの間を通るようになり、卓から卓への道も18本から31本に増えます。間が広がる分、ここが上の段への主な道になります。それなら、T05 にロボットが止まっていても、横をふだんの道（1.0m）で抜けられる幅が要ります。

### T06 を寄せる幅を0.8〜1.2mで比べたスクリプト sweep_t06.py

```python
"""T06 を右へ寄せる幅（0.8・0.9・1.0・1.2m）ごとに、T05 にロボットが止まったときの横の残り・T06 の右の通路・止まる位置・距離を出す（2026-10-29）。
使い方: python3 sweep_t06.py <tools/sim_layouts のフォルダ>"""
import sys, json
sys.path.insert(0, sys.argv[1])
import famires_v3 as v, famires_p0, unity_export as ux
for sh in (0.8, 0.9, 1.0, 1.2):
    L = v.prepare(famires_p0.p0_memory())
    for t in L["tables"]:
        if t["id"] == "T06": t["x"] = round(t["x"] + sh, 3)
    viol = v.check_rules(L)
    if viol: print(sh, "VIOL", viol); continue
    ctx = {}
    res, err = v.analyze(L, v.SETTINGS["res"], ctx)
    R = ux.build_routes(L, res, ctx["grid"], v.SETTINGS["normal_width"], v.ROBOT_MODELS[v.SETTINGS["model"]]["pass_width"])
    d = {r["id"]: r for r in res}; T = {t["id"]: t for t in L["tables"]}
    s5 = d["T05"]["stop"]; t6 = T["T06"]
    free = t6["x"] - (s5[0] + 0.25)
    gap = (4.75, t6["x"])
    thru = [k for k in ("T03", "T04") if any(gap[0] < p[0] < gap[1] for p in R["from_pass"][k]["points"])]
    print(sh, "T06", t6["x"], t6["x"]+t6["w"], "corr", round(9.5-(t6["x"]+t6["w"]),2), "T05stop", [round(x,2) for x in s5], d["T05"]["side"],
          "free_beside", round(free,2), "T06stop", [round(x,2) for x in d["T06"]["stop"]], d["T06"]["side"], "top via gap", thru,
          "mean", v.summarize(L,res)["robot_dist_mean"], "dists", {k: d[k]["dist"] for k in ("T03","T04","T05","T06")})
```

#### sweep_t06.py の出力

```text
0.8 T06 6.65 7.75 corr 1.75 T05stop [np.float64(5.54), np.float64(12.81)] right free_beside 0.86 T06stop [np.float64(7.59), np.float64(11.86)] bottom top via gap ['T03', 'T04'] mean 8.5 dists {'T03': 12.12, 'T04': 11.65, 'T05': 10.62, 'T06': 8.71}
0.9 T06 6.75 7.85 corr 1.65 T05stop [np.float64(5.54), np.float64(12.81)] right free_beside 0.96 T06stop [np.float64(7.69), np.float64(11.86)] bottom top via gap ['T03', 'T04'] mean 8.5 dists {'T03': 12.12, 'T04': 11.61, 'T05': 10.62, 'T06': 8.67}
1.0 T06 6.85 7.949999999999999 corr 1.55 T05stop [np.float64(5.54), np.float64(12.81)] right free_beside 1.06 T06stop [np.float64(7.79), np.float64(11.86)] bottom top via gap ['T03', 'T04'] mean 8.5 dists {'T03': 12.12, 'T04': 11.57, 'T05': 10.62, 'T06': 8.63}
1.2 T06 7.05 8.15 corr 1.35 T05stop [np.float64(5.54), np.float64(12.81)] right free_beside 1.26 T06stop [np.float64(7.99), np.float64(11.86)] bottom top via gap ['T03', 'T04'] mean 8.5 dists {'T03': 12.12, 'T04': 11.49, 'T05': 10.62, 'T06': 8.55}
```

| T06 を右へ | T05 に止まったロボットの横 | T06 の右とパントリーの壁の間 |
|---|---|---|
| 0.8m | 0.86m | 1.75m |
| 0.9m | 0.96m | 1.65m |
| 1.0m | 1.06m | 1.55m |
| 1.2m | 1.26m | 1.35m |

1.0m で、止まったロボットの横がふだんの道の1.0mを超えます。1.2m にすると、右の壁ぞい（奥の区画への一本道）が1.35m まで狭まり、T06 の右の椅子を引くとさらに減るので、1.0m にしました。

- ねらい：T05 に料理を置くロボットが止まっていても、上の段へ行くロボットが横を抜けられるようにする
- 変わったこと：丸テーブル2つの間 1.1m → 2.1m、止まったロボットの横 0.24m → 1.06m。19卓・88席のまま。卓までの距離が変わったのは5卓（T01 13.78→13.77・T03 12.56→12.12・T04 11.41→11.57・T05 11.03→10.62・T06 9.05→8.63m）
- 見込める効果：確かめの2台の回で、丸テーブルのまわりの60秒の止まり 8回 → 0回、料理の待ち 0.94 → 0.54分（測った値。下の依頼24）。30回の夜でも、ここの60秒の止まりは2回だけだった

【画像】LOG402_03_store2_round_tables.png 上の区画の、いまの並び（左）と T06 を右へ1.0m 寄せた案（右）。赤い丸は T05 に料理を置くロボット、赤い数字はその横を別のロボットが抜けられる幅（0.24m → 1.06m）

### 2つの並びを描いたスクリプト round_compare_img.py

```python
"""いまの並びと、T06 を右へ1.0m 寄せた案を、上の区画だけ並べて描く（2026-10-29）。
使い方: python3 round_compare_img.py <tools/sim_layouts のフォルダ> <出力フォルダ/>"""
import sys, json
sys.path.insert(0, sys.argv[1])
import famires_v3 as v, famires_p0, unity_export as ux
import matplotlib; matplotlib.use('Agg')
import matplotlib.pyplot as plt
from matplotlib.patches import Rectangle, Circle
from matplotlib import font_manager as fm
fm.fontManager.addfont('/usr/share/fonts/opentype/noto/NotoSansCJK-Regular.ttc')
plt.rcParams['font.family'] = fm.FontProperties(fname='/usr/share/fonts/opentype/noto/NotoSansCJK-Regular.ttc').get_name()
D = sys.argv[2]
fig, axes = plt.subplots(1, 2, figsize=(15, 8.0))
for ax, (title, sh) in zip(axes, (("いま", 0.0), ("案：T06（右の丸テーブル）を右へ1.0m", 1.0))):
    L = v.prepare(famires_p0.p0_memory())
    for t in L["tables"]:
        if t["id"] == "T06": t["x"] = round(t["x"] + sh, 3)
    ctx = {}
    res, _ = v.analyze(L, v.SETTINGS["res"], ctx)
    U = ux.build(L, res, ctx["grid"], ctx["d_norm"], ctx["d_pass"], ctx["sides"], v.standby_slots(L["robot_standby"]), v.FURNITURE_TYPES, {})
    R = ux.build_routes(L, res, ctx["grid"], v.SETTINGS["normal_width"], v.ROBOT_MODELS[v.SETTINGS["model"]]["pass_width"])
    for r in U["rooms"]:
        x0, y0, x1, y1 = r["rect"]; ax.add_patch(Rectangle((x0, y0), x1-x0, y1-y0, fc='#eceef2', ec='#999', lw=0.6))
        if x0 < 10 and y0 < 17.5: ax.text(min((x0+x1)/2, 10.6), (y0+y1)/2, r["label"], ha='center', va='center', fontsize=9, color='#666')
    for w in U["walls"] + [dict(rect=r) for r in U["outer_walls"]]:
        x0, y0, x1, y1 = w["rect"]; ax.add_patch(Rectangle((x0, y0), x1-x0, y1-y0, fc='#7d8590', ec='none'))
    for tid in ("T03", "T04", "T05", "T06"):
        pts = R["from_pass"][tid]["points"]
        ax.plot([p[0] for p in pts], [p[1] for p in pts], color='#e8590c', lw=1, alpha=0.45)
    for t in U["tables"]:
        p = t["parts"]; x0, y0, x1, y1 = t["footprint"]
        for b in p["benches"]: ax.add_patch(Rectangle((b[0], b[1]), b[2]-b[0], b[3]-b[1], fc='#d6d9df', ec='#555', lw=0.6))
        tp = p["top"]
        if p.get("top_shape") == "circle": ax.add_patch(Circle(((tp[0]+tp[2])/2, (tp[1]+tp[3])/2), (tp[2]-tp[0])/2, fc='white', ec='#222', lw=1.2))
        else: ax.add_patch(Rectangle((tp[0], tp[1]), tp[2]-tp[0], tp[3]-tp[1], fc='white', ec='#222', lw=1.2))
        for c in p["chairs"]:
            r = c["rect"]; ax.add_patch(Circle(((r[0]+r[2])/2, (r[1]+r[3])/2), (r[2]-r[0])/2, fc='#f2a33a', ec='#333', lw=0.5))
        if t["stop"]: ax.add_patch(Circle(tuple(t["stop"]), 0.09, fc='#e8590c', ec='white', lw=0.6, zorder=5))
        if x1 < 10.5 and y0 > 8: ax.text((x0+x1)/2, y1+0.12, t["id"], ha='center', fontsize=9)
    T = {t["id"]: t for t in U["tables"]}
    s5 = T["T05"]["stop"]
    ax.add_patch(Circle(tuple(s5), 0.25, fc='#e8590c', alpha=0.35, ec='#e8590c', lw=1.2, zorder=4))
    x6 = T["T06"]["footprint"][0]
    free = x6 - (s5[0] + 0.25)
    ax.annotate('', xy=(x6, 13.2), xytext=(s5[0]+0.25, 13.2), arrowprops=dict(arrowstyle='<->', color='#c92a2a', lw=1.4))
    ax.text((x6 + s5[0] + 0.25)/2, 13.32, f"{free:.2f}m", ha='center', fontsize=10, color='#c92a2a', weight='bold')
    gap = x6 - 4.75
    ax.annotate('', xy=(x6, 12.5), xytext=(4.75, 12.5), arrowprops=dict(arrowstyle='<->', color='#1c7ed6', lw=1.2))
    ax.text((x6+4.75)/2, 12.25, f"卓の間 {gap:.1f}m", ha='center', fontsize=9, color='#1c7ed6')
    x6r = T["T06"]["footprint"][2]
    ax.annotate('', xy=(9.5, 13.0), xytext=(x6r, 13.0), arrowprops=dict(arrowstyle='<->', color='#1c7ed6', lw=1.2))
    ax.text((x6r+9.5)/2, 13.12, f"{9.5-x6r:.2f}m", ha='center', fontsize=9, color='#1c7ed6')
    ax.set_xlim(-0.3, 10.2); ax.set_ylim(8.3, 17.5); ax.set_aspect('equal'); ax.axis('off')
    ax.set_title(title, fontsize=13)
fig.text(0.5, 0.02, "赤い丸＝T05 に料理を置くロボット（止まる位置）。赤い数字＝その横を別のロボットが抜けられる幅（ふだん走らせる幅 1.0m・通れる幅 0.8m）。線＝受け渡し口から T03〜T06 への道", ha='center', fontsize=10, color='#444')
plt.tight_layout(rect=(0, 0.04, 1, 0.97)); plt.savefig(D + 'p0_round_compare.png', dpi=110)
```

### 店の形の作り方 famires_p0.py（直した版・全文）

```python
"""記憶の店（昔働いていたファミレスを記憶から起こした店・layout_v11）を、5パターンと同じ決まりに合わせた版。

layout_v11.json（記憶のまま）は変えずに残し、ここで直した版を作る。
直したこと（2026-10-21 エイイチと決めたこと）
- 建物の形：客席の奥の壁はそのまま。トイレ・パントリーの出入り口・洗い場・物置の並びが、その外へ約2.2m出っ張る
- 空いた所は厨房が広がる（キッチンと冷蔵庫を奥へ延ばし、出っ張りとの間に裏の通路）
- トイレへは、パントリーの壁ぞいの通路を奥へ進んで入る。元のトイレの場所は通路。トイレの手前に短い仕切り壁（約2.6m）
- トイレの客席側（通路側）に厚い壁（30cm）、入口は下向き（通路の突き当たり）
- 上の並びの右端の4人席は残す（当時もあった）。トイレとの間は、トイレの厚い壁と通路の仕切り壁でへだてる
- 入口の右に待合を足した。レジを2.2mから2.5mにし、内側に店員の立つ所を付けた
- 待機場所を2.2×0.7mから2.4×0.8mに広げた（3台のまま。1台0.8×0.8m）（2026-10-22、codex の2回目の検証を受けて）
- パントリーの上の通路に出入りできなかったので、出入り口を2つ開けた（2026-10-22 エイイチの指摘。店員もここを通る）
  A：受け渡し口（上）のすぐ上の、パントリーの壁に1m（客席側のトイレへの通路とつながる）
  B：パントリーの上の端（受け渡し口（上）から上の通路へ）
  A・B とも扉はなく、開いているだけ。扉があるのは、上の通路から洗い場とキッチンへ入る所
- 仕切り壁の上の4人席2つを、壁との間が0.6mになるまで寄せた（ロボットが壁側から入らないように）
"""
import json
from pathlib import Path

import famires_gen2 as gen

HERE = Path(__file__).parent

WING_X0, WING_DEPTH = 7.6, 2.2   # 出っ張りの左端と奥行き（仮）


def p0_memory():
    B = json.load(open(HERE / "layout_v11.json", encoding="utf-8"))
    W, D0 = B["outer"]["w"], B["outer"]["d"]
    D = D0 + WING_DEPTH
    keep = {"パントリー", "冷凍庫", "保存庫", "社員トイレ", "更衣室", "こおり", "ドリンクバー"}
    rooms = [dict(r) for r in B["rooms"] if r["label"] in keep]
    rooms += [
        dict(label="キッチン", rect=[12.0, 6.0, 19.0, 16.0], kind="back"),
        dict(label="冷蔵庫", rect=[19.0, 10.5, 21.0, 16.0], kind="back"),
        # 出っ張り：トイレ・パントリーの出入り口（通路）・洗い場・物置
        dict(label="トイレ", rect=[WING_X0, D0, 9.5, D], kind="guest"),
        dict(label="洗い場", rect=[12.0, D0, 21.0, D], kind="back"),
        dict(label="物置", rect=[21.6, D0, W, D], kind="back"),
        # 建物の外（出っ張りの左）
        dict(label="建物の外", rect=[0.0, D0, WING_X0, D], kind="outside"),
        *gen.register([9.8, 2.2, 12.3, 2.9], [9.8, 2.9, 12.3, 3.7]),
        dict(label="待合", rect=[12.7, 0.0, 13.9, 0.5], kind="guest"),
    ]
    walls = [dict(w) for w in B["walls"] if w["label"] != "客席と裏の壁"]
    walls += [dict(label="客席と裏の壁", rect=[19.0, 6.0, W, 6.25])]
    # トイレの手前の短い仕切り壁（上の客席とトイレへの通路の間・約2.6m）
    walls += [dict(label="通路の仕切り壁", rect=[7.9, 14.4, 8.1, D0])]
    # 通路とバックヤード（パントリーの出入り口）の間の壁：パントリーの壁をトイレまで延ばす
    # 受け渡し口（上）のすぐ上を1m開けて、客席側（トイレへの通路）との出入り口にする（2026-10-22 エイイチと決めた）
    door_a = [9.5, 14.0, 9.8, 15.0]
    walls += [dict(label="パントリーの壁", rect=[9.5, door_a[3], 9.8, D0])]
    # 店員の出入り口：A＝パントリーの上の通路と客席側の間、B＝パントリーの上の端（受け渡し口（上）から上の通路へ）
    # door：扉があるか。A・B は扉のない、開いているだけの所（扉があると誰かが開けないといけないため）
    # 扉があるのは、上の通路から洗い場とキッチンへ入る所（位置は仮）
    doors = [dict(label="出入り口（パントリーの上の通路と客席）", rect=door_a, kind="staff", door=False),
             dict(label="出入り口（パントリーと上の通路）", rect=[9.8, 13.9, 12.0, 14.0], kind="staff", door=False),
             dict(label="洗い場の扉", rect=[12.2, D0, 13.1, D0 + 0.1], kind="staff", door=True),
             dict(label="キッチンの扉", rect=[12.2, 15.9, 13.1, 16.0], kind="staff", door=True)]
    # トイレの壁：通路側（下）は厚さ30cm、入口0.9m。右（パントリーの出入り口側）も壁
    door_x0, door_x1 = 8.3, 9.2
    walls += [dict(label="トイレの壁", rect=[WING_X0, D0, door_x0, D0 + 0.3]),
              dict(label="トイレの壁", rect=[door_x1, D0, 9.5, D0 + 0.3]),
              dict(label="トイレの壁", rect=[9.2, D0 + 0.3, 9.5, D])]
    toilet_door = [door_x0, D0 - 1.2, door_x1, D0]

    tables = []
    for t in B["tables"]:
        if t["type"] == "t4":
            tables.append(dict(type="t4", x=round(t["x"] - 0.6, 2), y=round(t["y"] - 0.6, 2), w=1.2, h=1.2, seats=4))
        elif t["type"] == "r4":
            tables.append(dict(type="r4", x=round(t["x"] - 0.55, 2), y=round(t["y"] - 0.55, 2), w=1.1, h=1.1, seats=4))
        elif t["type"] == "long6":
            tables.append(dict(type="long6", x=round(t["x"] - 1.6, 2), y=round(t["y"] - 0.97, 2), w=3.2, h=1.94, seats=6))
        else:
            tables.append({k: t[k] for k in ("type", "x", "y", "w", "h", "seats", "flip", "mirror") if k in t})
    # 仕切り壁（y 8.6〜9.0）の上の4人席2つ：壁との間が1.0mあり、ロボットが壁側から入っていたので、
    # 下の区画と同じ0.6m（ロボットが通れない幅）まで壁に寄せる（2026-10-22 エイイチの指摘）
    for t in tables:
        if t["type"] == "t4" and abs(t["y"] - 10.0) < 1e-6:
            t["y"] = 9.6
    # 右の丸テーブル（T06）を右へ1.0m（2026-10-29 エイイチと決めた）。丸テーブル2つの間が1.1mしかなく、T05 に料理を置くロボットが
    # 止まると横に0.24mしか残らず、上の段（T03・T04）へ行くロボットが抜けられなかった（Unity の確かめの2台の回で60秒の止まり8回）。
    # 間を2.1mにし、T05 にロボットが止まっていても横に1.06m（ふだんの道1.0m）残す。T06 の右とパントリーの壁の間は2.55m → 1.55m
    for t in tables:
        if t["type"] == "r4" and abs(t["x"] - 5.85) < 1e-6:
            t["x"] = 6.85

    # 待機場所：記憶のまま（2.2×0.7m）だと3台分（1台0.8×0.8m）に足りないので、右に0.2m・手前に0.1m広げる（2026-10-22 エイイチと決めた）
    sb0 = B["robot_standby"]
    standby = dict(label=sb0["label"], rect=[12.2, 5.1, 14.6, 5.9], slots=3)

    dish = [d for d in B["dish_up"] if "下" in d["label"]] + [d for d in B["dish_up"] if "下" not in d["label"]]
    outline = [(0, 0), (W, 0), (W, D), (WING_X0, D), (WING_X0, D0), (0, D0)]
    return dict(name="② 定番の郊外型", style="定番の郊外型", outer=dict(w=W, d=D), outline=outline,
                entrance=dict(side="bottom", a0=B["entrance"]["x0"], a1=B["entrance"]["x1"]),
                rooms=rooms, walls=walls, toilet_doors=[toilet_door], dish_up=dish, doors=doors,
                robot_standby=standby, tables=tables)
```

### 店の形の README.md と famires_p0.py の差分

```diff
diff --git a/tools/sim_layouts/README.md b/tools/sim_layouts/README.md
index 81ddaea..5be98f2 100644
--- a/tools/sim_layouts/README.md
+++ b/tools/sim_layouts/README.md
@@ -132,6 +132,13 @@ python3 test_famires_v3.py         # 確かめの仕組みそのものを確か
 - 記録だけ：会計の列（y 1.25）が待合の前の点（1.8, 0.9）の0.35m上に来て、案内を待つ客と会計に並ぶ客が重なる。待合は動かしていない（Unity で見る）
 - ⑥の卓までの距離：T27 4.79→5.25・T28 6.64→7.10・T29 8.49→8.12・T30 10.22→9.75m（平均10.7m・最長18.4mは同じ）。⑥以外は版の番号だけ
 
+## 決まり（2026-10-29 エイイチと決めたこと：②の丸テーブル）
+
+- ②の右の丸テーブル（T06）を右へ1.0m（x 5.85〜6.95 → 6.85〜7.95）。丸テーブル2つの間が1.1mしかなく、T05 に料理を置くロボットが止まると横に0.24mしか残らず、上の段（T03・T04）へ行くロボットが抜けられなかった（Unity の確かめの2台の回で、ここで60秒の止まり8回）。間を2.1mにし、T05 にロボットが止まっていても横に1.06m（ふだんの道1.0m）残る。T06 の右とパントリーの壁の間は2.55m → 1.55m
+- 記憶の店は昔の記憶なので、ロボットが回れない所は変えてよい（エイイチ）
+- ②の卓までの距離：T01 13.78→13.77・T03 12.56→12.12・T04 11.41→11.57・T05 11.03→10.62・T06 9.05→8.63m（平均8.6→8.5m）。②以外は版の番号だけ
+- 下の段の T08 も右へ寄せる案はやめた（T08 に料理を置くロボットが、パントリーの壁ぞいの奥への一本道を0.76mまでふさぐため）
+
 ## まだ入っていないこと
 
 - 厨房の中の人の動き（扉・作業通路・下げ膳の返却口）
diff --git a/tools/sim_layouts/famires_p0.py b/tools/sim_layouts/famires_p0.py
index 5f7c5ec..eefd99d 100644
--- a/tools/sim_layouts/famires_p0.py
+++ b/tools/sim_layouts/famires_p0.py
@@ -80,6 +80,12 @@ def p0_memory():
     for t in tables:
         if t["type"] == "t4" and abs(t["y"] - 10.0) < 1e-6:
             t["y"] = 9.6
+    # 右の丸テーブル（T06）を右へ1.0m（2026-10-29 エイイチと決めた）。丸テーブル2つの間が1.1mしかなく、T05 に料理を置くロボットが
+    # 止まると横に0.24mしか残らず、上の段（T03・T04）へ行くロボットが抜けられなかった（Unity の確かめの2台の回で60秒の止まり8回）。
+    # 間を2.1mにし、T05 にロボットが止まっていても横に1.06m（ふだんの道1.0m）残す。T06 の右とパントリーの壁の間は2.55m → 1.55m
+    for t in tables:
+        if t["type"] == "r4" and abs(t["x"] - 5.85) < 1e-6:
+            t["x"] = 6.85
 
     # 待機場所：記憶のまま（2.2×0.7m）だと3台分（1台0.8×0.8m）に足りないので、右に0.2m・手前に0.1m広げる（2026-10-22 エイイチと決めた）
     sb0 = B["robot_standby"]
```

### 6店の店の形を作り直した famires_v3.py の出力（版 08db8a0d067c）

```text
[OK] p0_memory: {'name': '② 定番の郊外型', 'seats': 88, 'tables': 19, 'model': 'BellaBot', 'pass_width': 0.8, 'normal_width': 1.0, 'robot_tables': 19, 'robot_seats': 88, 'narrow_tables': 0, 'narrow_seats': 0, 'human_tables': 0, 'human_seats': 0, 'robot_dist_mean': 8.5, 'robot_dist_max': 13.77, 'human_walk_total': 0.0, 'human_walk_max': None}  マス目の差: []
[OK] p1_efficient_corner: {'name': '③ 効率重視型・入口が左下の角', 'seats': 160, 'tables': 42, 'model': 'BellaBot', 'pass_width': 0.8, 'normal_width': 1.0, 'robot_tables': 42, 'robot_seats': 160, 'narrow_tables': 0, 'narrow_seats': 0, 'human_tables': 0, 'human_seats': 0, 'robot_dist_mean': 10.6, 'robot_dist_max': 20.14, 'human_walk_total': 0.0, 'human_walk_max': None}  マス目の差: []
[OK] p2_efficient_narrow: {'name': '④ 効率重視型・狭い店・入口が右の壁', 'seats': 88, 'tables': 28, 'model': 'BellaBot', 'pass_width': 0.8, 'normal_width': 1.0, 'robot_tables': 28, 'robot_seats': 88, 'narrow_tables': 0, 'narrow_seats': 0, 'human_tables': 0, 'human_seats': 0, 'robot_dist_mean': 8.5, 'robot_dist_max': 13.92, 'human_walk_total': 0.0, 'human_walk_max': None}  マス目の差: []
[OK] p3_relaxed_center: {'name': '⑤ ゆったり型・入口が正面の中央', 'seats': 200, 'tables': 46, 'model': 'BellaBot', 'pass_width': 0.8, 'normal_width': 1.0, 'robot_tables': 46, 'robot_seats': 200, 'narrow_tables': 0, 'narrow_seats': 0, 'human_tables': 0, 'human_seats': 0, 'robot_dist_mean': 12.5, 'robot_dist_max': 18.8, 'human_walk_total': 0.0, 'human_walk_max': None}  マス目の差: []
[OK] p4_relaxed_side: {'name': '⑥ ゆったり型・入口が左の壁', 'seats': 158, 'tables': 38, 'model': 'BellaBot', 'pass_width': 0.8, 'normal_width': 1.0, 'robot_tables': 38, 'robot_seats': 158, 'narrow_tables': 0, 'narrow_seats': 0, 'human_tables': 0, 'human_seats': 0, 'robot_dist_mean': 10.7, 'robot_dist_max': 18.38, 'human_walk_total': 0.0, 'human_walk_max': None}  マス目の差: []
[OK] p5_crammed: {'name': '⑦ ③の列の間の通路を95cmに（卓と席数は③と同じ）', 'seats': 160, 'tables': 42, 'model': 'BellaBot', 'pass_width': 0.8, 'normal_width': 1.0, 'robot_tables': 18, 'robot_seats': 64, 'narrow_tables': 24, 'narrow_seats': 96, 'human_tables': 0, 'human_seats': 0, 'robot_dist_mean': 10.8, 'robot_dist_max': 20.17, 'human_walk_total': 0.0, 'human_walk_max': None}  マス目の差: []
```

#### 確かめの仕組みを確かめた test_famires_v3.py の出力（版 08db8a0d067c）

```text
OK  80cmの通路はBellaBotで通れる（マス目0.025・ずらし0.0）
OK  77cmの通路はBellaBotで通れない（マス目0.025・ずらし0.0）
OK  75cmの通路はServiで通れる（マス目0.025・ずらし0.0）
OK  80cmの通路はBellaBotで通れる（マス目0.025・ずらし0.013）
OK  77cmの通路はBellaBotで通れない（マス目0.025・ずらし0.013）
OK  75cmの通路はServiで通れる（マス目0.025・ずらし0.013）
OK  80cmの通路はBellaBotで通れる（マス目0.025・ずらし0.031）
OK  77cmの通路はBellaBotで通れない（マス目0.025・ずらし0.031）
OK  75cmの通路はServiで通れる（マス目0.025・ずらし0.031）
OK  80cmの通路はBellaBotで通れる（マス目0.0125・ずらし0.0）
OK  77cmの通路はBellaBotで通れない（マス目0.0125・ずらし0.0）
OK  75cmの通路はServiで通れる（マス目0.0125・ずらし0.0）
OK  80cmの通路はBellaBotで通れる（マス目0.0125・ずらし0.013）
OK  77cmの通路はBellaBotで通れない（マス目0.0125・ずらし0.013）
OK  75cmの通路はServiで通れる（マス目0.0125・ずらし0.013）
OK  80cmの通路はBellaBotで通れる（マス目0.0125・ずらし0.031）
OK  77cmの通路はBellaBotで通れない（マス目0.0125・ずらし0.031）
OK  75cmの通路はServiで通れる（マス目0.0125・ずらし0.031）
OK  横向きのボックスの左右（ベンチの背）は座る側の候補にしない
OK  縦向きのボックスの上下（ベンチの背）は座る側の候補にしない
OK  店の外にはみ出した卓を見つける
OK  トイレの入口の前の壁を見つける
OK  トイレの壁でへだてた1mの席は違反にしない
OK  壁がなければ、トイレからちょうど1mの席を見つける
OK  卓に食い込んだ壁を見つける
OK  ゆったり型の仕切り（背もたれの上）は違反にしない
OK  座る側の前をふさがれた卓を見つける
OK  出発点がふさがれていたら止める
OK  待合がないのを見つける
OK  ⑦は③と同じ卓の数・種類・席数
OK  L字席（flip=False・mirror=False）の止まってよい辺は、開いた角とソファの端0.6mまで
OK  L字席（flip=False・mirror=True）の止まってよい辺は、開いた角とソファの端0.6mまで
OK  L字席（flip=True・mirror=False）の止まってよい辺は、開いた角とソファの端0.6mまで
OK  L字席（flip=True・mirror=True）の止まってよい辺は、開いた角とソファの端0.6mまで
OK  ⓪T02 の止まる位置は、開いた角か、そこからソファの端に沿って0.6m以内
OK  ⓪の待機場所は、1台ずつ受け渡し口の前まで出られる
OK  2人席（ベンチがbottom）は、ベンチの側とベンチの横を止まる辺にしない
OK  2人席（ベンチがtop）は、ベンチの側とベンチの横を止まる辺にしない
OK  2人席（ベンチがleft）は、ベンチの側とベンチの横を止まる辺にしない
OK  2人席（ベンチがright）は、ベンチの側とベンチの横を止まる辺にしない
OK  直す前の⓪の待機場所（2.2×0.7mに3台）を見つける
OK  待機場所の台数 100 を見つける
OK  待機場所の台数 0 を見つける
OK  待機場所の台数 -1 を見つける
OK  待機場所の台数 '3' を見つける
OK  待機場所の台数 2.5 を見つける
OK  待機場所の台数 True を見つける
OK  待機場所の前をふさぐと、真ん中の台だけ「出られない」を見つける
OK  待機場所の前と両横をふさぐと、3台とも「出られない」を見つける
OK  反例1：レジとレジ内を消すと見つける
OK  反例2：トイレの壁をほぼ全部外すと「切れ目」を見つける
OK  反例3：トイレの入口の前を「トイレの壁」という名前の壁でふさいでも見つける
OK  反例4：家具の真ん中に置いた接合扱いの仕切りを見つける
OK  反例5：待機場所100台を見つける
OK  反例6：⓪の建物の外を消すと、輪郭と合わないのを見つける
OK  反例7：輪郭を2m四方にすると見つける
OK  ⓪の輪郭から欠けを消すと、建物の外と合わないのを見つける
OK  今の店 p0_memory は決まりを守っている
OK  今の店 p1_efficient_corner は決まりを守っている
OK  今の店 p2_efficient_narrow は決まりを守っている
OK  今の店 p3_relaxed_center は決まりを守っている
OK  今の店 p4_relaxed_side は決まりを守っている
OK  今の店 p5_crammed は決まりを守っている
OK  ベンチの背に立つ仕切りは認める
OK  ベンチの背でも0.08mより深い食い込みは認めない
OK  トイレの目隠し：中心の線だけ当たる短い壁では違反にする（4本の線）
OK  トイレの目隠し：4本とも当たる壁なら違反にしない
OK  線分が厚さ2mmの壁を横切るのを見つける
OK  線分の端が壁に触れるだけなら、通ったとみなさない
OK  線分が壁から離れていれば、通ったとみなさない
OK  201番目だけ見通せる止まる位置も見つける
[OK] p2_efficient_narrow: {'name': '④ 効率重視型・狭い店・入口が右の壁', 'seats': 88, 'tables': 28, 'model': 'BellaBot', 'pass_width': 0.8, 'normal_width': 1.0, 'robot_tables': 28, 'robot_seats': 88, 'narrow_tables': 0, 'narrow_seats': 0, 'human_tables': 0, 'human_seats': 0, 'robot_dist_mean': 8.5, 'robot_dist_max': 13.92, 'human_walk_total': 0.0, 'human_walk_max': None}  マス目の差: []
OK  成功したときは、layout・analysis・summary に同じ版の番号が入る
[NG] p2_efficient_narrow: ④ 効率重視型・狭い店・入口が右の壁
   - 入口まわり: レジがない

違反があるので、/tmp/tmprohlnl9n には何も書いていない（前の版のまま）
OK  違反があると止まり、出力先のファイルは前の版のまま（作業用のフォルダも残らない）
[OK] p2_efficient_narrow: {'name': '④ 効率重視型・狭い店・入口が右の壁', 'seats': 88, 'tables': 28, 'model': 'BellaBot', 'pass_width': 0.8, 'normal_width': 1.0, 'robot_tables': 28, 'robot_seats': 88, 'narrow_tables': 0, 'narrow_seats': 0, 'human_tables': 0, 'human_seats': 0, 'robot_dist_mean': 8.5, 'robot_dist_max': 13.92, 'human_walk_total': 0.0, 'human_walk_max': None}  マス目の差: []

出力先へ入れ替える途中で失敗したので、/tmp/tmprohlnl9n を前の版に戻した
OK  入れ替えの途中で失敗すると、出力先は前の版に戻る（作業用のフォルダも残らない）
OK  反例A：トイレの壁の1cmの切れ目を見つける
OK  反例B：トイレの入口の内側の1cmのふさぎを見つける
OK  反例C：トイレの入口の前の奥行き0.1mを見つける
OK  反例D：輪郭の幅1cmの切れ込み（建物の外なし）を見つける
OK  輪郭に斜めの辺があれば止める
OK  出入り口Aを壁でふさぐと見つける
OK  p1：細い通路は3本で、幅はどれも1.2m
OK  p1：卓の数・止まる位置・距離が analysis と同じ
OK  p1：細い通路を通る卓は、止まる位置がその通路の区画の中
OK  p1：細い通路の入口は、受け渡し口の前から行ける端
OK  p1：全部の卓に部品（天板・座る位置）があり、座る位置の数が席数と同じ
OK  p1：場所の点がそろっている
OK  p1：スタッフが待つ点・並ぶ点・立つ点は、障害物から0.2m以上離れ、細い通路に入らない
OK  p1：席に着く点は障害物から0.2m以上離れ、どの卓にも1つ以上ある
OK  p1：レジ内は通れる部屋（スタッフだけ）、ほかの部屋は通れない箱
OK  p1：受け渡し口から全卓・卓から卓の全組に道順がある
OK  p1：ふだんの道か狭い道かは、試算の卓の分け方と同じ（robot→normal、narrow→narrow）
OK  p1：道順は受け渡し口の前から始まり、止まる位置で終わる
OK  p1：道順のどの区間も、その幅で通れるマス目だけを通る
OK  p1：会計に立つ点・並ぶ点は、ロボットの道から0.75m以上
OK  p1：会計の列が1つあり、ロボットは通れず、人は通れる
OK  p1：会計に立つ点・並ぶ点は会計の列の中
OK  p5：細い通路は3本で、幅はどれも0.95m
OK  p5：卓の数・止まる位置・距離が analysis と同じ
OK  p5：細い通路を通る卓は、止まる位置がその通路の区画の中
OK  p5：細い通路の入口は、受け渡し口の前から行ける端
OK  p5：全部の卓に部品（天板・座る位置）があり、座る位置の数が席数と同じ
OK  p5：場所の点がそろっている
OK  p5：スタッフが待つ点・並ぶ点・立つ点は、障害物から0.2m以上離れ、細い通路に入らない
OK  p5：席に着く点は障害物から0.2m以上離れ、どの卓にも1つ以上ある
OK  p5：レジ内は通れる部屋（スタッフだけ）、ほかの部屋は通れない箱
OK  p5：受け渡し口から全卓・卓から卓の全組に道順がある
OK  p5：ふだんの道か狭い道かは、試算の卓の分け方と同じ（robot→normal、narrow→narrow）
OK  p5：道順は受け渡し口の前から始まり、止まる位置で終わる
OK  p5：道順のどの区間も、その幅で通れるマス目だけを通る
OK  p5：会計に立つ点・並ぶ点は、ロボットの道から0.75m以上
OK  p5：会計の列が1つあり、ロボットは通れず、人は通れる
OK  p5：会計に立つ点・並ぶ点は会計の列の中
OK  ②：全部の卓に部品があり、座る位置の数が席数と同じ
OK  ②：角テーブル・丸テーブルの椅子は2脚ずつ向かい合わせ（向かい合う2辺に2脚ずつ）
OK  ②：椅子とスツールは卓の外形の内側
OK  ②：椅子を置く辺には、どれも席に着く点がある
OK  ②：ロボットが止まる辺に椅子があるのは、その向きの組では座れない卓だけ
OK  p1：地図を読み戻すと、マス目の数が同じ
OK  p1：地図を2回作ると同じ文字列（毎回同じ）
OK  p1：障害物までの距離は、計算の値と0.5mm以内
OK  p1：試算でふだんの道が通れるマスは、地図でも2（待機場所を床にした分だけ増える）
OK  p1：会計の列のマスは、地図では通れない
OK  p1：地図の上でも、ふだんの道で行ける卓は試算の robot の卓と同じ、狭い道でだけ行ける卓は narrow の卓と同じ
OK  p1：どの待機場所の真ん中にも、受け渡し口の前から地図の上で行ける（通れる幅の道）
OK  p5：地図を読み戻すと、マス目の数が同じ
OK  p5：地図を2回作ると同じ文字列（毎回同じ）
OK  p5：障害物までの距離は、計算の値と0.5mm以内
OK  p5：試算でふだんの道が通れるマスは、地図でも2（待機場所を床にした分だけ増える）
OK  p5：会計の列のマスは、地図では通れない
OK  p5：地図の上でも、ふだんの道で行ける卓は試算の robot の卓と同じ、狭い道でだけ行ける卓は narrow の卓と同じ
OK  p5：どの待機場所の真ん中にも、受け渡し口の前から地図の上で行ける（通れる幅の道）
OK  p0：地図を読み戻すと、マス目の数が同じ
OK  p0：地図を2回作ると同じ文字列（毎回同じ）
OK  p0：障害物までの距離は、計算の値と0.5mm以内
OK  p0：試算でふだんの道が通れるマスは、地図でも2（待機場所を床にした分だけ増える）
OK  p0：会計の列のマスは、地図では通れない
OK  p0：地図の上でも、ふだんの道で行ける卓は試算の robot の卓と同じ、狭い道でだけ行ける卓は narrow の卓と同じ
OK  p0：どの待機場所の真ん中にも、受け渡し口の前から地図の上で行ける（通れる幅の道）
OK  会計の列がないと、②は会計に立つ点の近くをロボットが通り、確かめに引っかかる
OK  ボックス席の列は、すき間なく並んだものだけをまとめる

すべて OK
```

#### check_gen_only.py の出力（dffc100b269c → 08db8a0d067c）

```text
generation dffc100b269c -> 08db8a0d067c
違う p0_memory.json: ['layout']
違う p0_memory_analysis.json: ['summary', 'tables']  卓: ['T01', 'T03', 'T04', 'T05', 'T06']
同じ（版の番号だけ） p1_efficient_corner.json
同じ（版の番号だけ） p1_efficient_corner_analysis.json
同じ（版の番号だけ） p2_efficient_narrow.json
同じ（版の番号だけ） p2_efficient_narrow_analysis.json
同じ（版の番号だけ） p3_relaxed_center.json
同じ（版の番号だけ） p3_relaxed_center_analysis.json
同じ（版の番号だけ） p4_relaxed_side.json
同じ（版の番号だけ） p4_relaxed_side_analysis.json
同じ（版の番号だけ） p5_crammed.json
同じ（版の番号だけ） p5_crammed_analysis.json
違う summary.json (list) [0]
違う unity/p0_memory.json: ['routes', 'tables']  卓: ['T01', 'T03', 'T04', 'T05', 'T06']
違う unity/p0_memory_map.json: ['counts', 'free_class', 'clear_mm']
同じ（版の番号だけ） unity/p1_efficient_corner.json
同じ（版の番号だけ） unity/p1_efficient_corner_map.json
同じ（版の番号だけ） unity/p2_efficient_narrow.json
同じ（版の番号だけ） unity/p2_efficient_narrow_map.json
同じ（版の番号だけ） unity/p3_relaxed_center.json
同じ（版の番号だけ） unity/p3_relaxed_center_map.json
同じ（版の番号だけ） unity/p4_relaxed_side.json
同じ（版の番号だけ） unity/p4_relaxed_side_map.json
同じ（版の番号だけ） unity/p5_crammed.json
同じ（版の番号だけ） unity/p5_crammed_map.json
```

②以外の5店は、版の番号のほかは何も変わっていません。


## 作業ログ ― 卓までの距離が5卓で変わったので、②の試算だけ計算し直した

### サイトの試算は、SimPy で店の時間を進めて数えている

サイトの試算（`haizen_sim.py`）は、Python の [SimPy](https://simpy.readthedocs.io/)（出来事を時刻の順に並べて進める、待ち行列のシミュレーションの道具）で書いています。お客さんが来る・席に案内される・料理ができる・ロボットかスタッフが運ぶ・食べ終えて会計する、という出来事を、ピークの2時間ぶん時刻の順に進め、待ち時間を数えます。卓までの距離は、店の形から測った卓ごとの距離の一覧（`dist_list`）から選びます。条件（店・スタッフ・ロボットの台数・来客のペースなど）の組み合わせは32,850あり、1つの条件を40回回した平均を、サイトのページに出しています。

### 使い回す結果から②を外した drop_p0.py

試算は、前の結果に同じ条件があれば回し直さない作りです。ところが条件の名前（`h.key`）には卓までの距離が入らないので、そのままでは②も回し直されません。②の行だけを外してから回しました。

```python
"""前の results.json から②（fam_p0）の行を外して、使い回す結果 results_reuse.json を作る（2026-10-29）。
②は卓までの距離（dist_list）が変わったが、条件の名前（h.key）には距離が入らないので、外さないと計算し直されない"""
import json
R = json.load(open('results.json'))
R2 = dict(R); R2['rows'] = [r for r in R['rows'] if r['store'] != 'fam_p0']
print(len(R['rows']), len(R2['rows']), set(R.keys()))
json.dump(R2, open('results_reuse.json', 'w'), ensure_ascii=False)
```

#### drop_p0.py の出力

```text
32850 30222 {'robots', 'trays', 'modes', 'rows', 'reps', 'fragile_by', 'common', 'robots_all', 'stores'}
```

### 条件を番号で分けて回す run_shard.py（前からあるもの・全文）

```python
"""v2.8 の全条件を、番号で分けて回す（2026-10-25。計算機を2台に分けて速くするため）。
使い方: python3 run_shard.py <k> <n> <出力.json> [使い回す結果.json ...]
- 条件の並び（haizen_sim.conditions()）の番号を n で割った余りが k のものだけ回す
- 使い回す結果に同じ条件（同じ前提）があれば回さない。100条件ごとに出力へ途中経過を書く"""
import json, os, sys
from multiprocessing import Pool
import haizen_sim as h

k, n, out = int(sys.argv[1]), int(sys.argv[2]), sys.argv[3]
common = json.loads(json.dumps(h.COMMON))
done = {}
for path in sys.argv[4:] + [out]:
    try:
        old = json.load(open(path, encoding="utf-8"))
        if old.get("common") == common and old.get("reps") == h.REPS:
            done.update({h.key(r): r for r in old["rows"]})
    except FileNotFoundError:
        pass
conds = [c for i, c in enumerate(h.conditions()) if i % n == k]
todo = [c for c in conds if h.key(c) not in done]
print(f"shard {k}/{n}: {len(conds)} conditions, {len(todo)} to run", flush=True)

def save():
    rows = [done[h.key(c)] for c in conds if h.key(c) in done]
    with open(out + ".tmp", "w", encoding="utf-8") as f:
        json.dump({"common": h.COMMON, "reps": h.REPS, "shard": [k, n], "rows": rows}, f, ensure_ascii=False)
    os.replace(out + ".tmp", out)

with Pool() as pool:
    for i, r in enumerate(pool.imap_unordered(h.run_condition, todo, chunksize=2), 1):
        done[h.key(r)] = r
        if i % 100 == 0:
            save(); print(f"  {i}/{len(todo)}", flush=True)
save(); print("done", flush=True)
```

#### run_shard.py の実行ログ（Claude のクラウド・2コア・約20分）

```
python3 run_shard.py 0 1 results_new.json results_reuse.json
```

```text
shard 0/1: 32850 conditions, 2628 to run
  100/2628
  200/2628
  300/2628
  400/2628
  500/2628
  600/2628
  700/2628
  800/2628
  900/2628
  1000/2628
  1100/2628
  1200/2628
  1300/2628
  1400/2628
  1500/2628
  1600/2628
  1700/2628
  1800/2628
  1900/2628
  2000/2628
  2100/2628
  2200/2628
  2300/2628
  2400/2628
  2500/2628
  2600/2628
done
```

### 結果をまとめる merge_p0.py

```python
"""run_shard.py の出力（results_new.json）を、前の results.json と同じ形（条件の並び・stores など）にまとめる（2026-10-29）。
使い方: python3 merge_p0.py   （haizen_sim.py と同じフォルダで）→ results_p0fix.json"""
import json, haizen_sim as h
R = json.load(open('results.json')); N = json.load(open('results_new.json'))
conds = list(h.conditions()); nk = {h.key(r): r for r in N['rows']}
assert len(nk) == len(conds) == len(R['rows'])
out = dict(R); out['rows'] = [nk[h.key(c)] for c in conds]
out['stores'] = json.loads(json.dumps(h.STORES))
assert out['common'] == N['common'] and out['reps'] == N['reps']
old = {h.key(r): r for r in R['rows']}
ch = {}
for r in out['rows']:
    if old[h.key(r)] != r:
        ch[r['store']] = ch.get(r['store'], 0) + 1
print('changed', ch)
json.dump(out, open('results_p0fix.json', 'w'), ensure_ascii=False)
```

#### merge_p0.py の出力

```text
changed {'fam_p0': 2628}
```

### 直す前と後の②の試算を比べた compare_p0_site.py

```python
"""②の試算を、T06 を動かす前（results.json）と後（results_p0fix.json）で比べる（2026-10-29）
使い方: python3 compare_p0_site.py   （haizen_sim.py と同じフォルダで）"""
import json, haizen_sim as h
A = {h.key(r): r for r in json.load(open('results.json'))['rows']}
B = {h.key(r): r for r in json.load(open('results_p0fix.json'))['rows']}
ch = {}
for k in B:
    if A[k] != B[k]:
        ch[k[0]] = ch.get(k[0], 0) + 1
print(ch)
for st in (1, 2, 3):
    for rb in (0, 1, 2):
        c = {'store': 'fam_p0', 'staff': st, 'robots': rb, 'arrivals_per_h': 19, 'mode': 'serve', 'trays': 3 if rb else 1, 'fragile_by': 'any', 'registers': 1}
        a = A[h.key(c)]; b = B[h.key(c)]
        print(st, rb, ' '.join(f"{m}:{a[m]:.2f}→{b[m]:.2f}" for m in ('entry_wait_mean', 'staff_wait_mean', 'dish_wait_mean', 'pay_wait_mean', 'groups')))
```

#### compare_p0_site.py の出力

```text
{'fam_p0': 2628}
1 0 entry_wait_mean:22.64→22.00 staff_wait_mean:19.71→19.26 dish_wait_mean:1.81→1.78 pay_wait_mean:3.93→3.79 groups:36.62→36.25
1 1 entry_wait_mean:15.37→14.97 staff_wait_mean:12.51→12.43 dish_wait_mean:0.76→0.77 pay_wait_mean:3.99→3.85 groups:38.42→37.88
1 2 entry_wait_mean:13.94→12.60 staff_wait_mean:11.96→11.13 dish_wait_mean:0.38→0.37 pay_wait_mean:4.16→4.27 groups:37.50→36.83
2 0 entry_wait_mean:2.68→2.65 staff_wait_mean:1.53→1.59 dish_wait_mean:0.60→0.61 pay_wait_mean:1.31→1.41 groups:37.42→38.10
2 1 entry_wait_mean:2.44→1.69 staff_wait_mean:0.83→0.71 dish_wait_mean:0.94→0.94 pay_wait_mean:1.30→1.30 groups:38.73→38.25
2 2 entry_wait_mean:1.60→1.17 staff_wait_mean:0.62→0.55 dish_wait_mean:0.40→0.39 pay_wait_mean:1.25→1.12 groups:37.48→36.40
3 0 entry_wait_mean:1.03→0.73 staff_wait_mean:0.28→0.25 dish_wait_mean:0.22→0.22 pay_wait_mean:0.54→0.53 groups:36.20→36.40
3 1 entry_wait_mean:1.38→1.24 staff_wait_mean:0.33→0.30 dish_wait_mean:0.94→0.92 pay_wait_mean:0.65→0.69 groups:39.27→38.12
3 2 entry_wait_mean:1.32→1.31 staff_wait_mean:0.25→0.28 dish_wait_mean:0.41→0.41 pay_wait_mean:0.66→0.66 groups:38.10→38.35
```

スタッフ2人・19組/時（Unity で回す条件）の入店待ちは、0台2.68→2.65分・1台2.44→1.69分・2台1.60→1.17分になりました。丸テーブルを寄せて上の段への道が短くなった分、ロボットがいる条件の入店待ちが縮んでいます。

### ページの②だけを差し替える update_page_p0.py

```python
"""②の店の形を直したとき（2026-10-29）、公開中の試算のページの②だけを差し替える。
使い方: python3 update_page_p0.py <公開中のページ> <新しい results.json> <前の p0 の店の形> <新しい p0 の店の形> <新しい summary.json> <出力するページ>
- const D の r（結果）：②（fam_p0）の行だけが変わっていることを確かめてから、全部を新しい結果に入れ替える
- const D の stores.fam_p0：卓までの距離（dist_m・dist_mean）を新しい値に
- const D の plans.fam_p0：②は右の丸テーブル（T06）の位置が変わったので、平面図をまるごと作り直す
  （作り方は build_page_v23.py と同じ。前の店の形から作った平面図が、公開中のページと同じになることを先に確かめる）
- const D の layout_generation：新しい版の番号に
ほかの店・費用の欄・画面の文は変えない"""
import json, sys
import haizen_sim as h

live, res, old_lay, new_lay, summ, out = sys.argv[1:7]
s = open(live, encoding="utf-8").read()
N = json.load(open(res, encoding="utf-8"))
assert N["common"] == json.loads(json.dumps(h.COMMON))
lines = [l for l in s.split("\n") if l.startswith("const D = ")]
assert len(lines) == 1
D = json.loads(lines[0][len("const D = "):].rstrip(";"))
cond = D["k"][:8]
mets = D["k"][8:-1]
conds = list(h.conditions())
assert len(N["rows"]) == len(conds) == len(D["r"])
rows, changed = [], {}
for c, r, o in zip(conds, N["rows"], D["r"]):
    assert all(r[k] == c[k] for k in cond)
    row = [r[k] for k in cond] + [round(r[k], 3) for k in mets] + [1 if r["staff_wait_mean"] >= h.NG_MIN else 0]
    assert o[:8] == row[:8]
    if o != row:
        changed[c["store"]] = changed.get(c["store"], 0) + 1
    rows.append(row)
print("結果が変わった行:", changed)
assert set(changed) <= {"fam_p0"}, changed
D["r"] = rows

st = h.STORES["fam_p0"]
D["stores"]["fam_p0"]["dist_m"] = list(st["dist_m"])
D["stores"]["fam_p0"]["dist_mean"] = round(sum(st["dist_list"]) / len(st["dist_list"]), 1)
assert D["stores"]["fam_p0"]["tables"] == st["tables"] == 19
print("②の距離:", D["stores"]["fam_p0"]["dist_m"], D["stores"]["fam_p0"]["dist_mean"])

q = lambda a: [round(v, 2) for v in a]
def plan(path):
    L = json.load(open(path, encoding="utf-8"))["layout"]
    W, Dd = L["outer"]["w"], L["outer"]["d"]
    return json.loads(json.dumps({
        "w": W, "d": Dd,
        "outline": L.get("outline") or [[0, 0], [W, 0], [W, Dd], [0, Dd]],
        "rooms": [q(r["rect"]) + [r["kind"], r["label"]] for r in L["rooms"] if r["kind"] != "outside"],
        "walls": [q(w["rect"]) for w in L["walls"]],
        "tables": [q([t["x"], t["y"], t["x"] + t["w"], t["y"] + t["h"]]) + [t["seats"]] for t in L["tables"]],
        "dish": [q(d["rect"]) for d in L["dish_up"]],
        "standby": q(L["robot_standby"]["rect"]),
        "ent": [L["entrance"]["side"], L["entrance"]["a0"], L["entrance"]["a1"]],
    }))
assert plan(old_lay) == D["plans"]["fam_p0"], "前の店の形から作った平面図が公開中のページと違う"
D["plans"]["fam_p0"] = plan(new_lay)
print("②の平面図を作り直した（卓", len(D["plans"]["fam_p0"]["tables"]), "）")

gens = {g["generation"] for g in json.load(open(summ, encoding="utf-8"))}
assert len(gens) == 1
D["layout_generation"] = gens.pop()
s = s.replace(lines[0], "const D = " + json.dumps(D, ensure_ascii=False, separators=(",", ":")) + ";")
open(out, "w", encoding="utf-8").write(s)
print("書いた:", out, "版", D["layout_generation"])
```

#### ページの差し替えと、全画面の確かめの出力

```
python3 update_page_p0.py page_before.html results_p0fix.json p0_memory.json（直す前） p0_memory.json（直した後） summary.json page_check.html
node test_page_v28.js page_check.html
```

```text
結果が変わった行: {'fam_p0': 2628}
②の距離: [2.5, 13.8] 8.5
②の平面図を作り直した（卓 19 ）
書いた: page_check.html 版 08db8a0d067c
rendered 37800 / レジが詰まるが出た画面 7083 / 回らないが出た画面 5913 / 5台以上の注意 10800
公開中のページと同じ
```

### Unity が読む条件を書き出す export_params.py（②を足した版・全文）

```python
"""試算（haizen_sim.py）の条件と店の回し方の値を、Unity が読む JSON に書き出す（2026-10-22。v2.8 で2026-10-25 にレジの数を足した）。

「何について正か」（unity_design_v0.md の 0 章）で、条件と店の回し方の決まり・時間・数字の定義はサイトが正。
Unity はこの JSON を読み、値を手で写さない（LOG359 のずれ9「値の手写し」をなくすため）。

使い方: python3 export_params.py results.json <出力先>   （出力先は p2m-site の public/sim/serving-robot-params.json）
- common：店に共通の値。role が "unity_measures" の値は Unity で測ってサイトに戻すための仮の値なので、Unity は読まない
- stores：Unity で回す店（fam_p1・fam_p5・fam_p2・fam_p3・fam_p4・fam_p0）の値。registers はレジの数（v2.8）
- unity_conditions：Unity で回す条件（店ごとに3つ。③⑦④⑤⑥②で18条件）と、同じ条件の試算の結果（40回の平均）。Unity の店はレジの内側に店員が1人だけなので、レジは1つ
"""
import json
import sys

import haizen_sim as h

res_path, out = sys.argv[1], sys.argv[2]
R = json.load(open(res_path, encoding="utf-8"))
gen = {g["generation"] for g in json.load(open(h.LAYOUT_DIR + "/summary.json", encoding="utf-8"))}
assert len(gen) == 1, gen

ROLE = {
    "robot_speed": "unity_measures", "pause_rate": "unity_measures", "pause_s": "unity_measures", "stuck_rate": "unity_measures",
    "hop_m": "site_only",          # 試算の近似（1往復で複数卓を回るときの寄り道）。Unity は実際の道を走るので使わない
    "sustain": "site_only", "warmup_min": "site_only", "util_sample_s": "site_only", "model": "site_only",
}
NOTE = {
    "unity_measures": "Unity で測ってサイトに戻すための仮の値。Unity は読まない",
    "site_only": "試算の中だけの設定。Unity は使わない",
    "site_rule": "サイトが正。Unity はこの値を使う",
}
common = {k: {"value": v, "role": ROLE.get(k, "site_rule")} for k, v in h.COMMON.items()}

UNITY_STORES = ["fam_p1", "fam_p5", "fam_p2", "fam_p3", "fam_p4", "fam_p0"]   # ④は2026-10-27に追加（スタッフ2人・28組/時）。⑤は2026-10-28に追加（スタッフ4人・46組/時）。⑥も2026-10-28に追加（スタッフ3人・38組/時）。②も2026-10-29に追加（スタッフ2人・19組/時。同じ日に T06 を右へ1.0m 動かして②だけ計算し直した）
UNITY_REGISTERS = 1
stores = {}
for k in UNITY_STORES:
    s = dict(h.STORES[k])
    stores[k] = s

conds = []
rows = {h.key(r): r for r in R["rows"]}
for k in UNITY_STORES:
    s = h.STORES[k]
    staff = s["staff"][1]           # 真ん中の人数
    arr = s["arrivals"][1]          # 普通
    for robots in (0, 1, 2):
        c = {"store": k, "staff": staff, "robots": robots, "arrivals_per_h": arr, "mode": "serve",
             "trays": 3 if robots else 1, "fragile_by": "any",   # ロボット0台の試算は trays=1 で持っている（使い方・段の数は関係ない）
             "registers": UNITY_REGISTERS}
        r = rows[h.key(c)]
        conds.append({"condition": c, "site_result": {m: r[m] for m in r if m not in c}})

D = {
    "meta": {
        "schema_version": "serving-robot-params/0.4",
        "model": h.COMMON["model"], "reps": h.REPS, "ng_min": h.NG_MIN, "layout_generation": gen.pop(),
        "source": "p2m-site の public/sim/serving-robot.html と同じ試算（haizen_sim.py）と結果（results.json）",
        "roles": NOTE,
        "time_window": "空の店から始め、peak_min 分だけ選んだペースで来客し、全員が帰るまで回す（max_extra_min で打ち切り）",
        "registers": "会計はレジ1つにつき1組ずつ（pay_s 秒）。食べ終えた組は卓に座ったまま順番を待つ。Unity の条件はすべてレジ1つ（v2.8）",
        "metrics": {
            "entry_wait_mean": "入店待ち：店に来てから案内されて卓に着くまで（分）",
            "full_wait_mean": "そのうち満席で待った時間（分）",
            "staff_wait_mean": "そのうち席は空いているのに片付け・案内が追いつかず待った時間（分）。ng_min 以上なら「店が回らない」",
            "dish_wait_mean": "料理ができてから卓に届くまで（分）", "dish_wait_p90": "同じく上位10%の境目（分）",
            "cold_share": "cold_min 分を超えて届いた皿の割合", "turn_mean": "客が帰ってから卓が使えるまで（分）",
            "walk_km_per_staff": "スタッフ1人が歩いた距離（km）", "staff_util": "スタッフの手がふさがっている割合",
            "robot_util": "ロボットがふさがっている割合", "robot_share": "ロボットが運んだ皿の割合",
            "rescues": "立ち往生でスタッフが動かしに行った回数", "pauses": "一時停止の回数", "groups": "入れた組の数",
            "pay_wait_mean": "食べ終えてから会計が始まるまで（分）。レジの順番とスタッフの手が空くのを待つ（v2.8）",
        },
    },
    "common": common,
    # 2026-10-27 エイイチと決めた回し方の決まり（案B）。試算の数字には効かない（試算の料理は卓の区別がなく、受け渡し口で積む時間も0秒で順番待ちがないため）。
    # 受け渡し口でのロボットどうしのぶつかりは通路で起きることなので Unity が測る。Unity はこの値を使う（切り替えで入れ、まず④で確かめる）
    "unity_rules": {
        # 2026-10-28 エイイチと決めた：待機場所へ戻るを標準に。案B（受け渡し口は1台ずつ・同じ卓は1台）は切に戻す
        # （④・③⑦の夜で、待機場所が受け渡し口から1.5m以内にあるため2台が互いを待ち、往復が減ったため。待機場所との距離の決め方を考え直すまで使わない）
        "standby_return": {"value": True, "role": "site_rule",
                           "note": "往復を終えたロボットは、受け渡し口の点で止まらず、店の形の RobotStandby（1台に1つ）へ下がって待つ"},
        "pass_one_robot": {"value": False, "role": "site_rule",
                           "note": "（切）受け渡し口の前に入れるロボットは1台だけ。前の1台が出発点から pass_clear_m 離れるまで、次の1台は待機場所で待つ"},
        "pass_clear_m": {"value": 1.5, "role": "site_rule", "note": "仮の値（pass_one_robot が切のあいだは使わない）"},
        "same_table_one_robot": {"value": False, "role": "site_rule",
                                 "note": "（切）その卓へ向かっているロボットがいる間は、その卓の料理を別のロボットに積まない"},
    },
    "stores": stores,
    "unity_conditions": conds,
}
json.dump(D, open(out, "w", encoding="utf-8"), ensure_ascii=False, indent=1)
print(out, len(conds), "conditions / generation", D["meta"]["layout_generation"])
for c in conds:
    print(" ", c["condition"], {m: c["site_result"].get(m) for m in ("entry_wait_mean", "staff_wait_mean", "dish_wait_mean", "pay_wait_mean")})
```

### 書き出した条件を、公開中のものと比べた compare_params.py

```python
"""書き出し直した serving-robot-params.json（params_new.json）を、公開中のもの（引数）と比べる（2026-10-29）"""
import json, sys
a = json.load(open(sys.argv[1])); b = json.load(open('params_new.json'))
print('meta diff', [k for k in a['meta'] if a['meta'][k] != b['meta'][k]], b['meta']['layout_generation'])
print('common', a['common'] == b['common'], 'rules', a['unity_rules'] == b['unity_rules'])
print('stores diff', [k for k in b['stores'] if a['stores'].get(k) != b['stores'][k]])
print('conds diff idx', [i for i, (x, y) in enumerate(zip(a['unity_conditions'], b['unity_conditions'])) if x != y], len(b['unity_conditions']))
for c in b['unity_conditions'][15:]:
    r = c['site_result']; print(c['condition']['robots'], {m: round(r[m], 2) for m in ('entry_wait_mean', 'staff_wait_mean', 'dish_wait_mean', 'pay_wait_mean')})
```

#### compare_params.py の出力

```text
meta diff ['layout_generation'] 08db8a0d067c
common True rules True
stores diff ['fam_p0']
conds diff idx [15, 16, 17] 18
0 {'entry_wait_mean': 2.65, 'staff_wait_mean': 1.59, 'dish_wait_mean': 0.61, 'pay_wait_mean': 1.41}
1 {'entry_wait_mean': 1.69, 'staff_wait_mean': 0.71, 'dish_wait_mean': 0.94, 'pay_wait_mean': 1.3}
2 {'entry_wait_mean': 1.17, 'staff_wait_mean': 0.55, 'dish_wait_mean': 0.39, 'pay_wait_mean': 1.12}
```

サイトへの反映は p2m-site の commit 07e09c7（29ファイル）です。公開後、params の版の番号が 08db8a0d067c・条件18件、ページの版の番号も 08db8a0d067c、Unity 用の JSON の T06 が x 6.85〜7.95 になったことを確かめました。


## 作業ログ ― 直した②を建て直し、合格したので続けて夜の30回を回した（依頼24）

1つの依頼の中で、建て直し・確かめの3回・夜の30回を続けて回すようにしました。確かめで丸テーブルのまわりの60秒の止まりが0でなければ、夜は回さずに止まって報告します。台帳は依頼の前に退避しました（634行・md5 738553fac6a9bd2732cf6ad19818f16b）。

### 依頼文：直した②を建てて確かめ、夜を回す（20261029_24）

````markdown
---
作業フォルダ: /Users/shimazueiichi/Robotics_UX/ServiceSim
上限時間: 180
---
# 依頼：直した②（fam_p0）を建て直して確かめの3回を回し、合格なら続けて②の夜（30回）を回す（2026-10-29）

依頼 23 の報告（20261029_1732_p0_build_check.txt）の「決めてほしいこと」への答え（エイイチと決めた）：
- 2：丸テーブル T05・T06 のあいだ → サイトで直した（下）。記憶の店は昔の記憶なので、ロボットが回れない所は変えてよい
- 1：②の夜は、直した②の確かめが合格なら、この依頼の中で続けて回す
- 3：待機場所1の中の止まりは、今は店の形を直さず、夜の種10個で数を見る（③⑦④⑥と同じ形のため）
- 4：入れた組の数が試算より少ない件は、先に調べず、夜の種10個で見る
- 5：卓の部品の読み方の広げ方（3章）はこのままでよい。知らない名前の裏の部屋を「kind = back なら事務所の箱」にしたのもこのまま
- 6：T19 の右の席に着く点・レジの内側の南北 0.52 m は、今は記録だけ

サイト（正）はもう直した（p2m-site commit 07e09c7。店の形の版 dffc100b269c → 08db8a0d067c）。
- ②の右の丸テーブル T06 を右へ1.0m（x 5.85〜6.95 → 6.85〜7.95）。丸テーブル2つの間 1.1m → 2.1m。T05 にロボットが止まっていても横に 1.06m 残る。T06 の右とパントリーの壁の間は 2.55m → 1.55m
- ②の止まる位置が変わった卓：T01 (3.162, 13.362) → (3.388, 14.238)・T04 (7.038, 14.238) → (6.363, 14.212)・T05 (5.363, 12.812) → (5.538, 12.812)・T06 (6.788, 11.862) → (7.788, 11.862)。T03 は同じ
- ②の試算だけ計算し直した（ほかの店の数字は変わっていない）。③④⑤⑥⑦の店の形は版の番号だけ変わった
- `public/sim/serving-robot-params.json`：meta.layout_generation が 08db8a0d067c、unity_conditions 18件のまま。変わったのは stores.fam_p0 と②の3条件（15〜17番）の site_result だけ
- ② スタッフ2人・19組/時の試算（入店待ち、分）：0台 2.65・1台 1.69・2台 1.17
- 台帳の退避は Claude が済ませた：`/Volumes/KIOXIA/r2r2r-data/service_sim/unity/archive/unity_ledger_v1_pre_p0fix_20261029/unity_ledger_v1.csv`（634行・md5 738553fac6a9bd2732cf6ad19818f16b）

## 始める前に確かめること（違えば手を止めて報告）

1. Unity エディタが起動していない（起動していたら閉じずに報告して終わる）
2. /Volumes/KIOXIA がマウントされている。鍵ファイル unity_ledger_v1.lock がない
3. 台帳の md5 が上の退避と同じ
4. ServiceSim の保留が 0（cs:39 head）
5. https://pixelstomotors.com/sim/serving-robot-params.json の meta.layout_generation が 08db8a0d067c、unity_conditions が18件（違えば数分おきに取り直す。30分たっても違えば報告して終わる）

## A. 建て直して確かめる

1. サイトの params と6店の店の形（`public/sim/layouts/unity/` の `.json` と `_map.json`、summary.json）を、今までと同じやり方でプロジェクトに写す（手で値を写さない）。generation が 08db8a0d067c でそろっているか確かめる。③④⑤⑥⑦は、前の写し（cs:39）と版の番号以外が同じであることを確かめる
2. ②を cs:39 と同じコード・同じ規則で建てる（JSON Store「② を建てて確かめる」・Map Planner「② 確かめ A」）。コードは変えない。②の店の形のせいで建てられないところがあっても、Unity 側で形を直さない（直すならサイトが先）
3. check-in して、画面なしの実行ファイルを作り直す（保留 0）
4. 確かめの3回を回す：② × ロボット0・1・2台 × 種0、今の標準のまま。ラベル `p0fixcheck`。同時に回す本数は4のまま
   - 台帳 634 → 637 行（追記だけ）。先頭634行の md5 が退避と同じか確かめる

**合格の条件（全部満たせば B へ進む。1つでも違えば B は回さずに報告して終わる）**
- 3回とも completed・全員帰った
- 2台の回で、丸テーブル T05・T06 のまわり（x 4.75〜6.85・y 11.3〜14.0）の60秒の「動けなくなった」が 0

## B. ②の夜（30回）

A が合格なら、台帳の行数と md5 を記録してから、続けて回す。

```
python3 tools/make_queue.py --stores fam_p0 --out queue_p0.json
python3 tools/night_runner.py --queue queue_p0.json --parallel 4 --night 20261105 --record-name 20261105_p0
```

- 夜の名前は 20261105。記録は night/20261105_p0/ に置く。オプションの名前が違えば、同じ意味になるように合わせる
- 並ぶのは 30 回（② × 0・1・2台 × 種0〜9・すれ違い入・待機場所へ戻る 入・案B 切）であることを、回す前に queue_p0.json で確かめる。30 回でなければ回さずに報告
- 回している間は、ほかの作業をしない。Assets・tools・設定ファイルを開かない・変えない。Unity を開かない
- Ctrl+C で止めない。途中で止まっても、同じ夜を回し直さない（そのまま報告する）
- 終わったら queue_p0.json を作業フォルダに残さない

## 変えないもの

- 店の回し方・人とロボットの動き・速さ・Stiffness などの物理の設定・同時に回す本数（N=4）
- 台帳の列（59列）と今までの行。今までの night/ と出力の記録
- make_queue.py・night_runner.py・judge_night.py（何も指定しない make_queue は③⑦の60回のまま）

## 報告

依頼箱の結果に加えて、claude_code_reports に 2つ書く（場所：~/Library/Mobile Documents/com~apple~CloudDocs/デスクトップ/ADAPT DESIGN/じぶんの/PixelstoMotors/デジタルツイン学習R2R2R/サービスロボット導入シミュレーション/unity/claude_code_reports/）。

**20261029_HHMM_p0fix_build_check.txt（A）**
- 始める前の確かめ5つの結果
- 入れた cs 番号・build_id と保留の有無
- 建てて分かったこと（卓19・椅子とスツール・止まる位置・場所の点が置けたか。T06 を動かして変わったこと）
- 3回それぞれ：依頼 23 の報告の5章と同じ項目。依頼 23 の同じ回（p0check）と試算の値も並べる
- 2台の回の30秒以上の止まりの場所と理由：依頼 23 の報告の6章と同じ分け方（丸テーブルのまわりは x 4.75〜6.85・y 11.3〜14.0 に変える）
- 台帳の行数と先頭634行の md5
- 合格か（B へ進んだか）

**20261105_night_p0.txt（B。回したときだけ）**
- runner_log のまとめ（completed の回数・失敗・止まった回・最長の実時間）
- 台帳の行数（637 → 667 になるはず）と、B の前に記録した md5 と先頭637行が同じか
- 全員が帰らなかった回があれば、その回の名前（原因の調べはしない）
- 台数ごと（0・1・2台）の種10個の中央値と最小・最大：入店待ち・そのうち席は空いているのに待った時間・料理の待ち・会計待ち・入れた組の数・ロボットが運んだ皿の割合・往復の数・30秒以上の止まり（1往復あたり）・動けなくなった（60秒）・瞬間移動・打ち切り・卓を空けた・冷めた皿の割合。試算の値（params の site_result）も並べる
- 種ごとの入れた組の数と、試算の組の数（約36〜38組）との比
- 2台の30秒以上の止まりを、理由ごと・場所ごとに、種10個の合計で。場所は次の分け方（重なる所は上の方に数える）
  - 待機場所の四角の中（x 12.2〜14.6・y 5.1〜5.9）
  - 受け渡し口の点 (10.9, 5.45) から 2.5 m 以内（待機場所の中を除く）
  - 丸テーブルのまわり（x 4.75〜6.85・y 11.3〜14.0）
  - 仕切りの右端のすき間のまわり（x 7.5〜9.5・y 8.0〜9.6）
  - 奥の区画のそのほか（x が 9.5 m より左で、y が 9.0 m より上）
  - ドリンクバーのまわり（x 13.0〜21.5・y 2.6〜4.5）
  - 入口・レジのまわり（x 9.0〜14.0・y が 3.8 m より下）
  - そのほか（多い所があれば 2 m 四方のマスで上位3つ）
- ロボットを1台増やしたときの向き（入店待ち・料理の待ち）が、種の過半数で試算と同じか逆か（judge と同じ数え方）
- judge.md ができたか（②は基準がないので「基準なし」でよい。中身の判断はしない）
````

### 報告：20261029_1847_p0fix_build_check.txt

```text
====================================================================
直した②（fam_p0・T06 を右へ 1.0 m）を建て直して、1回ずつ回して確かめた
依頼：20261029_24_直した店2を建てて確かめ夜を回す.md
2026-10-29 18:47　check-in：cs:40　build_id cs40_20261029_1816（保留 0）
====================================================================

結論

  ・始める前の確かめ5つは、すべて合格だった。
  ・公開版（版 08db8a0d067c）の params と6店の店の形を cp で写した。版はすべてそろっていた。
    ③④⑤⑥⑦は前の写し（cs:39）と「版の番号」以外同じ。params は stores.fam_p0 と②の3条件（15〜17番）の site_result だけ違う。
  ・コードは変えていない。②は cs:39 と同じコード・同じ規則で建った。卓19・席88・確かめ A は全卓・待機場所3つとも道が引けた。
  ・確かめの3回（② × 0・1・2台 × 種0）は3回とも completed・全員帰った。
  ・2台の回で、丸テーブル T05・T06 のまわり（x 4.75〜6.85・y 11.3〜14.0）の 60 秒の「動けなくなった」は 0（前は 8）。
  ・合格の条件を満たしたので、B（②の夜 30 回）へ進んだ（別の報告 20261105_night_p0.txt）。
  ・台帳 634 → 637 行（追記だけ）。先頭 634 行の md5 は退避と同じ。


====================================================================
1. 始める前の確かめ（5つとも合格。18:10 ごろ）
====================================================================

  1. Unity エディタ：起動していない（Unity Hub だけが起動していた）
  2. /Volumes/KIOXIA：マウントされている。unity_ledger_v1.lock：なし
  3. 台帳 unity_ledger_v1.csv：634 行・md5 738553fac6a9bd2732cf6ad19818f16b（退避と同じ）
  4. ServiceSim の保留：0（cs:39 head）
  5. 公開中の serving-robot-params.json：meta.layout_generation 08db8a0d067c・unity_conditions 18 件（1回目の取得で合った）


====================================================================
2. 写したもの（A-1）
====================================================================

  写し元：https://pixelstomotors.com/sim/（2026-10-29 18:12 に curl で取得）
    控え：unity/site_copy_08db8a0d067c/（params・summary.json・unity/ の6店の JSON と地図・README.txt）
  版の番号：params の layout_generation、6店の JSON と地図の meta.generation、summary.json の6店がすべて 08db8a0d067c
  プロジェクトの前の写し（cs:39）との違い（JSON を読んで、項目ごとに比べた）
    p1・p2・p3・p4・p5 の JSON と地図：meta.generation だけ違う。それ以外の違い 0
    p0 の JSON：meta.generation・tables（T01・T03・T04・T05・T06）・routes が違う
      T06：footprint・parts・spots・stop が変わった（右へ 1.0 m）
      止まる位置：T01 (3.162, 13.362) → (3.388, 14.238)・T04 (7.038, 14.238) → (6.363, 14.212)・
                  T05 (5.363, 12.812) → (5.538, 12.812)・T06 (6.788, 11.862) → (7.788, 11.862)。T03 は同じ（dist だけ 12.56 → 12.12）
    p0 の地図：meta.generation・clear_mm・free_class・counts が違う
      counts 2（ふだんの道）125446 → 125788 / 1 35825 → 35555 / 0 576009 → 575937
    summary.json：6店の generation と、②の robot_dist_mean・robot_dist_max だけ違う
    params：meta.layout_generation・stores.fam_p0・unity_conditions の 15〜17 番の site_result だけ違う（ほかは同じ。条件は 18 件のまま）
      ② の試算（入店待ち）：0台 2.6471・1台 1.6909・2台 1.169（依頼の 2.65・1.69・1.17 と同じ）
  どれも cp でそのまま写した（手で値を写していない）。写したあと cmp でサイトの控えと同じことを確かめた。


====================================================================
3. 入れた cs・build_id
====================================================================

  check-in：cs:40（14 ファイル。params・summary.json・6店の JSON と地図。コード・.asset・シーンは変えていない）
  画面なしの実行ファイル：build_id cs40_20261029_1816 / unity_cs ServiceSim/cs:40 / pending_changes 空
                         Build Finished, Result: Success・error CS 0
  保留：check-in のあと 0。確かめの3回・夜のあとも 0。

  手で戻したもの（check-in していない）
    建てて確かめる処理で ProjectSettings/NavMeshAreas.asset・Mat_RobotKeepout.mat・StoreLayout_p0_memory.asset が
    変更ありになったので cm undo で戻した（.asset は中身が cs:39 と同じで、触っただけだった。NavMeshAreas は今までと同じ）。

  make_queue.py・night_runner.py・judge_night.py は変えていない。


====================================================================
4. ②を建てて分かったこと（JSON Store「② を建てて確かめる」・Map Planner「② 確かめ A」。どちらも画面なしのエディタで実行）
====================================================================

  数         卓：Unity 19 / JSON 19 / summary.json 19 で一致。席 88 で一致。細い通路 0 本。外寸 24 × 19.2 m
             地図のマスの数は JSON の counts と一致。合わないもの：なし
  卓の部品    椅子 58（椅子 52 ＋ スツール 6。Unity の数え方は「椅子」）・席に着く点 57・座る位置 88（前と同じ）
             丸い天板 2（T05・T06）は前と同じ作りで建った
  止まる位置  19 か所すべてロボット用の NavMesh の上（乗らない 0）。地図でも 19 卓すべて通れるマス
  道順       受け渡し口から全 19 卓、すべての区間がつながった。JSON の dist との差は平均 −0.24 m・最大 0.47 m（T17）。
             30% を超えた卓 0。狭い道を使う卓 0
  NavMesh    ロボット用 137.78 m2・人用 151.03 m2、どちらも「つながっていない面」0 m2
  席         入口 (11.0, 0.5) から全 19 卓の席に着く点まで歩ける（入れない卓 0）
  場所の点    25 か所すべて NavMesh に乗った（置けなかった所はない）。待機場所3つは地図で「ふだんの道」のマス
  確かめ A   引けない卓 0 / 19。待機場所3つとも道が引けた。長さの比 最小 0.979 / 平均 1.016 / 最大 1.041

  T06 を動かして変わったこと
    ・受け渡し口からの道（Unity）：T06 8.28 m（JSON 8.63）・T05 10.28 m（10.62）・T04 11.25 m（11.57）・
      T03 11.70 m（12.12）・T01 13.34 m（13.77）。差はどれも −0.3〜−0.4 m で、ほかの卓と同じくらい
    ・地図の「ふだんの道」のマスが 342 増えた（丸テーブル2つの間が通れるようになった分）
  前から残っている気づき（変わらず。依頼のとおり記録だけ）
    ・T19 の右の席に着く点 (23.7, 1.0) が通る半径 0.25 m の確かめで NavMesh に乗らない
    ・レジの内側：南北の歩ける幅 0.52 m（確かめが「入口が 0.7 m 未満」と出す）

  書き出し（unity/screens/）
    20261029_1813_map_planner_checkA_p0.txt・20261029_1813_map_plan_p0_memory.csv
    20261029_p0_memory_json_check.txt・20261029_p0_memory_table_dist.csv・20261029_family_v0_*（18:13）
    ※ 時刻の入らない名前のもの（20261029_p0_memory_json_check.txt など）は、依頼 23 の 17:12 ごろの書き出しを上書きした
      （同じ日・同じ名前で書き出す作りのため）。依頼 23 の数字は依頼 23 の報告に残っている。


====================================================================
5. 確かめの3回（② × 0・1・2台 × 種0・すれ違い入・待機場所へ戻る入・案B切・ラベル p0fixcheck・同時 4 本）
====================================================================

  python3 tools/make_queue.py --stores fam_p0 --seeds 0 --label p0fixcheck --out /tmp/p0f/queue_p0fixcheck.json
  python3 tools/night_runner.py --queue /tmp/p0f/queue_p0fixcheck.json --parallel 4 --night 20261029
      --label p0fixcheck --record-name 20261029_p0fixcheck
  出力 20261029_p0fixcheck_cs40_fam_p0_r{0,1,2}_s0_passon_sbret
  記録 night/20261029_p0fixcheck/（runner 終了コード 0・completed 3・失敗 0）
  judge.md：基準なし 3

  「今回 ／ 依頼 23 の p0check ／ 今回の試算（params の site_result）」の順。単位は分。割合は 0〜1
                                   0台                      1台                      2台
  最後まで回ったか                 completed                completed                completed
  全員帰ったか                     はい                     はい                     はい
  実時間                           2.3 ／ 2.4 分            2.4 ／ 2.5 分            2.4 ／ 2.5 分
  （参考）店の時間                 164.2 ／ 164.1 分        164.0 ／ 163.7 分        162.7 ／ 164.0 分
  入れた組の数                     31 ／ 31 ／ 38.1         31 ／ 31 ／ 38.25        31 ／ 31 ／ 36.4
  入店待ち                         1.35 ／ 1.33 ／ 2.65     1.17 ／ 1.21 ／ 1.69     1.22 ／ 1.45 ／ 1.17
   うち席は空いているのに待った     0 ／ 0 ／ 1.19           0 ／ 0 ／ 0.44           0 ／ 0 ／ 0.28
  料理の待ち                       0.73 ／ 0.68 ／ 0.61     1.03 ／ 0.95 ／ 0.94     0.54 ／ 0.94 ／ 0.39
  会計待ち                         0.84 ／ 0.80 ／ 1.41     0.58 ／ 0.72 ／ 1.30     0.88 ／ 1.16 ／ 1.12
  ロボットが運んだ皿の割合         0 ／ 0 ／ 0              1.000 ／ 0.987 ／ 0.979  1.000 ／ 0.974 ／ 1.000
  往復の数                         0 ／ 0                   63 ／ 63                 76 ／ 73
  30秒以上の止まり                 0 ／ 0                   2 ／ 1                   5 ／ 17
   （1往復あたり）                 0 ／ 0                   0.032 ／ 0.016           0.066 ／ 0.233
  動けなくなった（60秒）           0 ／ 0                   2 ／ 0                   2 ／ 12
  卓を空けた（逃がし弁）           0 ／ 0                   0 ／ 0                   0 ／ 0
  瞬間移動                         3 ／ 3                   10 ／ 8                  15 ／ 15
  打ち切り                         0 ／ 0                   0 ／ 0                   0 ／ 1
  （参考）あきらめた               2 ／ 3                   6 ／ 4                   4 ／ 12
  （参考）冷めた皿の割合           0 ／ 0 ／ 0              0.065 ／ 0.026 ／ 0.007  0 ／ 0.065 ／ 0
  （参考）待機場所へ戻った／出た   0 / 0                    63 / 63（前 63 / 63）    76 / 76（前 72 / 72）（戻れず受け渡し口へ 0）
  （参考）ドリンクバーで並んだ／あきらめた  50 / 2（前 52 / 2）  57 / 3（前 56 / 4）  49 / 3（前 51 / 4）
  ※ 「席は空いているのに待った」は依頼 23 と同じく blocked_wait（片付け待ち）で並べた。試算の列も blocked_wait_mean
  ※ 0台の瞬間移動 3 はロボットのいない回なので、人の側のもの
  ※ 試算の値は版が変わったので、依頼 23 の試算（2.68・2.44・1.60 など）と違う

  目立つ点（差の理由は調べていない）
    ・2台の回：30 秒以上の止まり 17 → 5、動けなくなった 12 → 2、料理の待ち 0.94 → 0.54 分（試算 0.39）。1台の回より料理の待ちが短くなった
    ・1台の回：動けなくなった 0 → 2（どちらも (8.77〜8.87, 6.04〜6.05)、スタッフ／お客さんとすれ違って 60 秒。受け渡し口から 2.1 m）
    ・入れた組の数は3回とも 31 組のまま（試算 36〜38 組）


====================================================================
6. 2台の回の 30 秒以上の止まり（5 回）の場所と理由
====================================================================

  受け渡し口の点 (10.9, 5.45) から 2.5 m 以内              4 回
   うち待機場所1の四角（x 12.2〜13.0・y 5.1〜5.9）の中     3 回（(12.24〜12.25, 5.51)。もう1台のロボット 2（2回とも 60 秒の「動けなくなった」）・分からない 1（44 秒・よける場所へ動いた））
   うち待機場所での止まりを除いた数                        1 回（(11.62, 5.28)：もう1台のロボット・32 秒・回り込んで動き出した）
  仕切りの右端のすき間のまわり（x 7.5〜9.5・y 8.0〜9.6）  1 回（(8.59, 8.31)：もう1台のロボット・31 秒・自分で動き出した）
  丸テーブルのまわり（x 4.75〜6.85・y 11.3〜14.0）         0 回（前は 8 回・すべて 60 秒）
  奥の区画のそのほか                                       0 回
  ドリンクバーのまわり（x 13.0〜21.5・y 2.6〜4.5）         0 回
  入口・レジのまわり（x 9.0〜14.0・y < 3.8）                0 回
  理由ごと（5 回）：もう1台のロボット 4・分からない 1
  動けなくなった 2 ＝ 待機場所1 の 2

  ロボットどうしが向かい合って止まった（face_stop）：23 回（待機場所 14・通路 9・受け渡し口 0）、いちばん長いもので 248 秒（待機場所）


====================================================================
7. 台帳
====================================================================

  行数：634 → 637（3 行足した。追記だけ。3行とも unity_cs ServiceSim/cs:40・layout_generation 08db8a0d067c）
  先頭 634 行の md5：738553fac6a9bd2732cf6ad19818f16b（退避と同じ）
  列は今までどおり（59 列）。鍵ファイルは残っていない
  B の前の台帳（637 行）の md5：415f1bb1dd41fab4f4480eef101f4856


====================================================================
8. 合格か
====================================================================

  合格。3回とも completed・全員帰った。2台の回の丸テーブル T05・T06 のまわりの 60 秒の「動けなくなった」は 0。
  → 続けて B（②の夜 30 回）を回した。結果は 20261105_night_p0.txt


====================================================================
9. 決めてほしいこと
====================================================================

  1. StoreLayout_p0_memory.asset の「写した日時」（fetchedAt）が前の版（17:05・dffc100b269c）のまま。
     建てるときの報告に古い版の字が出る（中身の JSON は 08db8a0d067c）。③⑤⑦なども前から同じ扱いで直していない。
     .asset の字を写し直すたびに直すかどうか。
  （夜の結果についての決めごとは 20261105_night_p0.txt に書いた）
```

### 報告：20261105_night_p0.txt

```text
====================================================================
②（fam_p0・直した版 08db8a0d067c）の夜 30 回
依頼：20261029_24_直した店2を建てて確かめ夜を回す.md
夜の名前 20261105　回した日時 2026-10-29 18:20〜18:47　build_id cs40_20261029_1816（ServiceSim/cs:40・保留 0）
====================================================================

結論

  ・30 回とも completed・全員帰った。失敗 0・止まった回 0・やり直し 0。最長の実時間 3.8 分。
  ・台帳 637 → 667 行（追記だけ）。先頭 637 行の md5 は B の前に記録したものと同じ。
  ・2台の 30 秒以上の止まりは種10個で 192 回（うち 60 秒の「動けなくなった」146）。
    多い順に、入口・レジのまわり 56・待機場所の中 54・受け渡し口のまわり 32・そのほか 29（ほぼ全部 x 8〜10・y 6〜8 のマス）・
    仕切りの右端のすき間 16。丸テーブルのまわりは 2（種4 の1件ずつ・同じ時刻）。
  ・入店待ちの中央値は 0台 1.96・1台 1.69・2台 2.10 分（試算 2.65・1.69・1.17）。
    種1〜4 は台数によらず入店待ちが 5〜10 分と長い（入れた組の数が多い種と少ない種がある。理由は調べていない）。
  ・ロボットを1台増やしたときの向きは、種の過半数で試算と逆になったものはない（judge と同じ数え方）。
    ただし 1→2台は入店待ち・料理の待ちとも「試算と同じ向き」が過半数に届いていない（同じ 2〜4・逆 4・変わらない 2〜4）。
  ・judge.md はできた（30 回とも「基準なし」）。


====================================================================
1. 回したもの
====================================================================

  python3 tools/make_queue.py --stores fam_p0 --out queue_p0.json
  python3 tools/night_runner.py --queue queue_p0.json --parallel 4 --night 20261105 --record-name 20261105_p0
  （オプションの名前は依頼のまま使えた）
  回す前に queue_p0.json を確かめた：30 回（fam_p0 × 0・1・2台 × 種0〜9・すれ違い入・待機場所へ戻る入・案B切）・
    店の形の版 08db8a0d067c・試算の版 v2.8
  出力 20261105_night_cs40_fam_p0_r{0,1,2}_s{0..9}_passon_sbret
  記録 /Volumes/KIOXIA/r2r2r-data/service_sim/unity/night/20261105_p0/（runner_log.txt・runs.csv・queue.json・judge.md・judge.csv・logs）
  終わったあと、作業フォルダの queue_p0.json は消した（記録の queue.json は night/20261105_p0/ に残っている）。
  回している間は、ほかの作業をしていない。Unity は開いていない。保留は回したあとも 0。


====================================================================
2. runner_log のまとめ
====================================================================

  completed 30 回 / 失敗 0 / 止まった（stopped）0 / やり直し 0（30 回とも1回目で終わった）/ 終了コード すべて 0
  実時間：最短 2.8 分・平均 3.4 分・最長 3.8 分（2台 種6・226.9 秒。上限 90 分）
  runner の終了コード 0


====================================================================
3. 台帳
====================================================================

  行数：637 → 667（30 行足した。追記だけ。30 行とも unity_cs ServiceSim/cs:40・layout_generation 08db8a0d067c・completed）
  B の前に記録した md5（637 行）：415f1bb1dd41fab4f4480eef101f4856
  今の台帳の先頭 637 行の md5：415f1bb1dd41fab4f4480eef101f4856（同じ）
  列は 59 列のまま。鍵ファイルは残っていない


====================================================================
4. 全員が帰らなかった回
====================================================================

  なし（30 回とも全員帰った）


====================================================================
5. 台数ごとの種10個（中央値［最小〜最大］／試算）
====================================================================

  単位は分。割合は 0〜1。試算は params の site_result（種によらず同じ値）
                                 0台                          1台                           2台
  入店待ち                       1.96［1.25〜9.03］／2.65     1.69［1.17〜8.13］／1.69      2.10［1.22〜9.91］／1.17
   うち席は空いているのに待った   0.77［0.18〜5.60］／1.59     0.43［0.09〜4.52］／0.71      0.77［0.14〜5.71］／0.55
    （片付け待ちだけ blocked）    0.39［0〜5.24］／1.19        0.11［0〜4.09］／0.44         0.10［0〜5.21］／0.28
  料理の待ち                     0.89［0.56〜1.06］／0.61     1.04［0.92〜2.80］／0.94      1.04［0.54〜2.21］／0.39
  会計待ち                       1.13［0.61〜1.60］／1.41     1.06［0.52〜2.04］／1.30      1.34［0.52〜1.65］／1.12
  入れた組の数                   36.5［26〜48］／38.1         36.5［26〜48］／38.25         36.5［26〜48］／36.4
  ロボットが運んだ皿の割合       0［0〜0］／0                 0.956［0.633〜1.000］／0.979  0.967［0.900〜1.000］／1.000
  往復の数                       0                            64［50〜83］                  77.5［66〜101］
  30秒以上の止まり               0                            2［0〜28］                    18.5［3〜38］
   （1往復あたり）               0                            0.028［0〜0.560］             0.210［0.040〜0.409］
  動けなくなった（60秒）         0                            0［0〜23］                    12.5［2〜29］
  瞬間移動                       1.5［0〜3］                  9［6〜15］                    13.5［3〜24］
  打ち切り                       0                            0［0〜4］                     1.5［0〜6］
  卓を空けた（逃がし弁）         0                            0                             0［0〜1］
  冷めた皿の割合                 0［0〜0］／0                 0.041［0〜0.178］／0.007      0.055［0〜0.175］／0
  （参考）あきらめた             2［1〜7］                    3.5［1〜7］                   10.5［1〜23］
  （参考）待機場所へ戻った       0                            64［46〜83］                  77［64〜96］（戻れず受け渡し口へ 0）
  （参考）向かい合って止まった   0                            0                             23.5
  ※「席は空いているのに待った」は judge と同じ staff_wait（片付け待ち＋案内待ち）で並べた。
    依頼 23・確かめの報告で使った blocked_wait（片付け待ちだけ）も下の行に並べた。

  種ごとの、1台・2台の止まり（30 秒以上／動けなくなった／打ち切り／入店待ち）
    1台：種0 2/2/0/1.17・種1 28/23/4/8.13・種2 6/5/0/6.42・種3 2/0/0/5.61・種4 6/6/1/7.56・
         種5 0/0/0/1.27・種6 0/0/0/1.20・種7 0/0/0/1.22・種8 0/0/0/1.38・種9 2/0/0/2.00
    2台：種0 3/2/0/1.22・種1 18/12/1/7.70・種2 38/29/6/9.91・種3 23/20/3/8.31・種4 19/13/0/7.17・
         種5 29/24/4/1.36・種6 27/21/2/1.71・種7 9/7/0/1.23・種8 11/6/0/1.28・種9 15/12/2/2.48


====================================================================
6. 種ごとの入れた組の数と、試算との比
====================================================================

  入れた組の数は 0・1・2台で種ごとに同じだった（同じ種は同じ組が来る）。
  試算の組の数：0台 38.1・1台 38.25・2台 36.4
           組   ÷38.1（0台）  ÷38.25（1台）  ÷36.4（2台）
    種0    31     0.81          0.81           0.85
    種1    37     0.97          0.97           1.02
    種2    48     1.26          1.25           1.32
    種3    40     1.05          1.05           1.10
    種4    41     1.08          1.07           1.13
    種5    32     0.84          0.84           0.88
    種6    31     0.81          0.81           0.85
    種7    26     0.68          0.68           0.71
    種8    36     0.94          0.94           0.99
    種9    39     1.02          1.02           1.07
    中央値 36.5   0.96          0.95           1.00
  確かめで見た「31 組」は種0 の値で、種10個の中央値は 36.5 組（試算の 0.95〜1.00 倍）。
  種1〜4（37〜48 組）で入店待ちが 5〜10 分と長くなる傾向が台数によらず出ている（調べていない）。


====================================================================
7. 2台の 30 秒以上の止まり（種10個の合計 192 回。うち 60 秒の「動けなくなった」146）
====================================================================

  場所ごと（重なる所は上の方に数えた）            回数   うち動けなくなった   理由
  待機場所の四角の中（x 12.2〜14.6・y 5.1〜5.9）   54     37                  もう1台のロボット 54
  受け渡し口 (10.9, 5.45) から 2.5 m 以内           32     24                  もう1台のロボット 19・スタッフとすれ違った 11・人が立ち止まっていた 2
  丸テーブルのまわり（x 4.75〜6.85・y 11.3〜14.0）   2      2                  もう1台のロボット 2
                                                                              （種4 の 63 分ごろ、(6.38, 12.71) と (6.71, 11.81) で2台が同時に）
  仕切りの右端のすき間（x 7.5〜9.5・y 8.0〜9.6）    16     10                  もう1台のロボット 11・スタッフとすれ違った 4・分からない 1
  奥の区画のそのほか（x < 9.5・y > 9.0）             1      0                  もう1台のロボット 1
  ドリンクバーのまわり（x 13.0〜21.5・y 2.6〜4.5）   2      2                  もう1台のロボット 2
  入口・レジのまわり（x 9.0〜14.0・y < 3.8）        56     48                  人が立ち止まっていた 35・もう1台のロボット 16・スタッフとすれ違った 2・
                                                                              お客さんとすれ違った 2・分からない 1
                                                                              （ほとんどが (12.97〜13.98, 1.10〜2.97)。種1〜4 だけで出た。
                                                                               同じ点で 60 秒を何度も続けている）
  そのほか                                          29     23                  もう1台のロボット 22・人が立ち止まっていた 4・スタッフとすれ違った 2・お客さんとすれ違った 1
    2 m 四方のマス：x 8〜10・y 6〜8 が 28 回（(8.29〜8.87, 6.26〜7.97)。受け渡し口の左で、仕切りのすき間の手前）／
                    x 6〜8・y 6〜8 が 1 回（(6.18, 6.17)）。3つ目のマスはない
  合計                                              192    146

  理由ごと（192 回）：もう1台のロボット 127・人が立ち止まっていた 41・スタッフとすれ違った 19・お客さんとすれ違った 3・分からない 2
  どう抜けたか（192 回）：動けなくなった 146・よける場所へ動いた 19・回り込んで動き出した 17・自分で動き出した 10

  （参考）1台の 30 秒以上の止まり 46 回：入口・レジのまわり 38（種1 で 26）・受け渡し口のまわり 7・そのほか 1。
          うち動けなくなった 36


====================================================================
8. ロボットを1台増やしたときの向き（judge と同じ数え方：5%・0.2 分より小さい変化は「変わらない」）
====================================================================

                         試算の向き（平均）             Unity の種10個：同じ／逆／変わらない   過半数で逆か
  0→1台 入店待ち         短くなる（2.65 → 1.69）        5 ／ 0 ／ 5                            いいえ
  0→1台 料理の待ち       長くなる（0.61 → 0.94）        7 ／ 0 ／ 3                            いいえ
  1→2台 入店待ち         短くなる（1.69 → 1.17）        2 ／ 4 ／ 4                            いいえ（逆 4/10）
  1→2台 料理の待ち       短くなる（0.94 → 0.39）        4 ／ 4 ／ 2                            いいえ（逆 4/10）
  judge.md の「ロボットを増やしたときの向きが、種の過半数で試算と逆」も「なし」で同じ。


====================================================================
9. judge.md
====================================================================

  できた：night/20261105_p0/judge.md（judge.csv も）。振り分けは 30 回とも「基準なし」（②の基準データがないため）。
  中身の判断はしていない。
  記録の表（Unity÷試算 の種の中央値）：入店待ち 0台 0.74・1台 1.00・2台 1.79／料理の待ち 1.46・1.11・2.63／
    席は空いているのに待った 0.48・0.61・1.41


====================================================================
10. 決めてほしいこと
====================================================================

  1. 2台の 60 秒の「動けなくなった」が種10個で 146（中央値 12.5／回）。多いのは
     入口・レジのまわり（48。種1〜4、(13.0〜14.0, 1.1〜3.0) で人が立ち止まっていた）、
     待機場所の中（37。もう1台のロボット）、受け渡し口のまわり（24）、受け渡し口の左 x 8〜10・y 6〜8（23）。
     丸テーブルのまわりは 2 に減った。どこを先に見るか（調べるか、店の形をサイトで直すか、このまま記録にするか）。
  2. 種1〜4 は台数によらず入店待ちが 5〜10 分と長く、1台・2台では入口・レジのまわりの止まりも同じ種で出ている。調べるかどうか。
  3. 1→2台で入店待ち・料理の待ちが試算と同じ向きになった種が過半数に届かない（逆 4/10）。印にはならないが、扱いをどうするか。
```

### 依頼箱の結果：20261029_24_直した店2を建てて確かめ夜を回す_20261029_1811.md

```markdown
# 結果：20261029_24_直した店2を建てて確かめ夜を回す

- 状態：完了
- 始めた時刻：2026-10-29 18:11
- 終わった時刻：2026-10-29 18:49（38分）
- 作業フォルダ：/Users/shimazueiichi/Robotics_UX/ServiceSim
- この続きを Claude Code で話すとき：作業フォルダで `claude --resume 084522e2-491f-4016-8e85-eeafbed32da3`

## Claude Code の報告

やったこと
- 始める前の確かめを5つ行い、すべて合格でした。Unity エディタは起動していない（Hub だけ）、KIOXIA はマウント済みで鍵ファイルなし、台帳は 634 行で md5 は退避と同じ、保留 0（cs:39 head）、公開中の params は版 08db8a0d067c・条件 18 件でした。
- サイトから params と6店の形を curl で取り、cp でプロジェクトに写しました。版はすべて 08db8a0d067c でそろっています。③〜⑦は版の番号以外に違いがなく、params で違うのは stores.fam_p0 と②の3条件の試算の値だけでした。
- ②を cs:39 と同じコードで建てました。「② を建てて確かめる」と「② 確かめ A」は、どちらも画面なしのエディタで実行しました。コードは変えていません。そのあと check-in して cs:40 とし、画面なしの実行ファイル（build_id cs40_20261029_1816）を作り直しました。保留は 0 です。
- 確かめの3回（ラベル p0fixcheck）を回し、合格したので、続けて②の夜 30 回（夜の名前 20261105、記録は night/20261105_p0/）を回しました。作業フォルダの queue_p0.json は消してあります。

結果
- 建てた②：卓 19・席 88 が JSON・summary.json と一致しました。止まる位置 19 か所はすべて NavMesh の上に乗り、確かめ A は全卓と待機場所3つとも道が引けました。T06 を動かした分、地図の「ふだんの道」のマスが 342 増えました。
- 確かめの3回：3回とも completed・全員帰りました。2台の回で丸テーブルのまわりの「動けなくなった」は 0（前は 8）なので合格です。2台の回全体では、30 秒以上の止まりが 17 → 5、動けなくなったが 12 → 2、料理の待ちが 0.94 → 0.54 分（試算 0.39）になりました。
- 台帳：確かめで 634 → 637 行、夜で 637 → 667 行になりました。どちらも追記だけで、先頭の md5 はそれぞれ記録と同じです。
- 夜 30 回：すべて completed・全員帰りました。失敗・止まった回・やり直しは 0 で、最長の実時間は 3.8 分です。
- 夜の入店待ち（種10個の中央値）：

| 台数 | Unity | 試算 |
|---|---|---|
| 0台 | 1.96 分 | 2.65 分 |
| 1台 | 1.69 分 | 1.69 分 |
| 2台 | 2.10 分 | 1.17 分 |

- 入れた組の数の中央値は 36.5 組で、試算の 0.95〜1.00 倍でした。確かめで見た 31 組は種0 だけの値です。種1〜4 は台数によらず、入店待ちが 5〜10 分と長くなりました。
- 2台の 30 秒以上の止まりは、種10個の合計で 192 回、うち 60 秒の「動けなくなった」が 146 回でした。場所ごとの内訳です。

| 場所 | 30 秒以上の止まり |
|---|---|
| 入口・レジのまわり | 56 |
| 待機場所の中 | 54 |
| 受け渡し口のまわり | 32 |
| そのほか（ほぼ全部が x 8〜10・y 6〜8 のマス） | 29 |
| 仕切りの右端のすき間 | 16 |
| 丸テーブルのまわり | 2 |

- ロボットを1台増やしたときの向きが、種の過半数で試算と逆になったものはありませんでした。ただし 1→2台では、入店待ち・料理の待ちとも逆が 4/10 でした。
- judge.md はできています。30 回とも「基準なし」です。
- 依頼 23 で書き出した screens の、時刻の入らない名前のファイル（20261029_p0_memory_json_check.txt など）は、今回の書き出しで上書きされました。依頼 23 の数字は、依頼 23 の報告に残っています。

変えたファイル
- cs:40 で check-in（コード・.asset・シーンは変えていません）：
  - Assets/ServiceSim/Experiment/serving-robot-params.json
  - Assets/ServiceSim/Store/Layouts/ の summary.json と6店の JSON・地図（12 ファイル）
- 建てる確かめで変更ありになった NavMeshAreas.asset・Mat_RobotKeepout.mat・StoreLayout_p0_memory.asset は、cm undo で戻しました。
- 足したもの：
  - unity/site_copy_08db8a0d067c/（サイトの控え）
  - claude_code_reports/20261029_1847_p0fix_build_check.txt
  - claude_code_reports/20261105_night_p0.txt

決めてほしいこと
1. 2台の「動けなくなった」146 回のうち、どこを先に見るかを決めてください。多いのは次の場所です。調べるか、サイトで店の形を直すか、このまま記録にするかも合わせて決めてください。
   - 入口・レジのまわり 48（種1〜4 で、人が立ち止まっていた）
   - 待機場所の中 37
   - 受け渡し口のまわり 24
   - 受け渡し口の左 x 8〜10・y 6〜8 が 23
2. 種1〜4 は台数によらず入店待ちが 5〜10 分と長くなります。これを調べるかどうかを決めてください。
3. 1→2台で、試算と同じ向きの種が過半数に届いていません（逆 4/10）。印にはならない数ですが、扱いをどうするか決めてください。
4. StoreLayout_p0_memory.asset の「写した日時」の字が、前の版（dffc100b269c）のままです。中身の JSON は新しい版です。今後、写し直すたびにこの字も直すかどうかを決めてください。
```

### 1台は試算とぴったり同じで、2台は1台より待ちが延びた

確かめの2台の回では、丸テーブルのまわりの60秒の止まりが8回から0回になり、30秒以上の止まりも17回から5回に減りました。合格の条件を満たしたので、Claude Code はそのまま夜の30回に進みました。18:20に始まり18:47に終わっています。

夜の入店待ちの中央値は、0台1.96分・1台1.69分・2台2.10分です。試算は2.65分・1.69分・1.17分で、1台は小数第2位まで同じでした。2台は、試算では1台より縮むのに、3Dの店では延びています。種ごとに見ると、1台から2台で入店待ちが試算と同じ向き（縮む）になった種は10個のうち2個、逆（延びる）が4個、変わらないが4個でした。

来る客の数は種ごとにばらつき（26〜48組）、中央値は36.5組で試算（36〜38組）とそろいました。確かめで31組と少なく見えたのは、種0だけのことです。

### 2台の止まりは、待合のまわり・待機場所の中・受け渡し口のまわりに集まった

【画像】LOG402_04_store2_night_stops.png 直した②の図面に、ロボット2台の夜（種10個）の30秒以上の止まり192回を場所ごとに色を分けて重ねた図。入口の右の待合のまわり56回、待機場所の中54回、受け渡し口から2.5m以内32回、パントリーの壁ぞいの仕切りの右端16回

| 場所 | 30秒以上の止まり | そのうち60秒動けなくなった | おもな理由 |
|---|---|---|---|
| 入口・レジのまわり（待合の前） | 56 | 48 | 人が立ち止まっていた 35 |
| 待機場所の中 | 54 | 37 | もう1台のロボット 54 |
| 受け渡し口から2.5m以内 | 32 | 24 | もう1台のロボット 19 |
| そのほか（受け渡し口の左、パントリーの壁ぞい） | 29 | 23 | もう1台のロボット 22 |
| 仕切りの右端のすき間 | 16 | 10 | もう1台のロボット 11 |
| 丸テーブルのまわり | 2 | 2 | もう1台のロボット 2 |
| ドリンクバーのまわり・奥の区画のそのほか | 3 | 2 | もう1台のロボット 3 |

いちばん多かった入口・レジのまわりは、x 13〜14m・y 1.1〜3.0m の、レジの右から右下の卓（T16）へ向かう通路です。待合（x 12.7〜13.9m・y 0〜0.5m）のすぐ上にあたり、案内を待つお客さんが立ち止まる所と、ロボットが右下の卓へ向かう道が重なっています。お客さんが多かった種1〜4だけで出ていて、同じ点で60秒を何度も続けていました。

受け渡し口の左（x 8.3〜8.9m・y 6.3〜8.0m）の29回は、パントリーの壁ぞいで、スタッフが待つ点（x 9.25m・y 6.3〜9.4m）の並びのすぐ横です。奥の区画へ行くロボットの道もここを通ります。

### 止まりを書き出したスクリプト p0_night_stops_dump.py（KIOXIA の r2r2r-data/service_sim/unity で実行）

```python
"""②の夜（20261105_p0）のロボット2台・種0〜9の回から、30秒以上の止まりを [x, y, 理由, どう抜けたか, 秒, 種] で書き出す（図にするため）。
使い方: KIOXIA の r2r2r-data/service_sim/unity で python3 p0_night_stops_dump.py <出力.json>"""
import csv, glob, json, sys
pts = []
for d in sorted(glob.glob("20261105_night_cs40_fam_p0_r2_s*_passon_sbret")):
    for r in csv.DictReader(open(d + "/stops.csv")):
        if float(r["duration_s"]) >= 30:
            pts.append([round(float(r["x"]), 2), round(float(r["z"]), 2), r["cause"], r["resolved"], round(float(r["duration_s"]), 1), d.split("_s")[-1].split("_")[0]])
json.dump(pts, open(sys.argv[1], "w"), ensure_ascii=False)
print(len(pts))
```

#### p0_night_stops_dump.py の出力

```text
192
```

### 止まりを図面に重ねたスクリプト draw_night_stops.py

```python
"""②の夜（20261105_p0）のロボット2台・種10個の30秒以上の止まり192回を、直した②の図面（版 08db8a0d067c）に重ねる。
使い方: python3 draw_night_stops.py <unity/p0_memory.json> <p0_night_r2_stops.json> <出力.png>"""
import json, sys, math
import matplotlib; matplotlib.use("Agg")
import matplotlib.pyplot as plt
from matplotlib.patches import Rectangle, Circle
from matplotlib import font_manager as fm
FONT = "/usr/share/fonts/opentype/noto/NotoSansCJK-Regular.ttc"
fm.fontManager.addfont(FONT)
plt.rcParams["font.family"] = fm.FontProperties(fname=FONT).get_name()

U = json.load(open(sys.argv[1])); P = json.load(open(sys.argv[2]))
SB = [12.2, 5.1, 14.6, 5.9]; FP = (10.9, 5.45)
def area(x, y):
    if SB[0] <= x <= SB[2] and SB[1] <= y <= SB[3]: return "待機場所の中"
    if math.hypot(x - FP[0], y - FP[1]) <= 2.5: return "受け渡し口から2.5m以内"
    if 4.75 <= x <= 6.85 and 11.3 <= y <= 14.0: return "丸テーブルのまわり"
    if 7.5 <= x <= 9.5 and 8.0 <= y <= 9.6: return "仕切りの右端のすき間"
    if x < 9.5 and y > 9.0: return "奥の区画のそのほか"
    if 13.0 <= x <= 21.5 and 2.6 <= y <= 4.5: return "ドリンクバーのまわり"
    if 9.0 <= x <= 14.0 and y < 3.8: return "入口・レジのまわり"
    return "そのほか"
COL = {"待機場所の中": "#d6336c", "受け渡し口から2.5m以内": "#f08c00", "入口・レジのまわり": "#1971c2",
       "仕切りの右端のすき間": "#2f9e44", "丸テーブルのまわり": "#7048e8", "奥の区画のそのほか": "#7048e8",
       "ドリンクバーのまわり": "#868e96", "そのほか": "#495057"}
fig, ax = plt.subplots(figsize=(13, 11))
for r in U["rooms"]:
    x0, y0, x1, y1 = r["rect"]; ax.add_patch(Rectangle((x0, y0), x1 - x0, y1 - y0, fc="#eceef2", ec="#999", lw=0.6))
    ax.text((x0 + x1) / 2, (y0 + y1) / 2, r["label"], ha="center", va="center", fontsize=8, color="#666")
for w in U["walls"] + [dict(rect=r) for r in U["outer_walls"]]:
    x0, y0, x1, y1 = w["rect"]; ax.add_patch(Rectangle((x0, y0), x1 - x0, y1 - y0, fc="#7d8590", ec="none"))
for t in U["tables"]:
    p = t["parts"]
    for b in p["benches"]: ax.add_patch(Rectangle((b[0], b[1]), b[2] - b[0], b[3] - b[1], fc="#d6d9df", ec="#555", lw=0.5))
    tp = p["top"]
    if p.get("top_shape") == "circle": ax.add_patch(Circle(((tp[0] + tp[2]) / 2, (tp[1] + tp[3]) / 2), (tp[2] - tp[0]) / 2, fc="white", ec="#222", lw=0.9))
    else: ax.add_patch(Rectangle((tp[0], tp[1]), tp[2] - tp[0], tp[3] - tp[1], fc="white", ec="#222", lw=0.9))
    for c in p["chairs"]:
        r = c["rect"]; ax.add_patch(Circle(((r[0] + r[2]) / 2, (r[1] + r[3]) / 2), (r[2] - r[0]) / 2, fc="#ced4da", ec="#555", lw=0.4))
    x0, y0, x1, y1 = t["footprint"]; ax.text(x0, y1 + 0.06, t["id"], fontsize=7, color="#333")
for pl in U["places"]:
    if pl["kind"] == "RobotStandby":
        r = pl["rect"]; ax.add_patch(Rectangle((r[0], r[1]), r[2] - r[0], r[3] - r[1], fc="none", ec="#d6336c", lw=1.2, ls="--"))
    if pl["kind"] == "Waiting":
        r = pl["rect"]; ax.add_patch(Rectangle((r[0], r[1]), r[2] - r[0], r[3] - r[1], fc="#e7f5ff", ec="#1971c2", lw=1))
ax.add_patch(Circle(FP, 0.15, fc="white", ec="#e8590c", lw=1.5, zorder=6))
cnt = {}
for x, y, cause, res, dur, seed in P:
    a = area(x, y); cnt[a] = cnt.get(a, 0) + 1
    ax.add_patch(Circle((x, y), 0.13, fc=COL[a], ec="white", lw=0.3, alpha=0.75, zorder=7))
ax.set_xlim(-0.5, 24.5); ax.set_ylim(-1.2, 19.6); ax.set_aspect("equal"); ax.axis("off")
order = ["入口・レジのまわり", "待機場所の中", "受け渡し口から2.5m以内", "仕切りの右端のすき間", "丸テーブルのまわり", "奥の区画のそのほか", "ドリンクバーのまわり", "そのほか"]
txt = "　".join(f"{k} {cnt.get(k, 0)}" for k in order if cnt.get(k))
ax.set_title(f"② 定番の郊外型（直した版）：ロボット2台・種10個の30秒以上の止まり {len(P)}回\n{txt}", fontsize=11)
print(cnt)
plt.tight_layout(); plt.savefig(sys.argv[3], dpi=110)
```


## 作業ログ ― 6店の夜を並べると、待機場所のまわりはどの店でも詰まっていた

②で、用意した6店（③⑦④⑤⑥②）をすべて Unity で回し終えました。どの店も、ロボット0・1・2台 × 種0〜9 を今の標準（すれ違いあり・往復を終えたら待機場所へ戻る）で回しています。店ごとの報告を見比べるのではなく、6店の回の記録（`stops.csv`・`summary.json`）から同じ数え方で並べ直しました。④だけは、待機場所へ戻る作りを試した夜（20261031）の回を使っています。

### 6店の回をまとめたスクリプト six_store_stops.py（KIOXIA の r2r2r-data/service_sim/unity で実行）

```python
"""Unity で建てた6店の夜（今の標準：すれ違い入・待機場所へ戻る 入・案B 切）の、ロボット0・1・2台の回を店ごとにまとめる（2026-10-29）。
30秒以上の止まりの数・そのうち待機場所の四角の中・受け渡し口の点から2.5m以内（待機場所を除く）・60秒の「動けなくなった」と、
入店待ちの種10個の中央値と試算（params の site_result）を並べる。待機場所と受け渡し口の点は、公開中の店の形（unity/*.json）の値。
使い方: KIOXIA の r2r2r-data/service_sim/unity で python3 six_store_stops.py <出力.json>"""
import csv, glob, json, math, statistics, sys

G = {"fam_p0": {"sb": [12.2, 5.1, 14.6, 5.9], "fp": [10.9, 5.45]}, "fam_p1": {"sb": [16.5, 5.65, 18.9, 6.45], "fp": [15.3, 5.95]},
     "fam_p2": {"sb": [12.0, 4.15, 13.6, 4.95], "fp": [11.05, 4.45]}, "fam_p3": {"sb": [14.2, 8.55, 16.6, 9.35], "fp": [12.5, 8.85]},
     "fam_p4": {"sb": [15.5, 5.65, 17.9, 6.45], "fp": [14.3, 5.95]}, "fam_p5": {"sb": [16.5, 5.65, 18.9, 6.45], "fp": [15.3, 5.95]}}
# 店ごとに、今の標準で種10個を回した夜（④は待機場所へ戻るを試した夜 20261031 の B）
NIGHTS = {"fam_p1": "20261102_night_cs34_fam_p1", "fam_p5": "20261102_night_cs34_fam_p5", "fam_p2": "20261031_p2_cs33_fam_p2",
          "fam_p3": "20261103_night_cs36_fam_p3", "fam_p4": "20261104_night_cs38_fam_p4", "fam_p0": "20261105_night_cs40_fam_p0"}
res = {}
for st, pre in NIGHTS.items():
    sb, fp = G[st]["sb"], G[st]["fp"]
    for rb in (0, 1, 2):
        dirs = sorted(d for d in glob.glob(f"{pre}_r{rb}_s*_passon_sbret") if "ruleb" not in d)
        if not dirs:
            continue
        tot = insb = nearfp = stuck = 0
        ew = []
        for d in dirs:
            with open(d + "/stops.csv") as f:
                for r in csv.DictReader(f):
                    if float(r["duration_s"]) < 30:
                        continue
                    x, z = float(r["x"]), float(r["z"])
                    tot += 1
                    if r["resolved"] == "動けなくなった":
                        stuck += 1
                    if sb[0] <= x <= sb[2] and sb[1] <= z <= sb[3]:
                        insb += 1
                    elif math.hypot(x - fp[0], z - fp[1]) <= 2.5:
                        nearfp += 1
            s = json.load(open(d + "/summary.json"))
            for key in ("sim_like", "site_metrics"):
                if isinstance(s.get(key), dict) and "entry_wait_mean" in s[key]:
                    ew.append(s[key]["entry_wait_mean"])
                    break
        site = json.load(open(dirs[0] + "/summary.json")).get("site_result", {}).get("entry_wait_mean")
        res[f"{st}_r{rb}"] = dict(n=len(dirs), stops=tot, standby=insb, nearpass=nearfp, stuck=stuck,
                                  entry_med=round(statistics.median(ew), 2) if ew else None, site=site)
        print(st, rb, res[f"{st}_r{rb}"])
json.dump(res, open(sys.argv[1], "w"), ensure_ascii=False, indent=1)
```

#### six_store_stops.py の出力

```text
fam_p1 0 {'n': 10, 'stops': 0, 'standby': 0, 'nearpass': 0, 'stuck': 0, 'entry_med': 4.09, 'site': 3.301}
fam_p1 1 {'n': 10, 'stops': 88, 'standby': 0, 'nearpass': 2, 'stuck': 54, 'entry_med': 5.0, 'site': 2.5992}
fam_p1 2 {'n': 10, 'stops': 230, 'standby': 41, 'nearpass': 46, 'stuck': 156, 'entry_med': 3.99, 'site': 1.1788}
fam_p5 0 {'n': 10, 'stops': 0, 'standby': 0, 'nearpass': 0, 'stuck': 0, 'entry_med': 4.49, 'site': 2.7562}
fam_p5 1 {'n': 10, 'stops': 86, 'standby': 0, 'nearpass': 3, 'stuck': 53, 'entry_med': 3.22, 'site': 1.815}
fam_p5 2 {'n': 10, 'stops': 247, 'standby': 31, 'nearpass': 45, 'stuck': 157, 'entry_med': 3.56, 'site': 1.9669}
fam_p2 1 {'n': 10, 'stops': 242, 'standby': 2, 'nearpass': 18, 'stuck': 175, 'entry_med': 14.4, 'site': 2.9349}
fam_p2 2 {'n': 10, 'stops': 759, 'standby': 107, 'nearpass': 82, 'stuck': 610, 'entry_med': 24.79, 'site': 3.4597}
fam_p3 0 {'n': 10, 'stops': 0, 'standby': 0, 'nearpass': 0, 'stuck': 0, 'entry_med': 8.14, 'site': 6.2179}
fam_p3 1 {'n': 10, 'stops': 42, 'standby': 5, 'nearpass': 2, 'stuck': 19, 'entry_med': 6.6, 'site': 3.4227}
fam_p3 2 {'n': 10, 'stops': 184, 'standby': 51, 'nearpass': 5, 'stuck': 129, 'entry_med': 5.46, 'site': 3.6696}
fam_p4 0 {'n': 10, 'stops': 0, 'standby': 0, 'nearpass': 0, 'stuck': 0, 'entry_med': 9.6, 'site': 6.9454}
fam_p4 1 {'n': 10, 'stops': 33, 'standby': 0, 'nearpass': 2, 'stuck': 18, 'entry_med': 6.04, 'site': 3.116}
fam_p4 2 {'n': 10, 'stops': 122, 'standby': 60, 'nearpass': 9, 'stuck': 76, 'entry_med': 4.83, 'site': 1.8939}
fam_p0 0 {'n': 10, 'stops': 0, 'standby': 0, 'nearpass': 0, 'stuck': 0, 'entry_med': 1.96, 'site': 2.6471}
fam_p0 1 {'n': 10, 'stops': 46, 'standby': 0, 'nearpass': 7, 'stuck': 36, 'entry_med': 1.69, 'site': 1.6909}
fam_p0 2 {'n': 10, 'stops': 192, 'standby': 54, 'nearpass': 32, 'stuck': 146, 'entry_med': 2.1, 'site': 1.169}
```

### ロボット2台の30秒以上の止まりは、6店とも待機場所と受け渡し口のまわりに25〜57%

| 店 | 卓 | 30秒以上の止まり（2台・種10個） | 待機場所の中 | 受け渡し口から2.5m以内 | 合わせた割合 | 入店待ち 1台→2台（Unity） | 同（試算） |
|---|---|---|---|---|---|---|---|
| ③ | 42 | 230 | 41 | 46 | 38% | 5.00→3.99 | 2.60→1.18 |
| ⑦ | 42 | 247 | 31 | 45 | 31% | 3.22→3.56 | 1.82→1.97 |
| ④ | 28 | 759 | 107 | 82 | 25% | 14.40→24.79 | 2.93→3.46 |
| ⑤ | 46 | 184 | 51 | 5 | 30% | 6.60→5.46 | 3.42→3.67 |
| ⑥ | 38 | 122 | 60 | 9 | 57% | 6.04→4.83 | 3.12→1.89 |
| ② | 19 | 192 | 54 | 32 | 45% | 1.69→2.10 | 1.69→1.17 |

6店とも、待機場所は受け渡し口のすぐ横（受け渡し口の点から待機場所の端まで0.95〜1.7m）にあり、往復を終えて戻るロボットと、待機場所から受け渡し口へ出るロボットが、ここで出会います。④⑤⑥では、店ごとにドリンクバー・レジ・卓の位置を直しました。直した所の止まりは減りましたが、待機場所のまわりの止まりは、どの店にも残っています。

1台から2台にしたときの入店待ちの向きは、③⑦④⑥では試算と同じでした。逆になったのは⑤（Unity は縮み、試算は延びる）と②（Unity は延び、試算は縮む）です。小さい店の④（28卓）と②（19卓）は、Unity では2台目で入店待ちが延びています。

【図解】LOG402_six_stores_jam.html


## 作業ログ ― ②で区切り、直す先を店の形の決まりへ移す

②もここで区切りにしました。残った詰まりは店ごとに直さず、記録して、店の形を作る決まりのほうで考えます。直すなら、これまでどおりサイトの店の形を先に直し、Unity はそれに合わせます。

| 決めたこと・残したこと | 中身 |
|---|---|
| ②の椅子 | 角テーブル・丸テーブルは2脚ずつ向かい合わせ。椅子はロボットが止まる辺を含まない2辺に置く（壁ぎわで座れない卓だけ例外）。長テーブルは上下にスツール3つずつ |
| ②の店の形 | 右の丸テーブル T06 を右へ1.0m（間 1.1m → 2.1m）。版 08db8a0d067c |
| ②の試算 | ②の2,628条件だけ計算し直した（v2.8 のまま） |
| Unity で回す店 | ③⑦④⑤⑥②の18条件（serving-robot-params.json） |
| Unity の作り | 丸い天板とスツールを読めるように、部品の読み方を店に関係なく広げた（cs:39）。裏の部屋は名前を知らなくても通れない箱として建てる |
| 記録だけにしたもの | 待合のまわりの止まり（お客さんが多い種だけ）、受け渡し口の左のパントリーの壁ぞいの止まり、種1〜4で入店待ちが5〜10分と長いこと、1台→2台で試算と逆の向きの種が4個あること、T19 の右の席に着く点、レジの内側の幅 0.52m |
| 6店に共通の詰まり | 待機場所が受け渡し口のすぐ横にあり、戻るロボットと出るロボットが出会う。店ごとの直しではなく、待機場所・待合・スタッフが待つ点の置き方を、店の形を作る決まりとして考え直す |
