Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -1,5 +1,5 @@
|
|
| 1 |
# app.py
|
| 2 |
-
# @title Beer Game Final Version (v4.
|
| 3 |
|
| 4 |
# -----------------------------------------------------------------------------
|
| 5 |
# 1. Import Libraries
|
|
@@ -368,6 +368,7 @@ def plot_results(df: pd.DataFrame, title: str, human_role: str):
|
|
| 368 |
plot_data = []
|
| 369 |
for _, row in df.iterrows():
|
| 370 |
for e in echelons:
|
|
|
|
| 371 |
plot_data.append({'week': row.get('week', 0), 'echelon': e,
|
| 372 |
'inventory': row.get(f'{e}.inventory', 0), # Use end-of-week inventory for plots
|
| 373 |
'order_placed': row.get(f'{e}.order_placed', 0),
|
|
@@ -388,12 +389,14 @@ def plot_results(df: pd.DataFrame, title: str, human_role: str):
|
|
| 388 |
axes[1].legend()
|
| 389 |
axes[1].set_ylabel('Ordered/Produced (Units)')
|
| 390 |
|
| 391 |
-
|
|
|
|
| 392 |
total_costs = total_costs.set_index('echelon')['total_cost'].reindex(echelons, fill_value=0)
|
| 393 |
total_costs.plot(kind='bar', ax=axes[2], rot=0)
|
| 394 |
axes[2].set_title('Total Cumulative Cost')
|
| 395 |
axes[2].set_ylabel('Cost ($)')
|
| 396 |
|
|
|
|
| 397 |
human_cols = [f'{human_role}.initial_order', f'{human_role}.ai_suggestion', f'{human_role}.order_placed']
|
| 398 |
human_df_cols = ['week'] + [col for col in human_cols if col in df.columns]
|
| 399 |
human_df = df[human_df_cols].copy()
|
|
@@ -403,7 +406,7 @@ def plot_results(df: pd.DataFrame, title: str, human_role: str):
|
|
| 403 |
f'{human_role}.order_placed': 'Your Final Order'
|
| 404 |
}, inplace=True)
|
| 405 |
|
| 406 |
-
if len(human_df.columns) > 1:
|
| 407 |
human_df.plot(x='week', ax=axes[3], marker='o', linestyle='-')
|
| 408 |
axes[3].set_title(f'Analysis of Your ({human_role}) Decisions')
|
| 409 |
axes[3].set_ylabel('Order Quantity')
|
|
@@ -502,7 +505,6 @@ else:
|
|
| 502 |
**Conclusion:** Think 3 weeks ahead! Your order in Week 10 arrives at the start of Week 13.
|
| 503 |
""")
|
| 504 |
|
| 505 |
-
# =============== NEW: Understanding Inventory & Backlog ===============
|
| 506 |
st.subheader("4. Understanding Inventory & Backlog")
|
| 507 |
st.markdown("""
|
| 508 |
Managing your inventory and backlog is key to minimizing costs. Here's how they work:
|
|
@@ -510,20 +512,18 @@ else:
|
|
| 510 |
* **If you DON'T have enough inventory:**
|
| 511 |
* You ship **all** the inventory you have.
|
| 512 |
* The remaining unfilled "Orders to Fill" becomes your **new Backlog** for next week.
|
| 513 |
-
* **Backlog is cumulative!** If you
|
| 514 |
* **If you DO have enough inventory:**
|
| 515 |
* You ship all the "Orders to Fill".
|
| 516 |
* Your Backlog becomes 0.
|
| 517 |
* The remaining inventory is carried over to next week (and incurs holding costs).
|
| 518 |
""")
|
| 519 |
-
# ====================================================================
|
| 520 |
|
| 521 |
st.subheader("5. The Bullwhip Effect (What to Avoid)")
|
| 522 |
st.markdown("""
|
| 523 |
The "Bullwhip Effect" happens when small changes in customer demand cause **amplified**, chaotic swings in orders further up the supply chain (like you and the Factory). This often leads to cycles of **panic ordering** (ordering too much when out of stock) followed by **massive inventory pile-ups** (when late orders arrive). This cycle is very expensive. Try to order smoothly.
|
| 524 |
""")
|
| 525 |
|
| 526 |
-
# =============== UPDATED: How Each Week Works & Dashboard Explanation ===============
|
| 527 |
st.subheader("6. How Each Week Works & Understanding Your Dashboard")
|
| 528 |
st.markdown(f"""
|
| 529 |
Your main job is simple: place one order each week based on the dashboard presented to you.
|
|
@@ -549,7 +549,7 @@ else:
|
|
| 549 |
|
| 550 |
Submitting your final order ends the week. The system then calculates your `Weekly Cost` based on your inventory/backlog *after* Step 3 shipping, logs everything, and advances to the next week.
|
| 551 |
""")
|
| 552 |
-
|
| 553 |
|
| 554 |
st.markdown("---")
|
| 555 |
st.header("⚙️ Game Configuration")
|
|
@@ -566,7 +566,7 @@ else:
|
|
| 566 |
# --- Main Game Interface ---
|
| 567 |
elif 'game_state' in st.session_state and st.session_state.game_state.get('game_running'):
|
| 568 |
state = st.session_state.game_state
|
| 569 |
-
week, human_role, echelons, info_sharing = state['week'], state['echelons'], state['info_sharing']
|
| 570 |
# Define echelon order for display in the UI
|
| 571 |
echelon_order = ["Retailer", "Wholesaler", "Distributor", "Factory"]
|
| 572 |
|
|
|
|
| 1 |
# app.py
|
| 2 |
+
# @title Beer Game Final Version (v4.15 - Fixed Unpacking Error)
|
| 3 |
|
| 4 |
# -----------------------------------------------------------------------------
|
| 5 |
# 1. Import Libraries
|
|
|
|
| 368 |
plot_data = []
|
| 369 |
for _, row in df.iterrows():
|
| 370 |
for e in echelons:
|
| 371 |
+
# Safely access keys, provide default if missing (e.g., first few weeks)
|
| 372 |
plot_data.append({'week': row.get('week', 0), 'echelon': e,
|
| 373 |
'inventory': row.get(f'{e}.inventory', 0), # Use end-of-week inventory for plots
|
| 374 |
'order_placed': row.get(f'{e}.order_placed', 0),
|
|
|
|
| 389 |
axes[1].legend()
|
| 390 |
axes[1].set_ylabel('Ordered/Produced (Units)')
|
| 391 |
|
| 392 |
+
# Ensure total_cost calculation handles potential missing data gracefully
|
| 393 |
+
total_costs = plot_df.loc[plot_df.groupby('echelon')['week'].idxmax()] # Get row with max week for each echelon
|
| 394 |
total_costs = total_costs.set_index('echelon')['total_cost'].reindex(echelons, fill_value=0)
|
| 395 |
total_costs.plot(kind='bar', ax=axes[2], rot=0)
|
| 396 |
axes[2].set_title('Total Cumulative Cost')
|
| 397 |
axes[2].set_ylabel('Cost ($)')
|
| 398 |
|
| 399 |
+
# Safely access human decision columns
|
| 400 |
human_cols = [f'{human_role}.initial_order', f'{human_role}.ai_suggestion', f'{human_role}.order_placed']
|
| 401 |
human_df_cols = ['week'] + [col for col in human_cols if col in df.columns]
|
| 402 |
human_df = df[human_df_cols].copy()
|
|
|
|
| 406 |
f'{human_role}.order_placed': 'Your Final Order'
|
| 407 |
}, inplace=True)
|
| 408 |
|
| 409 |
+
if len(human_df.columns) > 1: # Check if there's data to plot
|
| 410 |
human_df.plot(x='week', ax=axes[3], marker='o', linestyle='-')
|
| 411 |
axes[3].set_title(f'Analysis of Your ({human_role}) Decisions')
|
| 412 |
axes[3].set_ylabel('Order Quantity')
|
|
|
|
| 505 |
**Conclusion:** Think 3 weeks ahead! Your order in Week 10 arrives at the start of Week 13.
|
| 506 |
""")
|
| 507 |
|
|
|
|
| 508 |
st.subheader("4. Understanding Inventory & Backlog")
|
| 509 |
st.markdown("""
|
| 510 |
Managing your inventory and backlog is key to minimizing costs. Here's how they work:
|
|
|
|
| 512 |
* **If you DON'T have enough inventory:**
|
| 513 |
* You ship **all** the inventory you have.
|
| 514 |
* The remaining unfilled "Orders to Fill" becomes your **new Backlog** for next week.
|
| 515 |
+
* **Backlog is cumulative!** If you start Week 10 with a backlog of 5, get an order for 8 (total needed = 13), receive 10 units, and ship those 10 units, your new backlog for Week 11 is `13 - 10 = 3`.
|
| 516 |
* **If you DO have enough inventory:**
|
| 517 |
* You ship all the "Orders to Fill".
|
| 518 |
* Your Backlog becomes 0.
|
| 519 |
* The remaining inventory is carried over to next week (and incurs holding costs).
|
| 520 |
""")
|
|
|
|
| 521 |
|
| 522 |
st.subheader("5. The Bullwhip Effect (What to Avoid)")
|
| 523 |
st.markdown("""
|
| 524 |
The "Bullwhip Effect" happens when small changes in customer demand cause **amplified**, chaotic swings in orders further up the supply chain (like you and the Factory). This often leads to cycles of **panic ordering** (ordering too much when out of stock) followed by **massive inventory pile-ups** (when late orders arrive). This cycle is very expensive. Try to order smoothly.
|
| 525 |
""")
|
| 526 |
|
|
|
|
| 527 |
st.subheader("6. How Each Week Works & Understanding Your Dashboard")
|
| 528 |
st.markdown(f"""
|
| 529 |
Your main job is simple: place one order each week based on the dashboard presented to you.
|
|
|
|
| 549 |
|
| 550 |
Submitting your final order ends the week. The system then calculates your `Weekly Cost` based on your inventory/backlog *after* Step 3 shipping, logs everything, and advances to the next week.
|
| 551 |
""")
|
| 552 |
+
|
| 553 |
|
| 554 |
st.markdown("---")
|
| 555 |
st.header("⚙️ Game Configuration")
|
|
|
|
| 566 |
# --- Main Game Interface ---
|
| 567 |
elif 'game_state' in st.session_state and st.session_state.game_state.get('game_running'):
|
| 568 |
state = st.session_state.game_state
|
| 569 |
+
week, human_role, echelons, info_sharing = state['week'], state['human_role'], state['echelons'], state['info_sharing']
|
| 570 |
# Define echelon order for display in the UI
|
| 571 |
echelon_order = ["Retailer", "Wholesaler", "Distributor", "Factory"]
|
| 572 |
|