サービスロボット導入シミュレーション Log#19 | 大きい店でも、詰まるのは片付けだった

この記事の素材(コード・ログ・データ 9ファイル・まとめてダウンロードあり)

配膳ロボットを足すと入店待ちは縮みますが、大きなファミレスで詰まるのは会計のレジではなく、食べ終えた卓の片付けと空いた席への案内でした。46卓・200席の店を Unity の3Dで再現したシミュレーションで、配膳ロボットを走らせて確かめました。ロボットを1台、2台と足すと、お客さんが席に着くまでの待ちは8.1分、6.6分、5.5分と縮みました。ここまでは、サイトに公開している試算と同じ向きです。ところが、店が詰まる場所が試算と違いました。試算ではレジに会計の列ができて詰まります。3Dの店ではレジはそれほど詰まらず、詰まっていたのは、食べ終えた卓の片付けと、空いた席への案内のほうでした。

配膳ロボットを入れると店がどう変わるかを、2つのやり方で調べています。1つはサイトの試算で、卓までの距離・料理の数・スタッフの人数から、待ち時間を計算します。もう1つは Unity(ゲームを作る道具)で作った3Dのファミレスで、お客さん・スタッフ・ロボットを1人ずつ動かすシミュレーションです。試算を正とし、3Dの店は「通路で実際に何が起きるか」を測る役です。これまで42卓の店(③と⑦)と28卓の小さい店(④)で回してきました。今回は、いちばん大きい⑤(ゆったり型・入口が正面の中央)に広げました。

⑤は、建てる前に図面を見た段階で、1つ問題が見つかりました。真ん中の島(背中合わせのソファ席の列)の上の端と、料理が出てくるパントリーの間が0.25mしかありませんでした。ロボットは料理を受け取ったあと、左側の卓へまっすぐ抜けられません。左の卓へ行くロボットは全部、島の下を回り、入口とレジの前を通っていました。お客さんが入ってくる所、会計に並ぶ所、待合の前を、料理を載せたロボットが横切る形です。

そこで、試算と3Dの店の両方の元になっている「店の形」を直しました。島の上の2卓を外して右の壁ぞいへ移し、キッチン側(パントリー・キッチン・洗い場・更衣室・受け渡し口・ロボットの待機場所)をまとめて左へ1.5mずらしました。卓の数と席の数は変わりません。島の上とパントリーの間は約2.1mになり、受け渡し口から左側へまっすぐ抜けられるようになりました。

やったことなぜ結果
③⑦の基準データを v5 に切り替えた
ロボットが往復のあと待機場所へ戻る作りを標準にしたため
受け渡し口の近くの30秒以上の止まりが、③156→86回・⑦133→76回
⑤の図面を見て、店の形を直した
島の上が0.25mで、左へ行くロボットが入口とレジの前を通っていた
入口・レジの前を通る道が46卓中24卓→10卓。卓までの距離は平均13.7m→12.5m
⑤の試算だけ計算し直した卓の位置が変わったため
料理の待ちはどの台数も少し短く。会計待ちはレジ1つで13〜19分
3Dの店に⑤を建てた
店の形のデータに、入口のない通路が1本あった
サイト側の作り方を直して建った
⑤を種10個ずつ、計30回回した
1回ずつでは来る客の数がぶれるため
入口・レジの前の止まりは2台で3回。詰まりは片付けと案内に移った

3Dの店で回した結果は、次のとおりです(種10個の中央値。右は試算)。

ロボット0台1台2台
入店待ち(分)8.1 / 6.26.6 / 3.45.5 / 3.7
そのうち、席は空いているのに待った(分)
6.5 / 1.54.6 / 0.83.4 / 0.7
会計待ち(分)5.7 / 18.87.2 / 13.07.0 / 13.0
料理の待ち(分)1.1 / 0.62.6 / 2.12.2 / 1.2
ロボットが運んだ皿の割合−0.67 / 0.690.82 / 0.98

試算では、食べ終えたお客さんがレジの順番を待つ間、卓に座ったままでいます。レジが1つしかないと会計待ちが13〜19分に延び、その分だけ卓が空かず、次のお客さんが待ちます。3Dの店では会計待ちは7分前後で、代わりに「席は空いているのに待った」時間が試算の4〜8倍になりました。スタッフ4人の手が、片付けと案内に回りきっていません。42卓の③⑦でも同じ形のずれが出ていて、店の大きさを変えても残りました。

この記事の後半は、作業ログです。⑤の前に済ませた③⑦の基準データの切り替え、図面の直し、試算の計算し直し、3Dの店に建てるまでの2回の失敗、30回分の結果を、依頼文・報告・コード・出力とあわせて載せます。

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

店の立体図(席・キッチン・配膳ロボットの通り道)導入前シミュレーション配膳ロボットを、導入前に自分の店舗でシミュレーション店舗の図面と人数から、何人で回るか・どこで止まるか・月いくらかかるかを出します

作業ログ ― ③⑦の基準データを v5 に切り替えた

この記事のコード・ログ・データは、1ファイルずつ下に置いています。全文はリンク先にあります。

ファイルの一覧(9本)

01_sec01.txt ― 報告:20261102_night_37_v5candidate.txt・12,957字

02_sec01.txt ― 基準データ v1〜v5候補は、何を変えるたびに、どう動いたか / compare_baselines.py の出力・3,092字

03_export_params.py.txt ― Unity が読む条件を書き出すスクリプト export_params.py(⑤を足した版)・4,766字

04_sec02.txt ― 報告:20261028_1338_p3_build_check.txt・3,297字

05_sec05.md ― 依頼文:直した⑤を建てて確かめる(20261028_18)・3,129字

06_sec05.txt ― 報告:20261028_1401_p3_build_check2.txt・7,746字

07_sec05.md ― 依頼文:直した⑤を建てて確かめる・やり直し(20261028_19)・3,678字

08_sec05.txt ― 報告:20261028_1440_p3_build_check3.txt・10,548字

09_runner_log.txt ― 夜の実行ログ runner_log.txt・8,544字

3Dの店は、夜のあいだに同じ条件を何十回も回し、前に決めた「基準データ」と比べて、作りが壊れていないかを自動で判定しています。④を調べたときに、ロボットが往復を終えても受け渡し口の前に止まったままになる作りの誤りが見つかり、「往復を終えたら待機場所へ戻る」作りを入れました。これを③⑦の標準にし、③⑦を60回回し直して、基準データ v5 の候補にしました。

この記事で書く効果は、すべて3Dの店で測った値です。直す前に回していない所は、そう断って書きます。

依頼文:待機場所へ戻るを標準にし、③⑦をv5候補で回す(20261028_15)

---
作業フォルダ: /Users/shimazueiichi/Robotics_UX/ServiceSim
上限時間: 240
---
# 依頼:待機場所へ戻るを標準にし、判定を切り替えごとに分け、③⑦を60回回す(基準データ v5 の候補・2026-10-28)

エイイチの決定(2026-10-28 06:33):前の2つの報告(20261031_night_p2_standby.txt・20261101_night_37_standby_ruleB.txt)を受けて
1. 待機場所へ戻るを標準(既定 入)にする
2. 案B(受け渡し口は1台ずつ・同じ卓は1台)は切のまま。作りは消さない
3. 判定(judge_night.py)を、切り替え(すれ違い・待機場所へ戻る・案B)の入切ごとに分けて比べる形にする
4. ③⑦を「すれ違い入・待機場所へ戻る 入・案B 切」で60回回し、基準データ v5 の候補にする(v5 にするかはエイイチが決める)

サイト(正)を直した(p2m-site commit eb03d73):params の schema 0.4。`unity_rules` に `standby_return`(true)を足し、`pass_one_robot`・`same_table_one_robot` を false にした。試算の数字・条件・店の形の版(39257d16b68a)は変わっていない。

台帳の退避は Claude が済ませた:`/Volumes/KIOXIA/r2r2r-data/service_sim/unity/archive/unity_ledger_v1_prenight_20261102/unity_ledger_v1.csv`(505行・md5 c7031e3824b9aa6b137668d44e87db64)

## 始める前に確かめること(違えば回さずに報告して終わる)

1. Unity エディタが起動していない
2. /Volumes/KIOXIA がマウントされている。鍵ファイル unity_ledger_v1.lock がない
3. 台帳の md5 が上の退避と同じ
4. ServiceSim の保留が 0(cs:33 head)
5. https://pixelstomotors.com/sim/serving-robot-params.json の meta.schema_version が serving-robot-params/0.4(まだ 0.3 なら数分おきに取り直す。30分たっても 0.3 なら報告して終わる)

## やること

1. 公開版の params をプロジェクトに写す。`unity_rules` 以外が今の写しと同じか確かめる
2. 待機場所へ戻る・案Bの既定を、params の `unity_rules` の値から決める形にする(standby_return 入・案B 切)。`-ssStandbyReturn`・`-ssRuleB`・make_queue / night_runner の `--standby-return`・`--rule-b` で、回ごとに入切を上書きできるのは今のまま。エディタのメニュー(Site Run など)も同じ既定にする
   - 出力フォルダ名の字:今は入のとき `_sbret` が付く。既定が入になっても、入のときは今までどおり `_sbret` を付ける(名前から作りが分かるように)
3. judge_night.py:回ごとの run_info.json(または queue)にある切り替え(すれ違い・待機場所へ戻る・案B)の入切を条件の一部として扱い、基準データの中で**同じ条件・同じ入切の回とだけ**比べる。同じ入切の回が基準に無ければ「基準なし」。判定の決まり(何を超えたら何に振り分けるか)は変えない。基準データの既定(v4・20261029_night_cs26_*)も変えない
   - 確かめ:夜 20261101(待機場所 入・案B 入)を判定し直すと、v4 と入切が違うので60回とも「基準なし」になること。夜 20261029(v4)を自分自身に当てると今までどおり「正常」60になること(/tmp に出す。night/ の記録は上書きしない)
