Lilli98 commited on
Commit
43d8850
·
verified ·
1 Parent(s): 5f0621c

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +78 -68
app.py CHANGED
@@ -1,5 +1,5 @@
1
  # app.py
2
- # @title Beer Game Final Version (v4.8 - Unified Human-Like Prompts)
3
 
4
  # -----------------------------------------------------------------------------
5
  # 1. Import Libraries
@@ -57,7 +57,7 @@ else:
57
 
58
 
59
  # -----------------------------------------------------------------------------
60
- # 3. Core Game Logic Functions
61
  # -----------------------------------------------------------------------------
62
 
63
  def get_customer_demand(week: int) -> int:
@@ -115,13 +115,11 @@ def get_llm_order_decision(prompt: str, echelon_name: str) -> (int, str):
115
  st.error(f"API call failed for {echelon_name}: {e}")
116
  return 8, f"API_ERROR: {e}"
117
 
118
- # =============== MODIFIED FUNCTION (Unified Prompts) ===============
119
  def get_llm_prompt(echelon_state: dict, week: int, llm_personality: str, info_sharing: str, all_echelons_state: dict) -> str:
120
  """Generates the prompt for the LLM based on the game scenario."""
121
 
122
  base_info = f"Your Current Status at the **{echelon_state['name']}** for **Week {week}**:\n- On-hand inventory: {echelon_state['inventory']} units.\n- Backlog (unfilled orders): {echelon_state['backlog']} units.\n- Incoming order this week (from your customer): {echelon_state['incoming_order']} units.\n"
123
 
124
- # Define task word and role-specific info
125
  if echelon_state['name'] == 'Factory':
126
  task_word = "production quantity"
127
  base_info += f"- Production pipeline (completing in future weeks): {list(st.session_state.game_state['factory_production_pipeline'])}"
