# 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")