4. 何も指定しないときの make_queue が、③⑦の60回・すれ違い入・待機場所へ戻る 入・案B 切になることを確かめる
5. check-in して、画面なしの実行ファイルを作り直す(保留 0)
6. 夜の名前 20261102 で、何も指定しない make_queue の60回を回す(同時4本・記録は night/20261102/)。回している間はほかの作業をしない
7. 台帳の行数(505 → 565 のはず)と先頭505行の md5 が退避と同じかを確かめる
8. 作業フォルダに queue の一時ファイルを残さない

## 変えないもの

- 店の形・人の動き・速さ・物理の設定・すれ違いの作り・待機場所へ戻る作りの中身(cs:33)・案Bの作り
- 台帳の列(59列)と今までの行。今までの night/ の記録

## 報告

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

- 始める前の確かめ5つの結果
- 入れた cs 番号・build_id と保留の有無・変えたファイル
- 判定の直しと、3 の確かめ2つの結果
- runner_log のまとめ・台帳の行数と md5
- 店 × 台数ごとの種10個の中央値(最小〜最大)を、v4(20261029・待機場所 切)と、夜 20261101(待機場所 入・案B 入)と並べる:入店待ち・料理の待ち・ロボットが運んだ皿の割合・往復の数・30秒以上の止まり(1往復あたり)・動けなくなった(60秒)・瞬間移動・打ち切り・冷めた皿の割合。試算の値も並べる
- 2台の30秒以上の止まりの、受け渡し口の点から 2.5 m 以内の数(待機場所での止まりを除いた数も)を、v4・20261101 と並べる
- ロボットを1台増やしたときの向き(入店待ち・料理の待ち)が、種の過半数で試算と同じか逆か
- 全員が帰らなかった回・失敗した回があればその名前
- 決めてほしいこと(なければ「なし」)

報告:20261102_night_37_v5candidate.txt

01_sec01.txt12,957字・270行・text
====================================================================
待機場所へ戻るを標準にし、判定を入切ごとに分け、③⑦を60回回した(夜 20261102・基準データ v5 の候補)
依頼:20261028_15_待機場所へ戻るを標準に_③⑦をv5候補で回す.md
実行ファイル:build_id cs34_20261028_0642(ServiceSim/cs:34・保留なし)
回した時刻:2026-10-28 06:42〜07:43
====================================================================

結論
別のタブで開く保存

待機場所へ戻ると、受け渡し口の近くの止まりが半分になった

  • ねらい:往復を終えたロボットが受け渡し口の前に居座り、次のロボットを止めないようにする
  • 変わったこと:2台の回で、受け渡し口の点から2.5m以内の30秒以上の止まり(種10個の合計)が、③156→86回・⑦133→76回。待機場所で待っている分を除くと③46回・⑦45回
  • 見込める効果:③⑦では受け渡し口の前の詰まりが主な止まりではなくなった。代わりに③はロボットが運んだ皿の割合が0.92→0.83に下がり、待機場所へ戻る時間の分だけ往復が減った(130→119.5回)

判定の作り(judge_night.py)は、切り替え(すれ違い・待機場所へ戻る・案B)の入切ごとに、同じ入切の回とだけ比べる形に直してもらいました。入切の違う夜を比べて「ずれた」と判定しないためです。

基準データ v1〜v5候補は、何を変えるたびに、どう動いたか

v5 にする前に、v1 からの流れを並べて確かめました。台帳(1回1行の記録)から、版ごと・店ごと・台数ごとの中央値を出しました。

版回した回数前の版から変えたこと
v118回(種3つ)
ロボットがサイトの地図の上で自分で道を引くようにした(cs:143・試算 v2.7)
v218回(種3つ)
逃がし弁「卓を空けた」を直した。試算 v2.8(レジ)を読むようにした
v360回(種10個)
新しいプロジェクトに分け、画面なしで夜に回すようにした(すれ違い切)
v460回すれ違いを入にした
v5候補60回
待機場所へ戻るを入にした(案B は切)
ロボット2台③ 料理の待ち(分)③ 運んだ割合③ 動けなくなった(60秒)⑦ 料理の待ち(分)⑦ 運んだ割合⑦ 動けなくなった(60秒)
v11.53(試算1.01)0.90(0.99)241.53(1.01)0.94(0.99)25
v21.43(0.95)0.89(0.99)191.45(0.98)0.92(0.99)21
v31.490.9320.51.380.9421.5
v41.620.92251.520.9217
v5候補1.950.83181.610.9216.5

v1→v2 が一番大きな変わり目でした。v1 は逃がし弁が片付けを飛ばしていて、ロボット0台の入店待ちが試算の半分以下(③1.7分・試算4.0分)でした。v2 からは Unity の入店待ちが試算より長くなり、その向きは v5候補まで変わっていません。v2→v3 で種を3つから10個にすると、v2 の⑦1台の入店待ち8.2分は5.0分になりました。種が少ないための外れ値でした。v3 から先は、料理の待ちと運んだ割合はほぼ横ばいで、すれ違いと待機場所の切り替えで変わったのは止まり方でした。料理の待ちが試算の1.5〜2倍、運んだ割合が少し低い、という大きさのずれは、どの版でも残っています。

この流れを見て、エイイチは夜 20261102 を基準データ v5 にすると決めました。

比べたスクリプト compare_baselines.py

"""基準データ v1〜v5候補を、店×台数ごとに中央値で並べる(2026-10-28。台帳 unity_ledger_v1.csv から)
使い方: cd /Volumes/KIOXIA/r2r2r-data/service_sim/unity && python3 compare_baselines.py"""
import csv, statistics as st
r = list(csv.DictReader(open('unity_ledger_v1.csv')))
B = {'v1': lambda f, x: x['unity_cs'] == 'cs:143', 'v2': lambda f, x: x['unity_cs'] == 'cs:144',
     'v3': lambda f, x: f.startswith('20261027_night_cs21') and 'passon' not in f,
     'v4': lambda f, x: f.startswith('20261029_night_cs26'), 'v5候補': lambda f, x: f.startswith('20261102_night_cs34')}
def m(v):
    v = [float(a) for a in v if a not in ('', None)]
    return f"{st.median(v):.2f}" if v else "-"
for st_ in ['fam_p1', 'fam_p5']:
    for rb in ['0', '1', '2']:
        print(f"## {st_} {rb}台")
        for k, fn in B.items():
            xs = [x for x in r if fn(x['run_folder'], x) and x['store'] == st_ and x['robots'] == rb]
            if not xs:
                continue
            g = lambda c: m([x[c] for x in xs])
            print(f" {k:5} n={len(xs):2} 入店{g('entry_wait_mean')}(試{g('site_entry_wait_mean')}) 料理{g('dish_wait_mean')}(試{g('site_dish_wait_mean')}) 割合{g('robot_share')}(試{g('site_robot_share')}) 往復{g('trips')} 止まり{g('stuck_count')} 打切{g('timeouts')} 卓空{g('table_freed')} 試算版{xs[0]['params_model']} 形{xs[0]['layout_generation'][:6]}")

compare_baselines.py の出力

02_sec01.txt3,092字・36行・text
## fam_p1 0台
 v1    n= 3 入店1.74(試3.99) 料理0.94(試0.65) 割合0.00(試0.00) 往復0.00 止まり0.00 打切0.00 卓空24.00 試算版v2.7 形8a5b2f
 v2    n= 3 入店3.90(試3.30) 料理0.94(試0.46) 割合0.00(試0.00) 往復0.00 止まり0.00 打切0.00 卓空0.00 試算版v2.8 形8a5b2f
 v3    n=10 入店4.08(試3.30) 料理0.94(試0.46) 割合0.00(試0.00) 往復0.00 止まり0.00 打切0.00 卓空0.00 試算版v2.8 形8a5b2f
 v4    n=10 入店4.21(試3.30) 料理0.94(試0.46) 割合0.00(試0.00) 往復0.00 止まり0.00 打切0.00 卓空0.00 試算版v2.8 形8a5b2f
 v5候補  n=10 入店4.09(試3.30) 料理0.98(試0.46) 割合0.00(試0.00) 往復0.00 止まり0.00 打切0.00 卓空0.00 試算版v2.8 形39257d
## fam_p1 1台
 v1    n= 3 入店1.67(試1.82) 料理2.51(試2.03) 割合0.69(試0.73) 往復65.00 止まり4.00 打切0.00 卓空8.00 試算版v2.7 形8a5b2f
別のタブで開く保存

依頼文:基準データ v5 に切り替える(20261028_16)

---
作業フォルダ: /Users/shimazueiichi/Robotics_UX/ServiceSim
上限時間: 60
---
# 依頼:夜 20261102 を基準データ v5 にし、判定の基準の既定を v5 に変える(2026-10-28)

エイイチの決定(2026-10-28 09:29):前の報告(20261102_night_37_v5candidate.txt)の「決めてほしいこと」への答え
1. 案B を「入」と指定した回は、受け渡し口は1台ずつ・同じ卓は1台の**両方を入れる**形のままでよい(20261101 と同じ動き)。作りは変えない
2. 夜 20261102(③⑦・すれ違い入・待機場所へ戻る 入・案B 切・60回・cs:34)を**基準データ v5** にする。judge_night.py の基準の既定を v4(20261029_night_cs26_*)から v5(20261102_night_cs34_*)に変える
3. 作業フォルダに 2026-10-27 からある古い `queue.json` を消す

回は回さない(判定の確かめだけ)。

## 始める前に確かめること(違えば何もせずに報告して終わる)

1. Unity エディタが起動していない・夜の回が動いていない
2. /Volumes/KIOXIA がマウントされている。鍵ファイル unity_ledger_v1.lock がない
3. 台帳が 565 行

## やること

1. judge_night.py の基準の既定を v5(20261102_night_cs34_*)にする。`--baseline` などで v4 を指定すれば今までどおり v4 と比べられる形は残す。判定の決まり(何を超えたら何に振り分けるか)・切り替えの入切ごとに分ける作りは変えない
2. 確かめ(出力は /tmp。night/ の記録は上書きしない)
   - 夜 20261102 を既定で判定すると「正常」60回になること
   - 夜 20261029 を既定で判定すると、待機場所へ戻るの入切が違うので60回とも「基準なし」になること
   - `--baseline` で v4 を指定して夜 20261029 を判定すると、今までどおり「正常」60回になること
