# 1回だけ使う:v2.9 の haizen_sim.py の中の値を、前提の表(assumptions.json)に書き出す import json, sys sys.path.insert(0, "/home/claude/v29") import haizen_sim as h D = "2026-10-31" def rec(v, unit, what, basis="仮置き", source="", updated=None, note=""): r = {"value": v, "unit": unit, "what": what, "basis": basis, "source": source, "n": None, "updated": updated or "2026-10-19"} if note: r["note"] = note return r C = h.COMMON common = { "staff_speed": rec(C["staff_speed"], "m/秒", "スタッフが歩く速さ"), "robot_speed": rec(C["robot_speed"], "m/秒", "ロボットが店内を走る速さ", note="Unity で測って戻す値(Unity の最高は0.6m/秒)。2026-10-24 に今のまま手を付けないと決めた"), "guide_s": rec(C["guide_s"], "秒", "案内(席の説明など。歩く時間は別)"), "staff_place_s": rec(C["staff_place_s"], "秒", "スタッフが卓に皿を置く"), "robot_handoff_s": rec(C["robot_handoff_s"], "秒", "客がロボットから皿を取る"), "pay_s": rec(C["pay_s"], "秒", "会計1組", "実感", "エイイチのファミレスの経験(1組90秒くらい)", "2026-10-25"), "call_s": rec(C["call_s"], "秒", "呼び出しへの対応(歩く時間は別)"), "clear_s": rec(C["clear_s"], "秒", "卓の皿をまとめる"), "wipe_s": rec(C["wipe_s"], "秒", "卓を拭いてセットする"), "load_s": rec(C["load_s"], "秒", "まとめた皿をロボットに載せる"), "guest_load_s": rec(C["guest_load_s"], "秒", "客が空いた皿をロボットに載せる(巡回して集めるとき)"), "pause_rate": rec(C["pause_rate"], "確率(1往復あたり)", "一時停止:人が前を横切ってロボットが止まる", note="Unity で測って戻す値"), "pause_s": rec(list(C["pause_s"]), "秒(最短, 最長)", "一時停止の長さ", note="Unity で測って戻す値"), "stuck_rate": rec(C["stuck_rate"], "確率(1往復あたり)", "立ち往生:スタッフが動かしに行かないと解けない", note="Unity で測って戻す値。LOG405 で Unity の方が多いと分かったが、今は変えないと決めた(2026-10-30)"), "rescue_s": rec(C["rescue_s"], "秒", "立ち往生したロボットをスタッフが動かす作業"), "hop_m": rec(C["hop_m"], "m", "1往復で複数の卓を回るときの、卓から次の卓への寄り道", note="試算だけの近似。Unity は実際の道を走る"), "fragile_cook": rec(list(C["fragile_cook"]), "分(最短, 最頻, 最長)", "デザート・ドリンクができるまで"), "cold_min": rec(C["cold_min"], "分", "これを超えて届いた皿を「待たせた皿」とする線", "決まり"), "dish_extra_m": rec(C["dish_extra_m"], "m", "洗い場が受け渡し口よりさらに奥にあるときの追加距離(店のタイプで上書き)"), "robot_first_wait_s": rec(C["robot_first_wait_s"], "秒", "料理はロボット優先。これだけ待ってもロボットが来なければスタッフが運ぶ", "決まり", "エイイチと決めた運用(料理はロボット最優先・2分待って来なければ人が運ぶ)", "2026-10-23"), "sustain": rec(C["sustain"], "", "回るかの確かめ(来客を止めない回し方)にするか", "設定"), "warmup_min": rec(C["warmup_min"], "分", "回るかの確かめで、数えない慣らしの時間", "設定"), "util_sample_s": rec(C["util_sample_s"], "秒", "手がふさがっている人数・台数を数える間隔", "設定"), "max_extra_min": rec(C["max_extra_min"], "分", "数える時間のあと、追いかけるのを打ち切る上限(回らない条件の保険)", "設定"), } assert list(common) == list(C) [:-1] or set(common) | {"model"} == set(C), set(C) ^ set(common) F = { # 店のタイプの項目の意味 "tables": ("卓", "卓の数"), "dist_m": ("m(最短, 最長)", "受け渡し口(洗い場)から卓までの距離の幅"), "peak_min": ("分", "ピークの長さ(この時間だけ選んだペースで来客する)"), "first_dishes": ("分(最短, 最頻, 最長)× 皿", "最初の注文の皿ごとの、料理ができるまで"), "extra_orders": ("回", "食事中の追加注文の回数(食べ放題)"), "extra_cook": ("分(最短, 最頻, 最長)", "追加注文の料理ができるまで"), "eat_min": ("分(最短, 最頻, 最長)", "食べている時間"), "call_rate": ("回/組", "1組あたりの呼び出しの回数の平均"), "bus_trips": ("往復", "下げ膳を人だけでやるときの往復回数(皿の量)"), "fragile": ("個/組", "1組あたりの倒れやすい物(デザート・ドリンク)の数の平均"), "dish_extra_m": ("m", "洗い場が受け渡し口よりさらに奥にあるときの追加距離"), "staff": ("人(少ない, 真ん中, 多い)", "最初に見せるスタッフの人数"), "staff_all": ("人", "「その他」で選べる人数(総当たりはこちら)"), "arrivals": ("組/時(空いている, 普通, 混んでいる)", "来客のペース"), "registers": ("台", "最初に見せるレジの数"), "registers_all": ("台", "選べるレジの数"), } stores = {} for k in ["small", "family", "large", "hotel", "buffet"]: s = h.STORES[k]; vals = {} for f, v in s.items(): if f == "label": continue v = json.loads(json.dumps(v)) basis, src, upd, note = "仮置き", "", "2026-10-19", "" if f == "peak_min" and v == 120: basis, src = "決まり", "エイイチと決めた:ファミレスはランチ・ディナーで混む時間が限られるので、ピークの2時間で区切る" if f in ("registers", "registers_all"): basis, src, upd = "決まり", "試算 v2.8 でエイイチと決めた(レジ1つ・2つを選べる。大型店は2つを最初に見せる)", "2026-10-25" if f == "dish_extra_m": basis, src = "公開事例", "洗い場が遠いホテルの店の導入事例(ホテル小倉)。距離は事例をもとにした仮の値" vals[f] = rec(v, F[f][0], F[f][1], basis, src, upd, note) stores[k] = {"label": s["label"], "values": vals} out = { "about": "サービスロボット導入シミュレーション(配膳ロボットの試算 haizen_sim.py)の前提の表。試算はこの表を読んで回す。値を直すときは、ここを直して git に残す", "model": C["model"], "basis_kinds": { "仮置き": "まだ根拠がない仮の値。現場・公開事例・Unity の値で置き換えていく", "実感": "エイイチの現場の経験(ファミレスで働いていたころ)", "公開事例": "メーカーの仕様・導入事例など、公開されている値", "Unity": "Unity(ServiceSim)で測った値", "現場": "現場で測った値(観察シートなど)。n に測った回数を書く", "決まり": "エイイチと決めた、試算の回し方・判定の線・運用の決まり", "設定": "試算の回し方の設定。店の前提ではない", }, "record_fields": {"value": "値", "unit": "単位", "what": "何の値か", "basis": "根拠の種類(basis_kinds)", "source": "出典・決めた経緯", "n": "現場で測った回数(測っていなければ null)", "updated": "値または根拠を最後に直した日", "note": "補足"}, "common": common, "stores": stores, "layout_stores": { "what": "図面のある店(②〜⑦)。標準ファミレス(family)をもとに、店の形から作る", "layout_dir": "../../public/sim/layouts", "labels": h.LAYOUT_LABELS, "rules": [ "卓の数と、受け渡し口から卓ごとの距離は店の形(*_analysis.json)から取る", "来客のペースは、標準ファミレスの3つを卓の数に比例させて丸める(最低1組/時)", "スタッフの真ん中の人数は、標準ファミレスの真ん中(3人)を卓の数に比例させて丸める(最低2人)。少ない・多いは ±1人、選べる幅は 真ん中-2〜真ん中+4(最低1人)", "それ以外は標準ファミレスと同じ", ], "basis": "決まり", "source": "エイイチと決めた(2026-10-21)", "updated": "2026-10-21", }, "choices": { "robots": rec(h.ROBOTS, "台", "最初に見せるロボットの台数", "設定"), "robots_all": rec(h.ROBOTS_ALL, "台", "「その他」で選べる台数(総当たりはこちら)", "決まり", "エイイチと決めた:5台・6台も選べるまま残す(ベストな状況だけ見せても納得されないため)", "2026-10-21"), "modes": rec(h.MODES, "", "ロボットの使い方(serve 上げ膳だけ/bus 下げ膳にも使う/patrol 食事中に回って集める)", "設定"), "trays": rec(h.TRAYS, "卓", "1往復で回る卓の数(1卓ずつ/最大3卓)", "設定"), "fragile_by": rec(h.FRAGILE_BY, "", "倒れやすい物を ロボットも運ぶ(any)/人だけが運ぶ(staff)", "設定"), "reps": rec(h.REPS, "回", "1条件を回す回数(結果はこの平均)", "設定"), }, "judge": { "ng_min": rec(h.NG_MIN, "分", "席は空いているのに待った時間がこれ以上なら「店が回らない」", "決まり", "試算 v2.2 でエイイチと決めた(5分だと厳しめ)", "2026-10-21"), "staff_full": rec(h.STAFF_FULL, "割合", "回るかの確かめで、スタッフの手がこれ以上ふさがっていたら「店が回らない」(ページでは使わない)", "設定"), "unstable_min": rec(h.UNSTABLE_MIN, "分", "参考:入店待ちがこれ以上延びていく条件(判定には使わない)", "設定"), }, } json.dump(out, open("/home/claude/p2m-site/tools/serving_sim/assumptions.json", "w", encoding="utf-8"), ensure_ascii=False, indent=1) print("ok")