@@ -129,52 +127,39 @@ def get_llm_prompt(echelon_state: dict, week: int, llm_personality: str, info_sh
129
  task_word = "order quantity"
130
  base_info += f"- Shipments on the way to you: {list(echelon_state['incoming_shipments'])}\n- Orders you have placed being processed by your supplier: {list(echelon_state['order_pipeline'])}"
131
 
132
- # --- Perfect Rational (Unchanged from last version, logic is correct) ---
133
  if llm_personality == 'perfect_rational' and info_sharing == 'full':
134
  stable_demand = 8
135
- if echelon_state['name'] == 'Factory':
136
- total_lead_time = FACTORY_LEAD_TIME
137
- elif echelon_state['name'] == 'Distributor':
138
- total_lead_time = ORDER_PASSING_DELAY + FACTORY_LEAD_TIME + FACTORY_SHIPPING_DELAY
139
- else:
140
- total_lead_time = ORDER_PASSING_DELAY + SHIPPING_DELAY
141
-
142
  safety_stock = 4
143
  target_inventory_level = (stable_demand * total_lead_time) + safety_stock
144
-
145
  if echelon_state['name'] == 'Factory':
146
  inv_pos_components = f"(Inv: {echelon_state['inventory']} - Backlog: {echelon_state['backlog']} + In_Production: {sum(st.session_state.game_state['factory_production_pipeline'])})"
147
  inventory_position = (echelon_state['inventory'] - echelon_state['backlog'] + sum(st.session_state.game_state['factory_production_pipeline']))
148
  else:
149
  inv_pos_components = f"(Inv: {echelon_state['inventory']} - Backlog: {echelon_state['backlog']} + In_Transit: {sum(echelon_state['incoming_shipments'])} + In_Pipeline: {sum(echelon_state['order_pipeline'])})"
150
  inventory_position = (echelon_state['inventory'] - echelon_state['backlog'] + sum(echelon_state['incoming_shipments']) + sum(echelon_state['order_pipeline']))
151
-
152
  optimal_order = max(0, int(target_inventory_level - inventory_position))
153
-
154
  return f"**You are a perfectly rational supply chain AI with full system visibility.**\nYour only goal is to maintain stability and minimize costs based on mathematical optimization.\n**System Analysis:**\n* **Known Stable End-Customer Demand:** {stable_demand} units/week.\n* **Your Current Total Inventory Position:** {inventory_position} units. {inv_pos_components}\n* **Optimal Target Inventory Level:** {target_inventory_level} units (Target for {total_lead_time} weeks lead time).\n* **Mathematically Optimal {task_word.title()}:** The optimal decision is **{optimal_order} units**.\n**Your Task:** Confirm this optimal {task_word}. Respond with a single integer."
155
 
156
  elif llm_personality == 'perfect_rational' and info_sharing == 'local':
157
  safety_stock = 4; anchor_demand = echelon_state['incoming_order']
158
  inventory_correction = safety_stock - (echelon_state['inventory'] - echelon_state['backlog'])
159
-
160
  if echelon_state['name'] == 'Factory':
161
  supply_line = sum(st.session_state.game_state['factory_production_pipeline'])
162
  supply_line_desc = "In Production"
163
  else:
164
  supply_line = sum(echelon_state['incoming_shipments']) + sum(echelon_state['order_pipeline'])
165
  supply_line_desc = "Supply Line (In Transit + In Pipeline)"
166
-
167
  calculated_order = anchor_demand + inventory_correction - supply_line
168
  rational_local_order = max(0, int(calculated_order))
169
-
170
  return f"**You are a perfectly rational supply chain AI with ONLY LOCAL information.**\nYou must use a logical heuristic to make a stable decision. A proven method is \"Anchoring and Adjustment\".\n\n{base_info}\n\n**Rational Calculation (Anchoring & Adjustment):**\n1. **Anchor on Demand:** Your best guess for future demand is your last incoming order: **{anchor_demand} units**.\n2. **Adjust for Inventory:** You want to hold a safety stock of {safety_stock} units. Your current stock is {echelon_state['inventory'] - echelon_state['backlog']}. You need to order an extra **{inventory_correction} units** to correct this.\n3. **Account for {supply_line_desc}:** You already have **{supply_line} units** being processed. These should be subtracted from your new order.\n\n**Final Calculation:**\n* Decision = (Anchor Demand) + (Inventory Adjustment) - ({supply_line_desc})\n* Decision = {anchor_demand} + {inventory_correction} - {supply_line} = **{rational_local_order} units**.\n**Your Task:** Confirm this locally rational {task_word}. Respond with a single integer."
171
 
172
- # --- Human-like (Unified Prompts as requested) ---
173
  elif llm_personality == 'human_like' and info_sharing == 'full':
174
  full_info_str = f"\n**Full Supply Chain Information:**\n- End-Customer Demand this week: {get_customer_demand(week)} units.\n"
175
  for name, e_state in all_echelons_state.items():
176
  if name != echelon_state['name']: full_info_str += f"- {name}: Inventory={e_state['inventory']}, Backlog={e_state['backlog']}\n"
177
-
178
  return f"""
179
  **You are a supply chain manager ({echelon_state['name']}) with full system visibility.**
180
  You can see everyone's inventory and the real customer demand.
@@ -195,7 +180,6 @@ def get_llm_prompt(echelon_state: dict, week: int, llm_personality: str, info_sh
195
  Your gut instinct is to panic and {task_word.split(' ')[0]} enough to ensure you are never caught with a backlog again.
196
  **React emotionally.** What is your knee-jerk {task_word}? Respond with a single integer.
197
  """
198
- # ===============================================
199
 
200
  def step_game(human_final_order: int, human_initial_order: int, ai_suggestion: int):
201
  # This core logic function remains correct and unchanged.
@@ -316,64 +300,83 @@ else:
316
  # --- Game Setup & Instructions ---
317
  if 'game_state' not in st.session_state or not st.session_state.game_state.get('game_running', False):
318
 
 
319
  st.markdown("---")
320
  st.header("📖 Welcome to the Beer Game!")
321
- st.markdown("""
322
- The Beer Game is a classic supply chain simulation that demonstrates a phenomenon called the **"Bullwhip Effect."** Even with stable customer demand, small variations in orders can amplify as they move up the supply chain, causing massive shortages and overstocks.
323
- """)
324
- st.subheader("Your Goal")
325
- st.markdown("""
326
- Minimize the total cost for your position in the supply chain. Costs are incurred for:
327
- - **Holding Inventory:** **$0.50 per unit per week**
328
- - **Backlog (Unfilled Orders):** **$1.00 per unit per week**
329
- """)
330
 
331
- col1, col2 = st.columns(2)
332
- with col1:
333
- st.subheader("🔗 The Supply Chain")
334
- try:
335
- st.image(IMAGE_PATH, caption="Orders flow upstream (right), beer flows downstream (left).")
336
- except FileNotFoundError:
337
- st.warning("Image file not found. Please ensure 'beer_game_diagram.png' is uploaded to the repository.")
 
 
 
 
 
 
338
 
339
- st.markdown("""
340
- You will play the role of the **Distributor**. The other three roles (Retailer, Wholesaler, Factory) will be controlled by AI agents.
341
- - **Retailer (AI):** Fulfills end-customer demand. Orders from the Wholesaler.
342
- - **Wholesaler (AI):** Fulfills Retailer orders. Orders from the Distributor.
343
- - **Distributor (You):** Fulfills Wholesaler orders. Orders from the Factory.
344
- - **Factory (AI):** Fulfills your orders. Produces new beer.
345
  """)
346
 
347
- with col2:
348
- st.subheader("⏳ The Challenge: Delays!")
349
- st.markdown(f"""
350
- The key challenge is managing the **delays** in our specific game:
 
 
 
 
 
 
 
 
 
351
 
352
- * **Order Delay:** It takes **{ORDER_PASSING_DELAY} week** for your order to reach the Factory.
353
- * **Production Delay:** The Factory needs **{FACTORY_LEAD_TIME} week** to produce your order.
354
- * **Shipping Delay:** It takes **{FACTORY_SHIPPING_DELAY} week** for the Factory to ship the finished beer to you.
 
 
 
 
 
 
 
355
 
356
- This means there is a **{ORDER_PASSING_DELAY + FACTORY_LEAD_TIME + FACTORY_SHIPPING_DELAY}-week total lead time** from when you place an order to when you receive the beer. You must order for what you'll need 3 weeks from now!
357
  """)
358
 
359
- st.subheader("🎮 How Each Week Works")
360
- st.markdown(f"""
361
- Your main job is to place an order each week. The system handles the rest.
362
 
363
- **1. Automated Steps (Start of Week)**
364
- When a new week begins, the system first automates three steps based on past decisions:
365
- * **(Step 1: Shipments Arrive):** Shipments from the Factory (which you ordered {ORDER_PASSING_DELAY + FACTORY_LEAD_TIME + FACTORY_SHIPPING_DELAY} weeks ago) arrive and are added to your inventory.
366
- * **(Step 2: New Orders Arrive):** You receive a new incoming order from the Wholesaler.
367
- * **(Step 3: Ship Beer):** The system automatically ships as much beer as you have in stock to fulfill the Wholesaler's order, plus any leftover backlog. Any unfulfilled amount becomes your new backlog for next week.
 
368
 
369
- **2. Your Decision (Two-Step Process)**
370
- After the automated steps, you will see your new inventory and backlog. Now, it's your turn to perform **Step 4**:
371
- * **(Step 4a):** Based on your new status, submit your **initial order** to the Factory.
372
- * **(Step 4b):** After submitting, you will see an **AI suggestion**. Review it, then submit your **final order**.
373
 
374
- Submitting your final order advances the game to the next week, and the cycle repeats.
 
 
375
  """)
376
-
 
377
  st.markdown("---")
378
  st.header("⚙️ Game Configuration")
379
  c1, c2 = st.columns(2)
@@ -402,8 +405,13 @@ else:
402
  e, icon = echelons[name], "👤" if name == human_role else "🤖"
403
  st.markdown(f"##### {icon} {name} {'(You)' if name == human_role else ''}")
404
  st.metric("Inventory", e['inventory']); st.metric("Backlog", e['backlog'])
 
 
 
 
 
 
405
  st.write(f"Incoming Order: **{e['incoming_order']}**")
406
-
407
  if name == "Factory":
408
  prod_completing = list(state['factory_production_pipeline'])[0] if state['factory_production_pipeline'] else 0
409
  st.write(f"Production Completing: **{prod_completing}**")
@@ -419,6 +427,10 @@ else:
419
  col2.metric("Current Backlog", e['backlog'])
420
  col3.write(f"**Incoming Order (This Week):**\n# {e['incoming_order']}")
421
  col4.write(f"**Shipment Arriving (Next Week):**\n# {list(e['incoming_shipments'])[0] if e['incoming_shipments'] else 0}")
 
 
 
 
422
 
423
  st.markdown("---")
424
  st.header("Your Decision (Step 4)")
@@ -488,13 +500,11 @@ else:
488
  state = st.session_state.game_state
489
  logs_df = pd.json_normalize(state['logs'])
490
 
491
- # =============== FIXED Typo Bug ===============
492
  fig = plot_results(
493
  logs_df,
494
  f"Beer Game (Human: {state['human_role']})\n(AI: {state['llm_personality']} | Info: {state['info_sharing']})",
495
  state['human_role']
496
  )
497
- # ==============================================
498
 
499
  st.pyplot(fig)
500
  save_logs_and_upload(state)
 
1
  # app.py
2
+ # @title Beer Game Final Version (v4.9 - Detailed Intro & Real-time Cost)
3
 
4
  # -----------------------------------------------------------------------------
5
  # 1. Import Libraries
 
57
 
58
 
59
  # -----------------------------------------------------------------------------
60
+ # 3. Core Game Logic Functions (No changes in this section)
61
  # -----------------------------------------------------------------------------
62
 
63
  def get_customer_demand(week: int) -> int:
 
115
  st.error(f"API call failed for {echelon_name}: {e}")
116
  return 8, f"API_ERROR: {e}"
117
 
 
118
  def get_llm_prompt(echelon_state: dict, week: int, llm_personality: str, info_sharing: str, all_echelons_state: dict) -> str:
119
  """Generates the prompt for the LLM based on the game scenario."""
120
 
121
  base_info = f"Your Current Status at the **{echelon_state['name']}** for **Week {week}**:\n- On-hand inventory: {echelon_state['inventory']} units.\n- Backlog (unfilled orders): {echelon_state['backlog']} units.\n- Incoming order this week (from your customer): {echelon_state['incoming_order']} units.\n"
122
 
 
123
  if echelon_state['name'] == 'Factory':
124
  task_word = "production quantity"
125
  base_info += f"- Production pipeline (completing in future weeks): {list(st.session_state.game_state['factory_production_pipeline'])}"
 
127
  task_word = "order quantity"
128
  base_info += f"- Shipments on the way to you: {list(echelon_state['incoming_shipments'])}\n- Orders you have placed being processed by your supplier: {list(echelon_state['order_pipeline'])}"
129
 
 
130
  if llm_personality == 'perfect_rational' and info_sharing == 'full':
131
  stable_demand = 8
132
+ if echelon_state['name'] == 'Factory': total_lead_time = FACTORY_LEAD_TIME
133
+ elif echelon_state['name'] == 'Distributor': total_lead_time = ORDER_PASSING_DELAY + FACTORY_LEAD_TIME + FACTORY_SHIPPING_DELAY
134
+ else: total_lead_time = ORDER_PASSING_DELAY + SHIPPING_DELAY
 
 
 
 
135
  safety_stock = 4
136
  target_inventory_level = (stable_demand * total_lead_time) + safety_stock
 
137
  if echelon_state['name'] == 'Factory':
138
  inv_pos_components = f"(Inv: {echelon_state['inventory']} - Backlog: {echelon_state['backlog']} + In_Production: {sum(st.session_state.game_state['factory_production_pipeline'])})"
139
  inventory_position = (echelon_state['inventory'] - echelon_state['backlog'] + sum(st.session_state.game_state['factory_production_pipeline']))
140
  else:
141
  inv_pos_components = f"(Inv: {echelon_state['inventory']} - Backlog: {echelon_state['backlog']} + In_Transit: {sum(echelon_state['incoming_shipments'])} + In_Pipeline: {sum(echelon_state['order_pipeline'])})"
142
  inventory_position = (echelon_state['inventory'] - echelon_state['backlog'] + sum(echelon_state['incoming_shipments']) + sum(echelon_state['order_pipeline']))
 
143
  optimal_order = max(0, int(target_inventory_level - inventory_position))
 
144
  return f"**You are a perfectly rational supply chain AI with full system visibility.**\nYour only goal is to maintain stability and minimize costs based on mathematical optimization.\n**System Analysis:**\n* **Known Stable End-Customer Demand:** {stable_demand} units/week.\n* **Your Current Total Inventory Position:** {inventory_position} units. {inv_pos_components}\n* **Optimal Target Inventory Level:** {target_inventory_level} units (Target for {total_lead_time} weeks lead time).\n* **Mathematically Optimal {task_word.title()}:** The optimal decision is **{optimal_order} units**.\n**Your Task:** Confirm this optimal {task_word}. Respond with a single integer."
145
 
146
  elif llm_personality == 'perfect_rational' and info_sharing == 'local':
147
  safety_stock = 4; anchor_demand = echelon_state['incoming_order']
148
  inventory_correction = safety_stock - (echelon_state['inventory'] - echelon_state['backlog'])
 
149
  if echelon_state['name'] == 'Factory':
150
  supply_line = sum(st.session_state.game_state['factory_production_pipeline'])
151
  supply_line_desc = "In Production"
152
  else:
153
  supply_line = sum(echelon_state['incoming_shipments']) + sum(echelon_state['order_pipeline'])
154
  supply_line_desc = "Supply Line (In Transit + In Pipeline)"
 
155
  calculated_order = anchor_demand + inventory_correction - supply_line
156
  rational_local_order = max(0, int(calculated_order))
 
157
  return f"**You are a perfectly rational supply chain AI with ONLY LOCAL information.**\nYou must use a logical heuristic to make a stable decision. A proven method is \"Anchoring and Adjustment\".\n\n{base_info}\n\n**Rational Calculation (Anchoring & Adjustment):**\n1. **Anchor on Demand:** Your best guess for future demand is your last incoming order: **{anchor_demand} units**.\n2. **Adjust for Inventory:** You want to hold a safety stock of {safety_stock} units. Your current stock is {echelon_state['inventory'] - echelon_state['backlog']}. You need to order an extra **{inventory_correction} units** to correct this.\n3. **Account for {supply_line_desc}:** You already have **{supply_line} units** being processed. These should be subtracted from your new order.\n\n**Final Calculation:**\n* Decision = (Anchor Demand) + (Inventory Adjustment) - ({supply_line_desc})\n* Decision = {anchor_demand} + {inventory_correction} - {supply_line} = **{rational_local_order} units**.\n**Your Task:** Confirm this locally rational {task_word}. Respond with a single integer."
158
 
 
159
  elif llm_personality == 'human_like' and info_sharing == 'full':
160
  full_info_str = f"\n**Full Supply Chain Information:**\n- End-Customer Demand this week: {get_customer_demand(week)} units.\n"
161
  for name, e_state in all_echelons_state.items():
162
  if name != echelon_state['name']: full_info_str += f"- {name}: Inventory={e_state['inventory']}, Backlog={e_state['backlog']}\n"
 
163
  return f"""
164
  **You are a supply chain manager ({echelon_state['name']}) with full system visibility.**
165
  You can see everyone's inventory and the real customer demand.
 
180
  Your gut instinct is to panic and {task_word.split(' ')[0]} enough to ensure you are never caught with a backlog again.
181
  **React emotionally.** What is your knee-jerk {task_word}? Respond with a single integer.
182
  """
 
183
 
184
  def step_game(human_final_order: int, human_initial_order: int, ai_suggestion: int):
185
  # This core logic function remains correct and unchanged.
 
300
  # --- Game Setup & Instructions ---
301
  if 'game_state' not in st.session_state or not st.session_state.game_state.get('game_running', False):
302
 
303
+ # =============== NEW DETAILED INTRODUCTION ===============
304
  st.markdown("---")
305
  st.header("📖 Welcome to the Beer Game!")
306
+ st.markdown("This is a simulation of a supply chain. You will play against 3 AI agents. **You do not need any prior knowledge to play.** Please read these instructions carefully.")
 
 
 
 
 
 
 
 
307
 
308
+ st.subheader("1. Your Goal: Minimize Costs")
309
+ st.success("**Your single, most important goal is to: Minimize the total cost for your position in the supply chain.**")
310
+ st.markdown("You get costs from two things every week:")
311
+ st.markdown(f"""
312
+ - **Holding Inventory:** **${HOLDING_COST:,.2f} per unit per week.** (Holding 10 units costs $5.00)
313
+ - **Backlog (Unfilled Orders):** **${BACKLOG_COST:,.2f} per unit per week.** (Having 5 unfilled orders costs $5.00)
314
+ """)
315
+
316
+ with st.expander("Click to see a cost calculation example"):
317
+ st.markdown(f"""
318
+ Imagine at the end of Week 5, your dashboard shows:
319
+ - `Current Inventory: 20`
320
+ - `Current Backlog: 3`
321
 
322
+ Your cost for Week 5 would be:
323
+ - `(20 units of Inventory * ${HOLDING_COST:,.2f})` = $10.00
324
+ - `(3 units of Backlog * ${BACKLOG_COST:,.2f})` = $3.00
325
+ - **Total Weekly Cost:** = **$13.00**
326
+
327
+ Your goal is to keep this number as low as possible, every week.
328
  """)
329
 
330
+ st.subheader("2. Your Role: The Distributor")
331
+ st.markdown("""
332
+ You will always play as the **Distributor**. The other 3 roles are played by AI.
333
+
334
+ - **Retailer (AI):** Sells to the final customer.
335
+ - **Wholesaler (AI):** Sells to the Retailer.
336
+ - **Distributor (You):** You sell to the Wholesaler.
337
+ - **Factory (AI):** You order from the Factory.
338
+ """)
339
+ try:
340
+ st.image(IMAGE_PATH, caption="You are the Distributor. You get orders from the Wholesaler and place orders to the Factory.")
341
+ except FileNotFoundError:
342
+ st.warning("Image file not found. Please ensure 'beer_game_diagram.png' is uploaded to the repository.")
343
 
344
+ st.subheader("3. The Core Challenge: Delays!")
345
+ st.warning(f"This is the most important rule: **It takes {ORDER_PASSING_DELAY + FACTORY_LEAD_TIME + FACTORY_SHIPPING_DELAY} weeks for an order you place to actually arrive in your inventory.**")
346
+
347
+ with st.expander("Click to see a detailed example of the 3-week delay"):
348
+ st.markdown(f"""
349
+ Let's follow a single order you place:
350
+ * **Week 10 (You):** You decide you need 50 units. You place an order for **50**.
351
+ * **Week 11 (System):** Your order of 50 *arrives* at the Factory. (This is the **{ORDER_PASSING_DELAY} week Order Delay**). The Factory AI sees your order and decides to produce 50.
352
+ * **Week 12 (System):** The Factory *finishes* producing the 50 units. (This is the **{FACTORY_LEAD_TIME} week Production Delay**). The Factory ships the 50 units to you.
353
+ * **Week 13 (System):** The 50 units *arrive* at your warehouse. (This is the **{FACTORY_SHIPPING_DELAY} week Shipping Delay**). You can now use this inventory.
354
 
355
+ **Conclusion:** You must always think 3 weeks ahead. The order you place in Week 10 will not help you until Week 13.
356
  """)
357
 
358
+ st.subheader("4. The Bullwhip Effect (What to Avoid)")
359
+ st.markdown("""
360
+ The "Bullwhip Effect" is the main challenge of this game. It describes how small, normal changes in customer demand (at the Retailer) get **amplified** into huge, chaotic swings in orders as they move up the supply chain.
361
 
362
+ This often leads to a cycle of **panic ordering** (ordering way too much because you are out of stock) followed by a **massive pile-up of inventory** (when all your late orders finally arrive). This cycle is extremely expensive. Your goal is to avoid it by ordering smoothly.
363
+ """)
364
+
365
+ st.subheader("5. How Each Week Works (Your Task)")
366
+ st.markdown(f"""
367
+ Your main job is simple: place one order each week.
368
 
369
+ **A) At the start of every week, the system automatically does 3 things:**
370
+ * **(Step 1) Your Shipments Arrive:** The beer you ordered 3 weeks ago arrives and is added to your `Current Inventory`.
371
+ * **(Step 2) New Orders Arrive:** You receive a new `Incoming Order` from the Wholesaler.
372
+ * **(Step 3) You Ship Beer:** The system automatically ships as much beer as possible from your inventory to fulfill the Wholesaler's order (plus any old `Backlog`).
373
 
374
+ **B) After this, you will see your new dashboard and must make your 2-part decision:**
375
+ * **Step 4a (Initial Order):** Based on your new status, submit your **initial order** to the Factory.
376
+ * **Step 4b (Final Order):** You will then see an **AI suggestion**. Review it, then submit your **final order** to end the week.
377
  """)
378
+ # =======================================================
379
+
380
  st.markdown("---")
381
  st.header("⚙️ Game Configuration")
382
  c1, c2 = st.columns(2)
 
405
  e, icon = echelons[name], "👤" if name == human_role else "🤖"
406
  st.markdown(f"##### {icon} {name} {'(You)' if name == human_role else ''}")
407
  st.metric("Inventory", e['inventory']); st.metric("Backlog", e['backlog'])
408
+
409
+ # =============== NEW: REAL-TIME COST METRIC ===============
410
+ if name == human_role:
411
+ st.metric("Your Total Cost", f"${e['total_cost']:,.2f}")
412
+ # =========================================================
413
+
414
  st.write(f"Incoming Order: **{e['incoming_order']}**")
 
415
  if name == "Factory":
416
  prod_completing = list(state['factory_production_pipeline'])[0] if state['factory_production_pipeline'] else 0
417
  st.write(f"Production Completing: **{prod_completing}**")
 
427
  col2.metric("Current Backlog", e['backlog'])
428
  col3.write(f"**Incoming Order (This Week):**\n# {e['incoming_order']}")
429
  col4.write(f"**Shipment Arriving (Next Week):**\n# {list(e['incoming_shipments'])[0] if e['incoming_shipments'] else 0}")
430
+
431
+ # =============== NEW: REAL-TIME COST METRIC ===============
432
+ st.metric("Your Total Cumulative Cost", f"${e['total_cost']:,.2f}")
433
+ # =========================================================
434
 
435
  st.markdown("---")
436
  st.header("Your Decision (Step 4)")
 
500
  state = st.session_state.game_state
501
  logs_df = pd.json_normalize(state['logs'])
502
 
 
503
  fig = plot_results(
504
  logs_df,
505
  f"Beer Game (Human: {state['human_role']})\n(AI: {state['llm_personality']} | Info: {state['info_sharing']})",
506
  state['human_role']
507
  )
 
508
 
509
  st.pyplot(fig)
510
  save_logs_and_upload(state)