3. KIOXIA の `service_sim/unity/night/20261102/` に `BASELINE_v5.md` を新しく置く(既存のファイルは触らない)。書くこと:基準データ v5 であること・決めた日(2026-10-28)・cs:34 と build_id・試算 v2.8・店の形の版 39257d16b68a(③⑦の形は 8a5b2f6a016a と同じ。④の直しで番号だけ変わった)・切り替えの入切(すれ違い入・待機場所へ戻る 入・案B 切)・回の数(③⑦ × 0/1/2台 × 種0〜9)・前の基準(v1 stageB_cs143/v2 stageB_cs144/v3 夜20261027 のすれ違い切/v4 夜20261029)を1行ずつ
4. 作業フォルダ直下の古い `queue.json`(2026-10-27 から残っているもの)を消す。night/ の中の queue.json は消さない。消す前に中身の先頭数行と日付を報告に書く
5. 変えたスクリプトを check-in する(保留 0)。画面なしの実行ファイルの作り直しは不要(Unity 側を変えないため)

## 変えないもの

- Unity の作り・params・店の形・台帳の列と行・今までの night/ の記録

## 報告

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

- 始める前の確かめの結果
- 変えたファイル・cs 番号
- 2 の確かめ3つの結果
- 消した queue.json の中身の先頭と日付
- 決めてほしいこと(なければ「なし」)

報告:20261028_baseline_v5.txt

20261028_baseline_v5 報告(依頼:20261028_16_基準データv5に切り替え.md)

■ やったこと
1. 始める前の確かめ
   - Unity エディタは起動していない(Unity Hub のみ動いている)。夜の回も動いていない
   - /Volumes/KIOXIA はマウントされている。unity_ledger_v1.lock はない
   - 台帳 unity_ledger_v1.csv は 565 行
   → 3つとも合っていたので作業を進めた
2. judge_night.py の基準の既定を v4(20261029_night_cs26_*)から v5(20261102_night_cs34_*)に変えた
   - --baseline '20261029_night_cs26_*' で今までどおり v4 と比べられる(v4 の glob を BASELINE_V4 として残し、--help にも出す)
   - 判定の決まり(何を超えたら何に振り分けるか)と、切り替えの入切ごとに分ける作りは変えていない
3. 確かめ(出力は /tmp。night/ の記録は上書きしていない。night/20261102・night/20261029 の judge.* の日時は元のまま)
   - 夜 20261102 を既定で判定:正常 60回(/tmp/bl5_a)
   - 夜 20261029 を既定で判定:基準なし 60回(待機場所へ戻るが 切 で、v5 は 入 のため)(/tmp/bl5_b)
   - 夜 20261029 を --baseline '20261029_night_cs26_*'(v4)で判定:正常 60回(/tmp/bl5_c)
4. KIOXIA の service_sim/unity/night/20261102/BASELINE_v5.md を新しく置いた(既存のファイルは触っていない)
   書いたこと:基準データ v5・決めた日 2026-10-28・cs:34・build_id cs34_20261028_0642・試算 v2.8・
   店の形の版 39257d16b68a(③⑦の形は 8a5b2f6a016a と同じ)・入切(すれ違い入・待機場所へ戻る入・案B切)・
   回の数(③⑦ × 0/1/2台 × 種0〜9 の60回)・前の基準 v1〜v4 を1行ずつ
5. 作業フォルダ直下の古い queue.json を消した(night/ の中の queue.json は消していない)
   - 日付:2026-10-27 10:19:06・14570 バイト。Plastic では Private(ignore.conf で無視される対象。版の管理には入っていない)
   - 中身は night/20261029/queue.json と同じ(cmp で一致)
   - 先頭:
     "schema": "servicesim-night-queue/0.1"
     "label": "night"
     "params_model": "v2.8"
     "layout_generation": "8a5b2f6a016a"
     "params_source": "Assets/ServiceSim/Experiment/serving-robot-params.json"
     "seeds": [0〜9]
     "conditions": fam_p1_s4_r0/r1/r2_a42・fam_p5_s4_r0/r1/r2_a42
     "pass_by": "on"・"count": 60
6. check-in:tools/judge_night.py → cs:35(保留 0)。画面なしの実行ファイルは作り直していない(Unity 側を変えていないため)
   回は回していない

■ 変えたファイル
- ServiceSim/tools/judge_night.py(cs:35)
- KIOXIA service_sim/unity/night/20261102/BASELINE_v5.md(新規)
- ServiceSim/queue.json(削除。版の管理の外)

■ 決めてほしいこと
なし

作業ログ ― ⑤の条件をサイトの試算から書き出した

⑤は46卓・200席の店です。3Dの店で回す条件は、③⑦④と同じ決め方にしました。スタッフは試算の真ん中の人数(4人)、来客は普通のペース(1時間46組)、ロボット0・1・2台、料理を運ぶだけ(下げ膳はしない)、1往復で3卓、レジは1つです。

試算では、⑤はレジが1つだと会計待ちが11〜18分になり、「レジが詰まる」の印が付きます。3Dの店でもレジが詰まるかを見るため、レジは③⑦④と同じ1つのままにしました。

Unity が読む条件を書き出すスクリプト export_params.py(⑤を足した版)

03_export_params.py.txt4,766字・93行・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)の値。registers はレジの数(v2.8)
別のタブで開く保存

依頼文:⑤を建てて確かめる(20261028_17)

---
作業フォルダ: /Users/shimazueiichi/Robotics_UX/ServiceSim
上限時間: 180
---
# 依頼:⑤ ゆったり・入口が正面の店(fam_p3)を Unity に建て、1回ずつ回して確かめる(2026-10-28)

エイイチの決定(2026-10-28 13:04):③⑦の標準を基準データ v5 で固めたので、別の店へ広げる。④のときと同じく、今回は⑤だけ。

サイト(正)はもう直した(p2m-site commit e12866e)。
- `public/sim/serving-robot-params.json`:Unity で回す店に fam_p3 を足した。unity_conditions は9件 → 12件。③⑦④の9件・common・unity_rules・meta は前と同じ。試算は v2.8 のまま計算し直していない
- ⑤の3条件:スタッフ4人・46組/時・ロボット0・1・2台・上げ膳・1往復3卓(0台は trays 1)・レジ1つ
- 店の形:`public/sim/layouts/unity/p3_relaxed_center.json` と `p3_relaxed_center_map.json`(generation 39257d16b68a。③⑦④と同じ版。前から公開済み)。46卓・200席
- 試算でも、⑤はレジ1つだと会計待ちが11〜18分で「レジが詰まる」。Unity でもレジが詰まるのは試算どおりなので、それだけで手を止めなくてよい
- 台帳の退避は Claude が済ませた:`/Volumes/KIOXIA/r2r2r-data/service_sim/unity/archive/unity_ledger_v1_pre_p3check_20261028/unity_ledger_v1.csv`(565行・md5 7f636cb533be1ee07caabb8782455f15)

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

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

## やること

1. サイトの params と⑤の店の形2つを、③⑦④と同じやり方でプロジェクトに写す(手で値を写さない)。generation が 39257d16b68a でそろっているか確かめる
2. ⑤を③⑦④と同じコード・同じ規則で建てる(地図の上で自分で道を引く動き方・すれ違い入・待機場所へ戻る 入・案B 切・店員優先のよけ方・逃がし弁・モニター、すべて今の標準のまま)。⑤のためだけの手直しはしない
   - スタッフ4人・46卓・レジ1つの組み合わせで足りないもの(待機場所の数、スタッフが待つ点、並ぶ点など)があれば、③⑦④の規則のまま置けるかを確かめる
   - ⑤の店の形のせいで建てられない・回らないところ(届かない卓、待機場所・レジ・スタッフが待つ点・並ぶ点が置けない、NavMesh の切れ目など)があっても、Unity 側で形を直さない。場所と理由を「決めてほしいこと」に書く(直すならサイトが先)
3. make_queue.py で `--stores fam_p3` が使えることを確かめる。**指定しないときは今までどおり ③⑦の60回**(params の条件が12件に増えても60回のまま)。judge_night.py は変えない(⑤は基準データがないので「基準なし」になってよい)
4. check-in して、画面なしの実行ファイルを作り直す(保留 0)
5. 確かめの3回を回す:⑤ × ロボット0・1・2台 × 種0、今の標準(すれ違い入・待機場所へ戻る 入・案B 切)。夜の回と混ざらないラベル `p3check` で。同時に回す本数は4のまま
   - 台帳には3行が足される(追記だけ)。終わったら行数(565 → 568 のはず)と、先頭565行の md5 が退避と同じかを確かめる
6. make_queue の dry-run で、何も指定しないとき③⑦の60回のままであることを確かめる(台帳に書かない)
7. 作業フォルダに queue の一時ファイルを残さない

## 変えないもの

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

## 報告

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

- 始める前の確かめ5つの結果
- 入れた cs 番号・build_id と保留の有無・変えたファイル
- ⑤を建てて分かったこと(卓の数46・止まる位置・待機場所・レジ・スタッフが待つ点・並ぶ点が置けたか、置けなかった所)
- 3回それぞれ:最後まで回ったか・全員帰ったか・実時間・入れた組の数・入店待ち・そのうち席は空いているのに待った時間・料理の待ち・会計待ち・ロボットが運んだ皿の割合・往復の数・30秒以上の止まり(1往復あたり)・動けなくなった(60秒)・卓を空けた・瞬間移動・打ち切り。試算の同じ条件の値(params の site_result)と並べる。差の理由の調べはしなくてよい
- 2台の回の30秒以上の止まりのうち、受け渡し口の点から 2.5 m 以内の数(待機場所での止まりを除いた数も)
- 台帳の行数と先頭565行の md5
- dry-run で③⑦が60回のままか
- **エイイチが画面で⑤を見る手順**(Unity を開いてから、どのシーン・メニューで⑤の、どの条件を流せるか。短く)
- 決めてほしいこと(なければ「なし」)

