"""試算の結果(results.json)から、公開用の試算ページ(serving-robot.html)を作る(v2.5)。 使い方: python3 build_page_v25.py results.json page_v25.template.html <出力先> v2.5:試算のモデルは v2.4 のまま、店の形(layouts/)を直した版に入れ替え、② 定番の郊外型だけ回し直した。 店の形の版(generation)がそろっているか、試算に使った卓までの距離が店の形の距離と同じかを確かめてから作る。 results.json は haizen_sim.py(v2.4)を総当たりで回した結果。v2.4 で入店待ちの終わりを卓に着いたときにし、 「下げ膳にも使う」でロボットがスタッフと一緒に卓へ向かい、載せ終えるまで待つ形に直した。 v2.3 で足したのは、標準ファミレスの中の「図面のある店」(fam_p0〜fam_p5)と、その平面図(D.plans)。 平面図は layouts/ の店の形(正は p2m-site の public/sim/layouts/)から、描くのに要る所だけを取り出す。 """ import json, os, sys import haizen_sim as h res_path, tpl_path, out = sys.argv[1], sys.argv[2], sys.argv[3] R = json.load(open(res_path, encoding="utf-8")) keys = ["store", "staff", "robots", "arrivals_per_h", "mode", "trays", "fragile_by", "dish_wait_mean", "dish_wait_p90", "cold_share", "entry_wait_mean", "full_wait_mean", "staff_wait_mean", "turn_mean", "walk_km_per_staff", "staff_util", "robot_util", "robot_share", "robot_bus_share", "collects", "rescues", "pauses", "fragile_robot", "groups"] rows = [] for r in R["rows"]: row = [round(r[k], 3) if i >= 7 else r[k] for i, k in enumerate(keys)] row.append(1 if r["staff_wait_mean"] >= h.NG_MIN else 0) # 丸める前の値で決める rows.append(row) # 図面のある店:画面で使う名前と平面図 stores = R["stores"] plans = {} q = lambda a: [round(v, 2) for v in a] for k, s in stores.items(): if not s.get("layout"): continue s["short"] = s["label"] s["label"] = f"標準ファミレス({s['short']})" s["dist_mean"] = round(sum(s["dist_list"]) / len(s["dist_list"]), 1) s.pop("dist_list", None) # ページには要らない(試算に使った距離は results.json と layouts/ にある) f = [x for x in os.listdir(h.LAYOUT_DIR) if x.startswith(s["layout"] + "_") and x.endswith(".json") and "_analysis" not in x][0] L = json.load(open(os.path.join(h.LAYOUT_DIR, f), encoding="utf-8"))["layout"] W, Dd = L["outer"]["w"], L["outer"]["d"] plans[k] = { "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"]], } # 店の形の版がそろっているか(layouts/ の summary・layout・analysis の generation が全部同じ)と、 # 試算に使った卓までの距離が、いまの店の形の距離と同じか gens = {g["generation"] for g in json.load(open(os.path.join(h.LAYOUT_DIR, "summary.json"), encoding="utf-8"))} for f in os.listdir(h.LAYOUT_DIR): if f.endswith(".json") and f != "summary.json": gens.add(json.load(open(os.path.join(h.LAYOUT_DIR, f), encoding="utf-8"))["meta"]["generation"]) if len(gens) != 1: sys.exit(f"店の形の版がそろっていない: {gens}") for f in os.listdir(h.LAYOUT_DIR): if f.endswith("_analysis.json"): nm = "fam_" + f.split("_")[0] dists = [t["dist"] for t in json.load(open(os.path.join(h.LAYOUT_DIR, f), encoding="utf-8"))["tables"]] if json.load(open(res_path, encoding="utf-8"))["stores"][nm]["dist_list"] != dists: sys.exit(f"{nm}: 試算に使った距離が、いまの店の形と違う(試算を回し直す)") layout_gen = gens.pop() D = {"layout_generation": layout_gen, "k": keys + ["ng"], "r": rows, "stores": stores, "common": R["common"], "plans": plans, "robots": R["robots"], "robots_all": R["robots_all"], "ng_min": h.NG_MIN} html = open(tpl_path, encoding="utf-8").read().replace("__DATA__", json.dumps(D, ensure_ascii=False, separators=(",", ":"))) open(out, "w", encoding="utf-8").write(html) print(len(html), "bytes /", len(rows), "conditions / 店が回らない", sum(r[-1] for r in rows), "/ 店の形の版", layout_gen)