報告:20261028_1338_p3_build_check.txt

04_sec02.txt3,297字・84行・text
====================================================================
⑤ ゆったり・入口が正面の店(fam_p3)を建てて確かめる … 始める前の確かめ 5 で止めた
依頼:20261028_17_店5を建てて確かめる.md
2026-10-28 13:38
====================================================================

結論
別のタブで開く保存

サイトの公開が一度失敗し、3Dの店は待ちぼうけになった

Claude Code(Mac で Unity を動かす係)は、サイトに⑤の条件が出るのを2分おきに30分待ち、出なかったので手を止めました。GitHub に送った変更は、Cloudflare(サイトを配る所)のビルドが一度失敗していて、公開されていませんでした。手元で同じビルドを回すと通ったので、一時的な失敗だったと考えています。次に送った変更(⑤の店の形の直し)のビルドは通り、そこで⑤の条件も公開されました。

作業ログ ― 図面を見て、島の上の0.25mの隙間に気づいた

3Dの店で1回目の確かめを待っている間に、エイイチが⑤の図面を見て、入口のまわりを指しました。

図面見たけど、ここが狭くてすぐ詰まるね。

こっちに抜けられるようにしないと全体回らないよきっと

2つ目に指したのは、真ん中の島の上の端とパントリーの間でした。店の形のデータで測ると、島の上の端(仕切りの上端)が y=9.15m、パントリーの下の端が y=9.4m で、間は0.25mでした。島の右の端(x=9.3m)は、パントリーの左の端(x=9.0m)より右まで出ていて、角からも抜けられません。

ロボットの道(受け渡し口の前から各卓へ、ふだん走らせる1.0m以上の道)を描くと、左側の卓へ行く道は全部、受け渡し口から斜め下へ下り、レジの横と入口の前を通って、島の下から回り込んでいました。

直す前の⑤の図面とロボットの道。受け渡し口から左側の卓へ行く道が、真ん中の島の下を回り、レジと入口の前を通っている

外した2卓をどこへ置くか、案を4つ描いた

島の上を空けるには、島の上の2卓を外せば足ります。外した2卓をどこへ置くかで、案を描いて比べました。

今の形と、案1(右上の壁ぞいへ2卓)、案2(左の島を上へ1列のばす)。赤い点線が外す卓、緑が足す卓、青い矢印が新しく抜けられる道
案3(真ん中の島を離れた4人テーブル3卓にする)と案4(真ん中の島をなくし、左上の奥に6人席を2つ置く)

エイイチは、右上の空きを見て言いました。

右上のスペースが勿体無いけどどうにかできない?

案1をベースにキッチンや洗い場などの全体を左にずらしたら?

案1は、右の壁ぞいの4人席の列を上へ2卓のばす案です。ただ、そのままだと一番上の卓が更衣室・社員トイレの真横になります。キッチン側をまとめて左へずらすと、更衣室が右上の卓から離れ、受け渡し口も混みやすい左側へ寄ります。ずらす幅は1.5mにしました。キッチンの左の端と左の島(右の端 x=5.25m)の間に2.25mの通路が残る幅です。2.75mまでずらすと、この通路が1.0mまで狭まります。

案1と、案1にキッチン側をまるごと左へ1.5mずらした版の比べ
  • ねらい:受け渡し口から左側の卓へ、入口とレジの前を通らずに行ける道を作る
  • 変わったこと:島の上とパントリーの間が0.25m→約2.1m。卓までの距離は平均13.7m→12.5m、最長23.2m→18.8m。卓46・席200は同じ
  • 見込める効果:受け渡し口から各卓への道のうち、入口・レジの前(y が3.4mより下で、x が9.3〜16.4m)を通るものが、46卓中24卓→10卓に減った(残る10卓は、入口の左右の6人席と、左下の席)。直す前の形では3Dの店を回していないので、止まりの前後の比べはない。直したあとの30回で、2台の回の入口・レジの前の30秒以上の止まりは3回だった

入口・レジの前を通る道を数えたスクリプト count_routes.py

"""⑤の受け渡し口から各卓への道(店の形の routes.from_pass)のうち、入口・レジの前を通るものを数える(2026-10-28)
入口・レジの前:y が 3.4 m より下で、x が 9.3〜16.4 m(真ん中の島の下の端より下、左下の6人席の右の端から右下の6人席の左の端まで)
使い方: python3 count_routes.py <直す前の unity/p3_relaxed_center.json> <直した後の unity/p3_relaxed_center.json>"""
import json, sys


def seg_in(p, q):
    for i in range(51):
        x = p[0] + (q[0] - p[0]) * i / 50
        y = p[1] + (q[1] - p[1]) * i / 50
        if y < 3.4 and 9.3 <= x <= 16.4:
            return True
    return False


for tag, path in (("直す前", sys.argv[1]), ("直した後", sys.argv[2])):
    m = json.load(open(path, encoding="utf-8"))
    fp = m["routes"]["from_pass"]
    hit = [k for k, v in fp.items() if any(seg_in(a, b) for a, b in zip(v["points"], v["points"][1:]))]
    print(tag, "卓", len(fp), "入口・レジの前を通る", len(hit), hit)
    print("  T14 への道", fp["T14"]["points"])

count_routes.py の出力

直す前 卓 46 入口・レジの前を通る 24 ['T01', 'T02', 'T03', 'T04', 'T05', 'T06', 'T07', 'T08', 'T09', 'T10', 'T11', 'T12', 'T13', 'T14', 'T15', 'T16', 'T17', 'T18', 'T19', 'T39', 'T40', 'T41', 'T42', 'T43']
  T14 への道 [[14.0, 8.85], [9.638, 3.013], [9.463, 2.913], [8.188, 2.713], [6.688, 2.738], [6.288, 3.163], [6.263, 3.312], [6.038, 7.262]]
直した後 卓 46 入口・レジの前を通る 10 ['T01', 'T02', 'T03', 'T07', 'T08', 'T39', 'T40', 'T41', 'T42', 'T43']
  T14 への道 [[12.5, 8.85], [6.038, 8.788]]

案1・案2を描いたスクリプト plan.py

import json, matplotlib; matplotlib.use('Agg')
import matplotlib.pyplot as plt, matplotlib.patches as P
from matplotlib import font_manager as fm
fp=fm.FontProperties(fname='/usr/share/fonts/opentype/noto/NotoSansCJK-Regular.ttc')
L=json.load(open('/home/claude/p2m-site/public/sim/layouts/p3_relaxed_center.json'))['layout']
def draw(ax,title,remove=(),add=(),hl=None):
    ax.add_patch(P.Rectangle((0,0),26,17,fill=False,lw=2))
    for r in L['rooms']:
        x0,y0,x1,y1=r['rect']; ax.add_patch(P.Rectangle((x0,y0),x1-x0,y1-y0,fc='#e4e4e0',ec='#999'))
        ax.text((x0+x1)/2,(y0+y1)/2,r['label'],ha='center',va='center',fontproperties=fp,fontsize=6)
    for t in L['tables']:
        if t['id'] in remove:
            ax.add_patch(P.Rectangle((t['x'],t['y']),t['w'],t['h'],fill=False,ec='#c33',ls='--',lw=1.2)); continue
        ax.add_patch(P.Rectangle((t['x'],t['y']),t['w'],t['h'],fc='w',ec='k',lw=.8))
        ax.text(t['x']+t['w']/2,t['y']+t['h']/2,str(t['seats']),ha='center',va='center',fontsize=6)
    for (x,y,w,h) in add:
        ax.add_patch(P.Rectangle((x,y),w,h,fc='#cfe8cf',ec='#2a7a2a',lw=1.2)); ax.text(x+w/2,y+h/2,'4',ha='center',va='center',fontsize=6)
    if hl: ax.annotate('',xy=hl[1],xytext=hl[0],arrowprops=dict(arrowstyle='->',color='#2a5cc8',lw=2))
    ax.add_patch(P.Rectangle((12,-.3),3,.3,fc='w',ec='w')); ax.text(13.5,-.8,'入口',ha='center',fontproperties=fp,fontsize=8)
    ax.set_xlim(-.5,26.5); ax.set_ylim(-1.2,17.5); ax.set_aspect('equal'); ax.axis('off'); ax.set_title(title,fontproperties=fp,fontsize=10)
fig,axs=plt.subplots(1,3,figsize=(18,5.2))
draw(axs[0],'今:島の上がパントリーとの間 0.25m(左へ抜けられない)',hl=((14,8.6),(9.6,8.6)))
draw(axs[1],'案1:島の上の2卓を外し、右上の壁ぞいへ2卓',remove=('T19','T22'),add=[(24.8,12.5,1.2,1.85),(24.8,14.35,1.2,1.85)],hl=((14,8.6),(6,8.6)))
draw(axs[2],'案2:島の上の2卓を外し、左の島を上へ1列のばす',remove=('T19','T22'),add=[(2.7,10.8,1.2,1.85),(4.05,10.8,1.2,1.85)],hl=((14,8.6),(6,8.6)))
plt.tight_layout(); plt.savefig('p3_options.png',dpi=130)

案3・案4を描いたスクリプト plan2.py

exec(open('plan.py').read().split('fig,axs')[0])
mid=('T17','T18','T19','T20','T21','T22')
fig,axs=plt.subplots(1,2,figsize=(12,5.2))
draw(axs[0],'案3:真ん中の島を、離れた4人テーブル3卓に(45卓・196席)',remove=mid,
     add=[(7.4,3.6,1.2,1.2),(7.4,5.4,1.2,1.2),(7.4,7.2,1.2,1.2),(2.7,10.8,1.2,1.85),(4.05,10.8,1.2,1.85)],hl=((14,8.9),(6,8.9)))
draw(axs[1],'案4:真ん中の島をなくし、左上の奥に6人席を2つ(44卓・196席)',remove=mid,
     add=[(2.7,10.8,1.2,1.85),(4.05,10.8,1.2,1.85)],hl=((14,8.9),(6,8.9)))
for x in (5.3,7.15):
    axs[1].add_patch(P.Rectangle((x,15.2),1.85,1.8,fc='#cfe8cf',ec='#2a7a2a',lw=1.2)); axs[1].text(x+.925,16.1,'6',ha='center',va='center',fontsize=6)
plt.tight_layout(); plt.savefig('p3_options2.png',dpi=130)

キッチン側をずらした版を描いたスクリプト plan3.py

exec(open('plan.py').read().split('fig,axs')[0])
import copy
S=1.5
for r in L['rooms']:
    if r['kind']=='back' and r['label']!='レジ内':
        r['rect']=[r['rect'][0]-S,r['rect'][1],r['rect'][2]-S,r['rect'][3]]
def extra(ax):
    for lab,(x0,y0,x1,y1) in [('受け渡し口',(12.5-S,9.4,15.5-S,9.8)),('ロボット待機',(15.7-S,8.55,18.1-S,9.35))]:
        ax.add_patch(P.Rectangle((x0,y0),x1-x0,y1-y0,fc='#333' if lab=='受け渡し口' else 'none',ec='#333',ls='-' if lab=='受け渡し口' else '--'))
fig,axs=plt.subplots(1,2,figsize=(12,5.2))
L0=json.load(open('/home/claude/p2m-site/public/sim/layouts/p3_relaxed_center.json'))['layout']
import builtins
Lsh=L; 
L=L0; draw(axs[0],'案1(キッチンはそのまま)',remove=('T19','T22'),add=[(24.8,12.5,1.2,1.85),(24.8,14.35,1.2,1.85)],hl=((14,8.6),(6,8.6)))
for lab,(x0,y0,x1,y1) in [('',(12.5,9.4,15.5,9.8))]: axs[0].add_patch(P.Rectangle((x0,y0),x1-x0,y1-y0,fc='#333'))
L=Lsh; draw(axs[1],'案1+キッチン側をまるごと左へ1.5m',remove=('T19','T22'),add=[(24.8,12.5,1.2,1.85),(24.8,14.35,1.2,1.85)],hl=((12.5,8.6),(6,8.6)))
extra(axs[1])
plt.tight_layout(); plt.savefig('p3_option1_shift.png',dpi=130)

作業ログ ― ⑤の店の形を直し、⑤だけ試算を計算し直した

店の形は、p2m-site の tools/sim_layouts/ にある作り方のコードから出ています。サイトの試算と3Dの店は、どちらもここから出たデータを読みます。直すのはこのコードの⑤の部分だけです。作り直したあと、②③④⑥⑦の出力が版の番号以外まったく同じであることを、ファイルごとに比べて確かめました。

店の形の作り方 famires_gen2.py の⑤の部分(直した版)

def p3_relaxed_center():
    W, D = 26.0, 17.0
    # 厨房側(パントリー・キッチン・洗い場・保存・更衣室・受け渡し口・待機場所)をまとめて左へ1.5m(2026-10-28 エイイチと決めた。
    # 右上を客席に使い、受け渡し口を混みやすい左側へ寄せる。キッチンの左と左の島の間は2.25m残る)
    rooms, walls, dish, sb, start = boh_top(W, D, 7.5, 17.5, 9.4, staff=[17.5, 14.5, 21.5, 17.0])
    toilet, twalls, tdoor = toilet_block([0.0, 14.6, 3.0, 17.0], "right", W, D)   # 左上の角。入口は右向き
    walls += twalls
    rooms += [toilet,
              *register([11.2, 0.3, 11.9, 2.8], [10.4, 0.3, 11.2, 2.8]),   # 入口の横に縦向き(前の通路をふさがない)
              dict(label="待合", rect=[15.4, 0.3, 15.9, 2.3], kind="guest"),   # 入口の右に縦向き(6人席の前をふさがない)
              dict(label="ドリンクバー", rect=[15.0, 4.6, 18.6, 5.3], kind="drink")]
    t = strip(0.0, 1.4, "v", 6, walls=walls)          # 左の壁ぞい(ボックスごとに仕切り・トイレの手前で止める)
    t += island(2.7, 3.4, "v", 5, walls=walls)
    # 真ん中の島は2段(2026-10-28 エイイチと決めた。前は3段で、上の端とパントリーの間が0.25mしかなく、
    # 受け渡し口から左側へ抜けられず、左の卓へ行くロボットが全部入口とレジの前を回っていた。上の2卓は右上の壁ぞいへ移した)
    t += island(6.75, 3.4, "v", 2, walls=walls)
    t += strip(24.8, 1.4, "v", 8, walls=walls)        # 右の壁ぞい(2026-10-28 に上へ2卓のばした。前は6卓)
    t += island(20.75, 3.4, "v", 5, walls=walls)
    t += strip(1.6, 0.0, "h", 4, seats=6, walls=walls)    # 家族用の6人ボックス(下の壁ぞい・左)
    t += strip(16.4, 0.0, "h", 4, seats=6, walls=walls)   # 同(右)。入口の右側
    return dict(name="⑤ ゆったり型・入口が正面の中央", style="ゆったり", outer=dict(w=W, d=D),
                entrance=dict(side="bottom", a0=12.0, a1=15.0), rooms=rooms, walls=walls, toilet_doors=[tdoor],
                dish_up=dish, robot_standby=sb, start=start, tables=t)
直したあとの⑤の図面とロボットの道。受け渡し口から島の上を通って左側へ抜けている

卓までの距離が変わったので、⑤の3,066条件だけ計算し直した

試算は、店の種類・スタッフの人数・ロボットの台数・来客のペースなどの組み合わせ32,850条件を、1条件40回ずつ回した平均です。前提が変わった⑤の3,066条件だけを計算し直し、ほかは前の結果を使い回しました。Claude のクラウドの作業環境(2コア)で約25分でした。

haizen_sim.py の実行ログ

32850 conditions, 29784 reused, 3066 to run
  100/3066
  200/3066
  300/3066
  400/3066
  500/3066
  600/3066
  700/3066
  800/3066
  900/3066
  1000/3066
  1100/3066
  1200/3066
  1300/3066
  1400/3066
  1500/3066
  1600/3066
  1700/3066
  1800/3066
  1900/3066
  2000/3066
  2100/3066
  2200/3066
  2300/3066
  2400/3066
  2500/3066
  2600/3066
  2700/3066
  2800/3066
  2900/3066
  3000/3066
32850 conditions written

直す前と後の試算を比べたスクリプト compare_p3_site.py

"""⑤の試算を、店の形を直す前(results_before.json)と後(results.json)で比べる(2026-10-28)
使い方: python3 compare_p3_site.py   (haizen_sim.py と同じフォルダで)"""
import json, haizen_sim as h
A = {h.key(r): r for r in json.load(open('results_before.json'))['rows']}
B = {h.key(r): r for r in json.load(open('results.json'))['rows']}
ch = {}
for k in B:
    if A[k] != B[k]:
        ch[k[0]] = ch.get(k[0], 0) + 1
print(ch)
s = h.STORES['fam_p3']
for st in s['staff']:
    for rb in (0, 1, 2):
        c = {'store': 'fam_p3', 'staff': st, 'robots': rb, 'arrivals_per_h': 46, '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', 'robot_share')))

compare_p3_site.py の出力

{'fam_p3': 3066}
3 0 entry_wait_mean:17.51→16.28 staff_wait_mean:9.69→8.99 dish_wait_mean:1.09→0.93 pay_wait_mean:24.18→23.12 robot_share:0.00→0.00
3 1 entry_wait_mean:8.21→8.44 staff_wait_mean:3.11→2.19 dish_wait_mean:2.38→2.28 pay_wait_mean:22.01→22.13 robot_share:0.73→0.75
3 2 entry_wait_mean:5.22→5.34 staff_wait_mean:1.35→1.20 dish_wait_mean:1.25→1.13 pay_wait_mean:19.22→20.01 robot_share:0.98→0.99
4 0 entry_wait_mean:5.44→6.22 staff_wait_mean:1.67→1.50 dish_wait_mean:0.63→0.57 pay_wait_mean:18.04→18.81 robot_share:0.00→0.00
4 1 entry_wait_mean:3.58→3.42 staff_wait_mean:0.82→0.77 dish_wait_mean:2.22→2.14 pay_wait_mean:13.77→12.95 robot_share:0.67→0.69
4 2 entry_wait_mean:2.40→3.67 staff_wait_mean:0.56→0.69 dish_wait_mean:1.35→1.24 pay_wait_mean:11.20→13.00 robot_share:0.97→0.98
5 0 entry_wait_mean:3.15→2.50 staff_wait_mean:0.71→0.64 dish_wait_mean:0.38→0.34 pay_wait_mean:12.39→12.98 robot_share:0.00→0.00
5 1 entry_wait_mean:3.02→2.50 staff_wait_mean:0.61→0.56 dish_wait_mean:2.09→2.03 pay_wait_mean:10.76→10.95 robot_share:0.65→0.66
5 2 entry_wait_mean:1.38→2.35 staff_wait_mean:0.37→0.44 dish_wait_mean:1.33→1.23 pay_wait_mean:8.70→10.51 robot_share:0.97→0.98

スタッフ4人・1時間46組(3Dの店で回す条件)では、料理の待ちはどの台数も少し短くなりました(0.63→0.57・2.22→2.14・1.35→1.24分)。卓までの距離が縮んだ分です。2台で入店待ちが2.4→3.7分に延びたのは、会計待ちが11.2→13.0分に延びたためです。試算では、食べ終えた組が卓に座ったままレジの順番を待つので、会計待ちが延びると卓が空かず、入店待ちも延びます。

ページの⑤だけを差し替えるスクリプト update_page_p3.py

公開中の試算のページは、全条件の結果と店の平面図を1つのデータとして持っています。⑤の行だけが変わったことを確かめてから結果を入れ替え、⑤の平面図を作り直しました。前の店の形から作った平面図が公開中のページと一致することを先に確かめ、作り方が同じであることを担保しています。

"""⑤の店の形を直したとき(2026-10-28)、公開中の試算のページの⑤だけを差し替える。
使い方: python3 update_page_p3.py <公開中のページ> <新しい results.json> <前の p3 の店の形> <新しい p3 の店の形> <新しい summary.json> <出力するページ>
- const D の r(結果):⑤(fam_p3)の行だけが変わっていることを確かめてから、全部を新しい結果に入れ替える
- const D の stores.fam_p3:卓までの距離(dist_m・dist_mean)を新しい値に
- const D の plans.fam_p3:⑤は卓の数の並びと厨房の位置が変わったので、平面図をまるごと作り直す
  (作り方は 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_p3"}, changed
D["r"] = rows

st = h.STORES["fam_p3"]
D["stores"]["fam_p3"]["dist_m"] = list(st["dist_m"])
D["stores"]["fam_p3"]["dist_mean"] = round(sum(st["dist_list"]) / len(st["dist_list"]), 1)
assert D["stores"]["fam_p3"]["tables"] == st["tables"] == 46
print("⑤の距離:", D["stores"]["fam_p3"]["dist_m"], D["stores"]["fam_p3"]["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_p3"], "前の店の形から作った平面図が公開中のページと違う"
D["plans"]["fam_p3"] = plan(new_lay)
print("⑤の平面図を作り直した(卓", len(D["plans"]["fam_p3"]["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"])
公開中の試算のページに出る、直したあとの⑤の平面図

作業ログ ― 3Dの店が⑤を建てられなかった:通路の端の点が外壁の上にあった

依頼文:直した⑤を建てて確かめる(20261028_18)

05_sec05.md3,129字・57行・markdown
---
作業フォルダ: /Users/shimazueiichi/Robotics_UX/ServiceSim
上限時間: 180
---
# 依頼:直した⑤(fam_p3)を Unity に建て、1回ずつ回して確かめる(2026-10-28・前の依頼 17 のやり直し)

前の依頼 17 は、サイトの公開が止まっていた(Cloudflare のビルドが一度失敗した)ため、始める前の確かめ5で止まった。今は公開されている。
別のタブで開く保存

報告:20261028_1401_p3_build_check2.txt

06_sec05.txt7,746字・182行・text
====================================================================
直した⑤(fam_p3)を建てて確かめる … ⑤が建たないので、建てる段で止めた
依頼:20261028_18_直した店5を建てて確かめる.md(依頼 17 のやり直し)
2026-10-28 14:01
====================================================================

結論
別のタブで開く保存

右の壁ぞいの列を奥の壁までのばしたら、通路の入口が「なし」になった

3Dの店は、ボックス席の列と列の間の通路(細い通路)ごとに、両端の0.8m外に「入口の点」を置き、受け渡し口から近い方をその通路の入口にしています。右の壁ぞいの列を上へ2卓のばしたので、列の上の端は y=16.2m になり、上の入口の点は y=17.0m、つまり奥の外壁の線の上に来ました。下の入口の点(y=0.6m)は、もともと6人席にふさがれて行けません。両端とも行けないので、作り方のコードはこの通路の入口を「なし」と書き出し、3Dの店はその通路を使う13卓を読めずに止まりました。

実際には、この通路は右の島の下からも上からも横に入れます。端の点の置き方の決まりが、列が壁まで届く形を想定していませんでした。直し方は3つ考え、サイト側の決まりを直す案をエイイチが選びました。両端とも行けないときだけ、端の点を通路の中へ0.1mずつ戻し、最初に行ける所に置き直します。片方でも行ける通路は前と同じなので、②③④⑥⑦の出力は版の番号以外変わりません。試算はこの点を使わないので、試算の数字も変わりません。

店の形の作り方 unity_export.py の aisle_entrances(直した版)

def aisle_entrances(aisles, grid, dist, dist_pass):
    """両端の入口の点の、受け渡し口の前からの道のり(ふだんの幅の道。行けなければ通れる幅の道)。短い方を entrance にする"""
    def reach(x, y):
        cy, cx = grid.cell(x, y)
        if 0 <= cy < grid.ny and 0 <= cx < grid.nx:
            for D in (dist, dist_pass):
                if D is not None and np.isfinite(D[cy, cx]):
                    return r2(D[cy, cx])
        return None

    for a in aisles:
        ds = [reach(x, y) for x, y in a["ends"]]
        if all(d is None for d in ds):
            # 両端とも行けないとき(端の点が外壁や別の卓に当たる)は、それぞれの端の点を通路の中へ0.1mずつ戻し、
            # 最初に行ける所に置き直す(2026-10-28 エイイチと決めた。⑤の右の壁ぞいの列を奥の壁までのばしたら、上の端の点が
            # 外壁の線の上に来て、通路の横から入れるのに入口なしになった)。片方でも行ける通路は今までどおりで変えない
            k = 1 if a["axis"] == "v" else 0
            (x0, y0), (x1, y1) = a["ends"]
            span = abs((y1 - y0) if k else (x1 - x0))
            for i in (0, 1):
                p, q = list(a["ends"][i]), a["ends"][1 - i]
                step = 0.1 if q[k] > p[k] else -0.1
                n = 1
                while n * 0.1 < span - 1e-6:
                    c = list(p)
                    c[k] = r2(p[k] + step * n)
                    d = reach(*c)
                    if d is not None:
                        a["ends"][i], ds[i] = c, d
                        break
                    n += 1
        a["end_dist"] = ds
        ok = [i for i, d in enumerate(ds) if d is not None]
        a["entrance"] = a["ends"][min(ok, key=lambda i: ds[i])] if ok else None

直した結果、この通路の入口は (24.05, 2.1)、右の島の下から入る所になりました。

依頼文:直した⑤を建てて確かめる・やり直し(20261028_19)

07_sec05.md3,678字・63行・markdown
---
作業フォルダ: /Users/shimazueiichi/Robotics_UX/ServiceSim
上限時間: 180
---
# 依頼:直した⑤(fam_p3)を Unity に建て、1回ずつ回して確かめる(2026-10-28・依頼 18 のやり直し)

前の依頼 17 は、サイトの公開が止まっていた(Cloudflare のビルドが一度失敗した)ため、始める前の確かめ5で止まった。今は公開されている。
別のタブで開く保存

報告:20261028_1440_p3_build_check3.txt

08_sec05.txt10,548字・212行・text
====================================================================
直した⑤(fam_p3)を建てて、1回ずつ回して確かめた(3回目)
依頼:20261028_19_直した店5を建てて確かめる_やり直し.md(依頼 18 のやり直し)
2026-10-28 14:40 check-in:cs:36 build_id cs36_20261028_1435(保留 0)
====================================================================

結論
別のタブで開く保存

1回ずつ(種0)では、入れた組の数が3回とも71組で、試算の91〜95組より少なく出ました。会計待ちも2〜3分で、試算のようにレジが詰まりませんでした。種0は③⑦でも来る客が少ない種でした。理由を先に調べず、種10個の夜で見ることにしました。スタッフが待つ点が2つしかない件(4人で2つを分ける)と、建てたときの確かめで出た2つの表示(細い通路の幅、人用の歩ける面のつながっていない所)は、今は直さず記録だけにしました。

作業ログ ― ⑤を種10個ずつ回すと、詰まっていたのは片付けと案内だった

依頼文:⑤の夜を回す(20261028_20)

---
作業フォルダ: /Users/shimazueiichi/Robotics_UX/ServiceSim
上限時間: 180
---
# 依頼:⑤の夜(30回)を回す(2026-10-28)

エイイチが「⑤の夜を回す」と決めた(2026-10-28 15:36)。⑤(fam_p3・店の形 d7bb919590d4)× ロボット0・1・2台 × 種0〜9、今の標準(すれ違い入・待機場所へ戻る 入・案B 切)。
依頼 19 の報告(20261028_1440_p3_build_check3.txt)の「決めてほしいこと」への答え:
- 1:回す(この依頼)
- 2:入れた組の数が71組と少ない件は、先に調べず、この夜の種10個で見る
- 3:スタッフが待つ点は2つ(2人ずつ同じ点)のまま
- 4:細い通路の幅の表示と、人用の NavMesh のつながっていない面は、今は直さず記録だけ

台帳の退避は Claude が済ませた。
- 退避先:/Volumes/KIOXIA/r2r2r-data/service_sim/unity/archive/unity_ledger_v1_prenight_20261028_p3/unity_ledger_v1.csv
- 568 行・md5 7ecd602ae377cb6fd213f5cdc306ff8d

## 始める前に確かめること(1つでも違えば回さずに報告して終わる)

1. Unity エディタが起動していない(起動していたら閉じずに報告して終わる)
2. /Volumes/KIOXIA がマウントされている。鍵ファイル unity_ledger_v1.lock がない
3. 本物の台帳の md5 が上の退避と同じ
4. ServiceSim の保留が 0 で、実行ファイルの build_info が cs36_20261028_1435・保留なし

## 回す

作業フォルダで、次の2つを順に実行する。night_runner.py は終わるまで待つ。

```
python3 tools/make_queue.py --stores fam_p3 --out queue_p3.json
python3 tools/night_runner.py --queue queue_p3.json --parallel 4 --night 20261103 --record-name 20261103_p3
```

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

## 報告

依頼箱の結果に加えて、claude_code_reports に 20261103_night_p3.txt として書く(場所:~/Library/Mobile Documents/com~apple~CloudDocs/デスクトップ/ADAPT DESIGN/じぶんの/PixelstoMotors/デジタルツイン学習R2R2R/サービスロボット導入シミュレーション/unity/claude_code_reports/)。
- 始める前の確かめ4つの結果
- runner_log のまとめ(completed の回数・失敗・止まった回・最長の実時間)
- 台帳の行数(568 → 598 になるはず)と、先頭 568 行の md5 が退避と同じか
- 全員が帰らなかった回があれば、その回の名前(原因の調べはしない)
- 台数ごと(0・1・2台)の種10個の中央値と最小・最大:入店待ち・そのうち席は空いているのに待った時間・料理の待ち・会計待ち・入れた組の数・ロボットが運んだ皿の割合・往復の数・30秒以上の止まり(1往復あたり)・動けなくなった(60秒)・瞬間移動・打ち切り・卓を空けた・冷めた皿の割合。試算の値(params の site_result)も並べる
- 種ごとの入れた組の数(種0〜9。台数で変わらなければ1行でよい)と、試算の組の数(約93組)との比
- 2台の30秒以上の止まりを、理由ごと・場所ごと(受け渡し口の点から 2.5 m 以内/待機場所/入口・レジの前=y が 3.4 m より下で x が 9.3〜16.4 m/スタッフが待つ点の近く 1.0 m 以内/そのほか)に、種10個の合計で
- ロボットを1台増やしたときの向き(入店待ち・料理の待ち)が、種の過半数で試算と同じか逆か(judge と同じ数え方)
- judge.md ができたか(⑤は基準がないので「基準なし」でよい。中身の判断はしない)

この依頼は、30回の途中で依頼箱の見張り係(Claude Code に依頼を渡す Mac の仕組み)を入れ替えたため、「失敗」の扱いになりました。30回を回す本体は止まらずに最後まで回り、台帳にも30行が足されました。書かれなかったのは Claude Code の報告だけなので、Claude が台帳と回の記録からまとめを書きました。

夜の実行ログ runner_log.txt

09_runner_log.txt8,544字・75行・text
2026-10-28 15:39:02  === 夜の実行係を始めます(night 20261103・同時 4 本・上限 90.0 分)===
2026-10-28 15:39:02  並べた回: queue_p3.json(30 回)
2026-10-28 15:39:02  台帳: /Volumes/KIOXIA/r2r2r-data/service_sim/unity/unity_ledger_v1.csv(59 列)
2026-10-28 15:39:02  版: ServiceSim/cs:36(Builds/headless/build_info.json)→ 出力フォルダの字 cs36
2026-10-28 15:39:02  並べた回の試算の版: v2.8 / 店の形の版: d7bb919590d4
2026-10-28 15:39:02  スリープを止めました(caffeinate pid 88774)
2026-10-28 15:39:02  並べた回を写しました: /Volumes/KIOXIA/r2r2r-data/service_sim/unity/night/20261103_p3/queue.json
2026-10-28 15:39:02  並べた回 30 / もう completed の回を飛ばす 0 / 回す 30
別のタブで開く保存

判定 judge.md

# 夜の結果の振り分け(20261103_night_*)

基準データ: 20261102_night_cs34_*(60回)/振り分けた回: 30回

切り替えの入切(条件の一部。同じ入切の基準の回とだけ比べる): 今回 すれ違い入・待機場所へ戻る入・案B切/基準 すれ違い入・待機場所へ戻る入・案B切

| 振り分け | 回数 |
|---|---|
| 正常 | 0 |
| 試算を見直す候補 | 0 |
| Unity の作り | 0 |
| 回の失敗 | 0 |
| 基準なし | 30 |

## 回の失敗

- なし

## 基準なし(基準データに同じ条件・同じ入切の回がないので判定していない)

- fam_p3 スタッフ4 ロボット0台・すれ違い入・待機場所へ戻る入・案B切
- fam_p3 スタッフ4 ロボット1台・すれ違い入・待機場所へ戻る入・案B切
- fam_p3 スタッフ4 ロボット2台・すれ違い入・待機場所へ戻る入・案B切

## Unity の作り(種の中央値が、基準の同じ条件の最大を超えた)

- なし

## 試算を見直す候補

### ロボットを増やしたときの向きが、種の過半数で試算と逆

- なし

### Unity÷試算 の大きさが、基準の同じ条件の範囲から外れた

- なし

## 記録(印にしない):試算との差の大きさ(条件ごとの種の中央値・Unity÷試算)

| 条件 | 種の数 | 入店待ち | 料理の待ち | 席は空いているのに待った |
|---|---|---|---|---|
| fam_p3 スタッフ4 ロボット0台・すれ違い入・待機場所へ戻る入・案B切 | 10 | 1.31 | 1.96 | 4.35 |
| fam_p3 スタッフ4 ロボット1台・すれ違い入・待機場所へ戻る入・案B切 | 10 | 1.93 | 1.21 | 5.94 |
| fam_p3 スタッフ4 ロボット2台・すれ違い入・待機場所へ戻る入・案B切 | 10 | 1.49 | 1.77 | 4.95 |

## すれ違い 入 と 切 の比べ(同じ夜・同じ条件・種の中央値。印にしない)

| 条件 | 入店待ち | 料理の待ち | 席は空いているのに待った | 動けなくなった | あきらめた | ロボットが運んだ割合 |
|---|---|---|---|---|---|---|
| fam_p3 スタッフ4 ロボット0台・すれ違い切・待機場所へ戻る入・案B切(0回) | - | - | - | - | - | - |
| fam_p3 スタッフ4 ロボット0台・すれ違い入・待機場所へ戻る入・案B切(10回) | 8.14 | 1.12 | 6.50 | 0.00 | 2.00 | 0.00 |
| fam_p3 スタッフ4 ロボット1台・すれ違い切・待機場所へ戻る入・案B切(0回) | - | - | - | - | - | - |
| fam_p3 スタッフ4 ロボット1台・すれ違い入・待機場所へ戻る入・案B切(10回) | 6.60 | 2.59 | 4.56 | 1.00 | 32.50 | 0.67 |
| fam_p3 スタッフ4 ロボット2台・すれ違い切・待機場所へ戻る入・案B切(0回) | - | - | - | - | - | - |
| fam_p3 スタッフ4 ロボット2台・すれ違い入・待機場所へ戻る入・案B切(10回) | 5.46 | 2.19 | 3.41 | 11.50 | 79.50 | 0.82 |

線: 立ち往生 30秒以上の止まり/向きは 5%・0.2分より小さい変化を数えない/外れは基準の同じ条件の最小〜最大

まとめたスクリプト night_p3_summary.py

"""⑤の夜(20261103_night_cs36・30回)を台帳と回の記録からまとめる(2026-10-28。Claude Code の報告が書かれなかったため Claude が書いた)
使い方: cd /Volumes/KIOXIA/r2r2r-data/service_sim/unity && python3 night_p3_summary.py"""
import csv, statistics as S, os, collections
r = [x for x in csv.DictReader(open('unity_ledger_v1.csv')) if x['run_folder'].startswith('20261103_night_cs36')]
print(len(r), collections.Counter(x['status'] for x in r), 'everyone_left', collections.Counter(x['everyone_left'] for x in r))
def f(v): return float(v) if v not in ('', None) else None
def m(xs):
    xs = [a for a in xs if a is not None]
    return f"{S.median(xs):.2f}({min(xs):.2f}〜{max(xs):.2f})" if xs else '-'
cols = [('entry_wait_mean', '入店待ち', 'site_entry_wait_mean'), ('staff_wait_mean', '席空き待ち', 'site_staff_wait_mean'),
        ('dish_wait_mean', '料理の待ち', 'site_dish_wait_mean'), ('pay_wait_mean', '会計待ち', 'site_pay_wait_mean'),
        ('robot_share', '運んだ割合', 'site_robot_share'), ('trips', '往復', None), ('stuck_count', '60秒', None),
        ('warped', '瞬間移動', None), ('timeouts', '打切', None), ('table_freed', '卓空け', None), ('cold_share', '冷めた', None)]
for x in r:
    x['groups'] = sum(1 for _ in open(os.path.join(x['run_folder'], 'groups.csv'))) - 1
for rb in '012':
    xs = [x for x in r if x['robots'] == rb]
    print(f'## {rb}台 n={len(xs)}')
    for c, l, s in cols:
        print(f"  {l}: {m([f(x[c]) for x in xs])}" + (f"  試算 {f(xs[0][s]):.2f}" if s and xs[0][s] else ''))
    print('  組:', m([x['groups'] for x in xs]))
print('種ごとの組:', {x['seed']: x['groups'] for x in r if x['robots'] == '0'})
cnt = collections.Counter(); causes = collections.Counter(); grid = collections.Counter(); gc = collections.Counter()
for x in r:
    if x['robots'] != '2':
        continue
    for s in csv.DictReader(open(os.path.join(x['run_folder'], 'stops.csv'))):
        if float(s['duration_s']) < 30:
            continue
        X, Y = float(s['x']), float(s['z'])
        if 14.2 <= X <= 16.6 and 8.55 <= Y <= 9.35: w = '待機場所'
        elif ((X - 12.5) ** 2 + (Y - 8.85) ** 2) ** .5 <= 2.5: w = '受け渡し口2.5m'
        elif Y < 3.4 and 9.3 <= X <= 16.4: w = '入口・レジ前'
        elif min(((X - 7.25) ** 2 + (Y - 10) ** 2) ** .5, ((X - 17.75) ** 2 + (Y - 10) ** 2) ** .5) <= 1.0: w = 'スタッフ待つ点'
        else: w = 'そのほか'
        cnt[w] += 1; causes[s['cause']] += 1
        k = (int(X // 2) * 2, int(Y // 2) * 2); grid[k] += 1; gc[(k, s['cause'])] += 1
print('2台30秒以上:', dict(cnt), dict(causes))
for k, v in grid.most_common(10):
    print(' ', k, v, [(c, n) for (kk, c), n in gc.items() if kk == k])

night_p3_summary.py の出力

30 Counter({'completed': 30}) everyone_left Counter({'1': 30})
## 0台 n=10
  入店待ち: 8.14(1.79〜20.07)  試算 6.22
  席空き待ち: 6.50(0.63〜11.73)  試算 1.50
  料理の待ち: 1.12(0.98〜1.23)  試算 0.57
  会計待ち: 5.72(2.37〜7.44)  試算 18.81
  運んだ割合: 0.00(0.00〜0.00)  試算 0.00
  往復: 0.00(0.00〜0.00)
  60秒: 0.00(0.00〜0.00)
  瞬間移動: 10.00(6.00〜19.00)
  打切: 0.00(0.00〜0.00)
  卓空け: 0.00(0.00〜0.00)
  冷めた: 0.00(0.00〜0.02)
  組: 91.50(71.00〜110.00)
## 1台 n=10
  入店待ち: 6.60(1.59〜16.59)  試算 3.42
  席空き待ち: 4.56(0.38〜7.45)  試算 0.77
  料理の待ち: 2.59(2.40〜2.78)  試算 2.14
  会計待ち: 7.17(2.98〜8.63)  試算 12.95
  運んだ割合: 0.67(0.62〜0.75)  試算 0.69
  往復: 68.00(59.00〜80.00)
  60秒: 1.00(0.00〜6.00)
  瞬間移動: 48.00(34.00〜56.00)
  打切: 0.00(0.00〜0.00)
  卓空け: 0.50(0.00〜6.00)
  冷めた: 0.35(0.32〜0.43)
  組: 91.50(71.00〜110.00)
## 2台 n=10
  入店待ち: 5.46(1.81〜20.45)  試算 3.67
  席空き待ち: 3.41(0.53〜11.50)  試算 0.69
  料理の待ち: 2.19(1.95〜3.46)  試算 1.24
  会計待ち: 6.98(3.87〜12.27)  試算 13.00
  運んだ割合: 0.82(0.71〜0.90)  試算 0.98
  往復: 132.50(97.00〜160.00)
  60秒: 11.50(2.00〜30.00)
  瞬間移動: 62.00(45.00〜81.00)
  打切: 4.00(1.00〜13.00)
  卓空け: 3.00(1.00〜6.00)
  冷めた: 0.25(0.18〜0.33)
  組: 91.50(71.00〜110.00)
種ごとの組: {'0': 71, '1': 94, '2': 110, '3': 85, '4': 101, '5': 83, '6': 107, '7': 89, '8': 89, '9': 98}
2台30秒以上: {'受け渡し口2.5m': 5, 'そのほか': 117, 'スタッフ待つ点': 8, '待機場所': 51, '入口・レジ前': 3} {'もう1台のロボット': 94, 'スタッフとすれ違った': 39, 'お客さんとすれ違った': 14, '人が立ち止まっていた': 33, '分からない': 4}
  (14, 8) 53 [('スタッフとすれ違った', 4), ('もう1台のロボット', 37), ('人が立ち止まっていた', 9), ('分からない', 2), ('お客さんとすれ違った', 1)]
  (4, 2) 21 [('もう1台のロボット', 21)]
  (8, 2) 17 [('もう1台のロボット', 12), ('お客さんとすれ違った', 1), ('分からない', 1), ('人が立ち止まっていた', 2), ('スタッフとすれ違った', 1)]
  (20, 2) 16 [('人が立ち止まっていた', 5), ('スタッフとすれ違った', 5), ('もう1台のロボット', 5), ('お客さんとすれ違った', 1)]
  (6, 2) 11 [('もう1台のロボット', 8), ('スタッフとすれ違った', 2), ('お客さんとすれ違った', 1)]
  (6, 8) 10 [('スタッフとすれ違った', 5), ('お客さんとすれ違った', 2), ('人が立ち止まっていた', 3)]
  (4, 12) 8 [('お客さんとすれ違った', 3), ('スタッフとすれ違った', 5)]
  (2, 12) 6 [('スタッフとすれ違った', 4), ('分からない', 1), ('人が立ち止まっていた', 1)]
  (12, 8) 5 [('もう1台のロボット', 2), ('スタッフとすれ違った', 2), ('人が立ち止まっていた', 1)]
  (2, 6) 5 [('スタッフとすれ違った', 2), ('人が立ち止まっていた', 3)]

まとめ:20261103_night_p3.txt

⑤の夜(20261103_p3・30回)のまとめ — Claude が台帳と回の記録から書いた(2026-10-28 16:20)

Claude Code の報告がない理由:回している途中(16:04)に見張り係を入れ替えたため、依頼 20 は「失敗」扱いになり、
Claude Code の報告は書かれなかった。night_runner は止まらず最後まで回った(30回とも completed・終了コード 0・全員帰った)。
台帳 568 → 598 行。判定 judge.md は night/20261103_p3/ にある(⑤は基準なし)。
版:cs36_20261028_1435・店の形 d7bb919590d4・試算 v2.8・すれ違い入・待機場所へ戻る 入・案B 切・スタッフ4人・46組/時・レジ1つ

種10個の中央値(最小〜最大)/試算
              0台                      1台                      2台
入店待ち      8.14(1.79〜20.07)/6.22    6.60(1.59〜16.59)/3.42    5.46(1.81〜20.45)/3.67
席空き待ち    6.50(0.63〜11.73)/1.50    4.56(0.38〜7.45)/0.77     3.41(0.53〜11.50)/0.69
料理の待ち    1.12(0.98〜1.23)/0.57     2.59(2.40〜2.78)/2.14     2.19(1.95〜3.46)/1.24
会計待ち      5.72(2.37〜7.44)/18.81    7.17(2.98〜8.63)/12.95    6.98(3.87〜12.27)/13.00
運んだ割合    0/0                      0.67(0.62〜0.75)/0.69     0.82(0.71〜0.90)/0.98
往復          0                        68(59〜80)               132.5(97〜160)
動けなくなった(60秒) 0                  1(0〜6)                  11.5(2〜30)
瞬間移動      10(6〜19)                48(34〜56)               62(45〜81)
打ち切り      0                        0                        4(1〜13)
卓を空けた    0                        0.5(0〜6)                3(1〜6)
冷めた皿      0.00                     0.35                     0.25

入れた組の数(種0〜9。台数で同じ):71, 94, 110, 85, 101, 83, 107, 89, 89, 98(中央値 91.5。試算 約93)
→ 依頼 19 で71組と少なかったのは種0だけのこと

2台の30秒以上の止まり(種10個の合計 184)
  場所:待機場所 51/受け渡し口の点から2.5m以内 5/入口・レジの前 3/スタッフが待つ点の近く 8/そのほか 117
  理由:もう1台のロボット 94/スタッフとすれ違った 39/人が立ち止まっていた 33/お客さんとすれ違った 14/分からない 4
  2m四方のマスで多い所:x14〜16・y8〜10(待機場所のまわり)53(うちロボットどうし37)/
    左下の6人席の前の通路 x4〜10・y2〜4 で計49(うちロボットどうし41)/右下の6人席の前 x20〜22・y2〜4 16

来る客の数は試算と同じで、71組は種0だけだった

入れた組の数は、種0〜9で71〜110組、中央値91.5組でした。試算は約93組です。1回目の確かめで少なく見えたのは、種0がたまたま少ない種だったためです。

ロボットを足すと待ちが縮む向きは、試算と同じだった

入店待ちは、ロボット0台8.1分→1台6.6分→2台5.5分と縮みました。試算は6.2→3.4→3.7分です。料理の待ちは、0台1.1分→1台2.6分→2台2.2分で、1台のときに延びて2台で戻る形が試算(0.6→2.1→1.2分)と同じでした。④では「ロボットを足すと入店待ちが延びる」逆の向きが出ましたが、⑤では出ませんでした。

試算はレジで詰まり、3Dの店は片付けと案内で詰まる

試算では会計待ちが13〜19分で、店が詰まる所はレジです。3Dの店の会計待ちは6〜7分で、レジは詰まっていません。代わりに、席は空いているのに案内を待った時間が、0台6.5分(試算1.5分)・1台4.6分(0.8分)・2台3.4分(0.7分)と長くなりました。

これは③⑦(42卓)で見たずれと同じ形です。③⑦では、3Dの店のスタッフは1組あたりの仕事が試算より1割ほど長く、ピークでスタッフ4人の手がすべてふさがり、いちばん後回しの片付けがたまっていました。試算はピークでスタッフの手が95%ふさがっているので、1割長いだけで手が足りなくなります。46卓の⑤でも、同じことが起きていると見ています。試算の歩く距離は「受け渡し口から卓まで」で、案内(入口から卓)と片付け(卓から洗い場)の道のりを数えていないことが、ずれの元の1つです。このずれは、③⑦のときに決めたとおり、試算には入れず記録して調べる対象にしています。

2台のときに残った詰まりは、待機場所のまわりと左下の通路

2台の回の30秒以上の止まりは、種10個の合計で184回でした。入口・レジの前は3回で、直した所では詰まっていません。残った詰まりは2か所です。

場所30秒以上の止まりそのうちロボットどうし
待機場所のまわり(受け渡し口の右)
53回37回
左下の6人席の前の通路49回41回
右下の6人席の前16回5回

待機場所のまわりは、③⑦でも見た形です。左下の6人席の前の通路は、6人席の天板(y=1.8m)と島の下の端(y=3.4m)の間の1.6mの通路で、ここでロボット2台が正面から出会っています。2台の回では打ち切りが中央値4回(1〜13回)あり、ロボットが運んだ皿の割合は0.82で、試算の0.98に届いていません。

作業ログ ― ⑤はここで区切り、⑥へ進む

④と同じく、⑤もここで区切りにしました。残った2か所の詰まりは直し続けず、記録して調べる対象にします。直すなら、店の形(サイト)を先に直します。次は⑥(ゆったり型・入口が左の壁)に広げます。

⑤で決めたことと、残したことは次のとおりです。

決めたこと・残したこと中身
基準データ v5
夜 20261102(③⑦・すれ違い入・待機場所へ戻る入・案B切・60回)。判定の既定を v5 にした
⑤の店の形
島を2段に、右の壁ぞいを8卓に、キッチン側を左へ1.5m。版 d7bb919590d4
細い通路の入口の点
両端とも行けないときだけ、通路の中へ戻して置く(サイトの作り方の決まり)
スタッフが待つ点
⑤は2つ(4人で2つを分ける)のまま
記録だけにしたもの
試算=レジ・3Dの店=片付けと案内、という詰まる所のずれ。⑤の待機場所のまわりと左下の通路の詰まり。建てたときの2つの表示