awacke1 commited on
Commit
6ab7e68
·
verified ·
1 Parent(s): afa27c7

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +474 -0
app.py ADDED
@@ -0,0 +1,474 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ import pandas as pd
3
+ import plotly.express as px
4
+ import random
5
+ import uuid
6
+ import os
7
+ from datetime import datetime
8
+ from streamlit_flow import streamlit_flow
9
+ from streamlit_flow.elements import StreamlitFlowNode, StreamlitFlowEdge
10
+ from streamlit_flow.layouts import TreeLayout
11
+
12
+ # 🐱 Cat Rider and Gear Data
13
+ CAT_RIDERS = [
14
+ {"name": "Whiskers", "type": "Speed", "emoji": "🐾", "strength": 3, "skill": 7},
15
+ {"name": "Fluffy", "type": "Bravery", "emoji": "🦁", "strength": 5, "skill": 5},
16
+ {"name": "Midnight", "type": "Stealth", "emoji": "🌑", "strength": 4, "skill": 6},
17
+ {"name": "Bella", "type": "Charm", "emoji": "😺", "strength": 2, "skill": 8},
18
+ {"name": "Shadow", "type": "Mystery", "emoji": "👤", "strength": 4, "skill": 6},
19
+ {"name": "Simba", "type": "Royalty", "emoji": "🦁", "strength": 5, "skill": 7},
20
+ {"name": "Luna", "type": "Magic", "emoji": "🌙", "strength": 3, "skill": 8},
21
+ {"name": "Leo", "type": "Courage", "emoji": "🐯", "strength": 6, "skill": 5},
22
+ {"name": "Milo", "type": "Playful", "emoji": "😼", "strength": 4, "skill": 7},
23
+ {"name": "Nala", "type": "Grace", "emoji": "🐈", "strength": 5, "skill": 6}
24
+ ]
25
+
26
+ RIDING_GEAR = [
27
+ {"name": "Feathered Boots", "type": "Agility", "strength": 2},
28
+ {"name": "Golden Armor", "type": "Defense", "strength": 4},
29
+ {"name": "Magic Whisker Wand", "type": "Magic", "strength": 3},
30
+ {"name": "Sleek Shadow Cape", "type": "Stealth", "strength": 1}
31
+ ]
32
+
33
+ # 🌍 Game World Data (Expanded to 10 Situations)
34
+ SITUATIONS = [
35
+ {"id": "feline_escape", "name": "The Great Feline Escape", "description": "Your cat rider is trapped in an old mansion, which is about to be demolished. Using agility, wit, and bravery, orchestrate the perfect escape before the walls crumble! 🏚️", "emoji": "🚪", "type": "escape", "preferred_action": "agility"},
36
+ {"id": "lost_temple", "name": "The Treasure of the Lost Temple", "description": "On a quest to retrieve an ancient artifact, your cat rider must navigate through a labyrinth filled with traps and guardian spirits. Don't let the spooky ghosts get you! 👻", "emoji": "🏛️", "type": "exploration", "preferred_action": "resourcefulness"},
37
+ {"id": "royal_tournament", "name": "The Royal Tournament", "description": "Compete in a grand tournament where the finest cat riders showcase their skills and bravery to earn the title of the Royal Rider. Prepare for a showdown with noble feline adversaries! 🐱", "emoji": "👑", "type": "competition", "preferred_action": "bravery"},
38
+ {"id": "sky_race", "name": "The Sky Race", "description": "Compete in the annual Sky Race, where your cat rider flies across the skies on a magical broomstick! Watch out for lightning storms and mischievous crows! 🌩️", "emoji": "☁️", "type": "competition", "preferred_action": "agility"},
39
+ {"id": "cheese_heist", "name": "The Great Cheese Heist", "description": "Your cat rider must sneak into the royal pantry to steal the legendary Cheese of Destiny. Beware – the palace mice are guarding it! 🧀", "emoji": "🧀", "type": "heist", "preferred_action": "stealth"},
40
+ {"id": "pirate_cove", "name": "The Pirate Cove", "description": "Sail the high seas with your trusty crew of cats and uncover the secrets of Pirate Cove. Beware of the treacherous Sea Dogs! 🏴‍☠️", "emoji": "🏴‍☠️", "type": "exploration", "preferred_action": "bravery"},
41
+ {"id": "feline_moon_mission", "name": "The Feline Moon Mission", "description": "Blast off into space! Your mission is to plant the flag of Catopia on the moon. Pilot your rocket through an asteroid field! 🚀", "emoji": "🌕", "type": "exploration", "preferred_action": "resourcefulness"},
42
+ {"id": "purr_summit", "name": "The Purr Summit", "description": "Join a secret gathering of the most intellectual cats in the world. Engage in a battle of wits and wisdom to become the Grand Purr! 🧠", "emoji": "📜", "type": "debate", "preferred_action": "insight"},
43
+ {"id": "feline_invasion", "name": "The Feline Invasion", "description": "Aliens have invaded Earth and only your cat rider can save the planet! Use cunning strategies to repel the invaders! 👽", "emoji": "👽", "type": "battle", "preferred_action": "strategy"},
44
+ {"id": "eternal_catnap", "name": "The Eternal Catnap", "description": "You've entered a sacred temple where cats nap for centuries. Can you navigate the dream world and escape before you too are lulled into eternal slumber? 🛏️", "emoji": "💤", "type": "exploration", "preferred_action": "stealth"}
45
+ ]
46
+
47
+ # 🧠 Expanded Actions (10 Actions)
48
+ ACTIONS = [
49
+ {"id": "stealth", "name": "Use Stealth", "description": "Sneak past obstacles or enemies without being detected. You're like a ninja in the shadows! 🐾", "emoji": "🤫", "type": "skill"},
50
+ {"id": "agility", "name": "Showcase Agility", "description": "Perform impressive acrobatic maneuvers to overcome challenges. Cats always land on their feet, right? 🏃", "emoji": "🏃", "type": "physical"},
51
+ {"id": "charm", "name": "Charm Others", "description": "Use your cat's natural charisma to win over allies or distract foes. Who could resist those cute eyes? 😻", "emoji": "😻", "type": "social"},
52
+ {"id": "resourcefulness", "name": "Be Resourceful", "description": "Utilize the environment or items in creative ways to solve problems. Think on your paws! 🧠", "emoji": "🧠", "type": "mental"},
53
+ {"id": "bravery", "name": "Show Bravery", "description": "Face dangers head-on with your feline courage. Not all heroes wear capes – some wear fur! 🦁", "emoji": "🦁", "type": "physical"},
54
+ {"id": "strategy", "name": "Develop a Strategy", "description": "Use tactical thinking to outsmart opponents and gain the upper hand in battle. Brains over brawn! 🧠", "emoji": "🧠", "type": "mental"},
55
+ {"id": "speed", "name": "Sprint Away", "description": "Run faster than you've ever run before to escape danger. Like a cat fleeing a vacuum cleaner! 🏃‍♀️", "emoji": "🏃‍♀️", "type": "physical"},
56
+ {"id": "insight", "name": "Use Insight", "description": "Tap into ancient feline wisdom to solve puzzles and mysteries. A cat always knows! 🔮", "emoji": "🔮", "type": "mental"},
57
+ {"id": "distraction", "name": "Create a Distraction", "description": "Use cunning tricks and diversions to draw attention away from your real goal. Look over there! 🪄", "emoji": "🪄", "type": "mental"},
58
+ {"id": "negotiation", "name": "Negotiate", "description": "Use diplomacy and clever negotiation to get out of a tight spot. Every cat has their price! 💼", "emoji": "💼", "type": "social"}
59
+ ]
60
+
61
+ # Expanded conclusions for outcomes - 10 items each for success and failure
62
+ SUCCESS_CONCLUSIONS = [
63
+ "Your swift paws led you to victory! 🎉",
64
+ "You pounced at the perfect moment! 🏆",
65
+ "The stars aligned for your cat rider! 🌟",
66
+ "You navigated the challenge like a true feline champion! 🐱",
67
+ "Victory is sweet, just like a bowl of fresh milk! 🥛",
68
+ "Your opponents are left in awe of your skills! 😺",
69
+ "You’ve earned the title of Cat Commander! 🏅",
70
+ "All the other cats are jealous of your agility! 🏃‍♂️",
71
+ "Your strategy was flawless, and the victory is yours! 🎖️",
72
+ "Your cat rider is now a legend in the feline world! 👑"
73
+ ]
74
+
75
+ FAILURE_CONCLUSIONS = [
76
+ "You tried your best, but it just wasn’t enough. 😿",
77
+ "Maybe next time, kitty. Keep your tail up! 🐾",
78
+ "That didn’t go as planned. Time for a catnap to recover! 💤",
79
+ "Even the best cats have their off days. 😔",
80
+ "The challenge was too great this time. Better luck next time! 🍀",
81
+ "You might need more than nine lives to get through this. 🐈",
82
+ "The enemy was too clever for your plan. 🧠",
83
+ "You tripped over your own paws! 🐾",
84
+ "The cat gods were not in your favor today. 🙀",
85
+ "It’s okay, every cat has a learning curve. 📚"
86
+ ]
87
+
88
+ # Function to save history to a markdown file
89
+ def save_history_to_file(history_df, user_id):
90
+ timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
91
+ filename = f"history_{user_id}_{timestamp}.md"
92
+ markdown = create_markdown_preview(history_df)
93
+ with open(filename, 'w', encoding='utf-8') as f:
94
+ f.write(markdown)
95
+ return filename
96
+
97
+ # Function to load saved histories
98
+ def load_saved_histories():
99
+ history_files = [f for f in os.listdir('.') if f.startswith('history_') and f.endswith('.md')]
100
+ return history_files
101
+
102
+ # 🧠 Game Mechanics
103
+ def generate_situation():
104
+ return random.choice(SITUATIONS)
105
+
106
+ def generate_actions():
107
+ return random.sample(ACTIONS, min(3, len(ACTIONS)))
108
+
109
+ def evaluate_action(situation, action, gear_strength, rider_skill, history):
110
+ # Adjusted base success chance to around 50%
111
+ base_success_chance = 50
112
+
113
+ # Adjust success chance based on gear strength and rider skill
114
+ stat_modifier = (gear_strength + rider_skill - 10) * 2 # Assuming average stats sum to 10
115
+ success_chance = base_success_chance + stat_modifier
116
+
117
+ # Boost success chance for preferred action
118
+ if action['id'] == situation['preferred_action']:
119
+ success_chance += 10
120
+
121
+ # Adjust based on action history
122
+ if action['id'] in history:
123
+ success_chance += history[action['id']] * 2
124
+
125
+ # Clamp success chance between 5% and 95%
126
+ success_chance = max(5, min(95, success_chance))
127
+
128
+ outcome = random.randint(1, 100) <= success_chance
129
+ return outcome, success_chance
130
+
131
+ def generate_encounter_conclusion(situation, action, outcome):
132
+ if outcome:
133
+ return random.choice(SUCCESS_CONCLUSIONS)
134
+ else:
135
+ return random.choice(FAILURE_CONCLUSIONS)
136
+
137
+ # 🔄 Update character stats based on outcome
138
+ def update_character_stats(game_state, outcome):
139
+ if outcome:
140
+ # Increase stats on success
141
+ game_state['rider_skill'] += 0.5
142
+ game_state['gear_strength'] += 0.2
143
+ else:
144
+ # Decrease stats on failure, but not below 1
145
+ game_state['rider_skill'] = max(1, game_state['rider_skill'] - 0.3)
146
+ game_state['gear_strength'] = max(1, game_state['gear_strength'] - 0.1)
147
+ return game_state
148
+
149
+ # 🌳 Journey Visualization
150
+ def create_heterogeneous_graph(history_df):
151
+ nodes = []
152
+ edges = []
153
+ node_ids = {}
154
+ for index, row in history_df.iterrows():
155
+ situation_node_id = f"situation_{row['situation_id']}_{row['attempt']}"
156
+ action_node_id = f"action_{row['action_id']}_{index}"
157
+ outcome_node_id = f"outcome_{index}"
158
+
159
+ # Situation node
160
+ if situation_node_id not in node_ids:
161
+ situation_node = StreamlitFlowNode(
162
+ situation_node_id,
163
+ pos=(0, 0),
164
+ data={'content': f"{row['situation_emoji']} {row['situation_name']}"},
165
+ type='default',
166
+ sourcePosition='bottom',
167
+ targetPosition='top',
168
+ shape='ellipse'
169
+ )
170
+ nodes.append(situation_node)
171
+ node_ids[situation_node_id] = situation_node_id
172
+
173
+ # Action node
174
+ action_node = StreamlitFlowNode(
175
+ action_node_id,
176
+ pos=(0, 0),
177
+ data={'content': f"{row['action_emoji']} {row['action_name']}"},
178
+ type='default',
179
+ sourcePosition='bottom',
180
+ targetPosition='top',
181
+ shape='ellipse'
182
+ )
183
+ nodes.append(action_node)
184
+
185
+ # Outcome node with success celebration
186
+ outcome_content = '✅ Success' if row['outcome'] else '❌ Failure'
187
+ stars = '⭐' * int(row['score'])
188
+ outcome_node = StreamlitFlowNode(
189
+ outcome_node_id,
190
+ pos=(0, 0),
191
+ data={'content': f"{row['conclusion']}\n{outcome_content}\n{stars}"},
192
+ type='default',
193
+ sourcePosition='bottom',
194
+ targetPosition='top',
195
+ shape='ellipse'
196
+ )
197
+ nodes.append(outcome_node)
198
+
199
+ # Edges
200
+ edges.append(StreamlitFlowEdge(
201
+ id=f"edge_{situation_node_id}_{action_node_id}_{index}",
202
+ source=situation_node_id,
203
+ target=action_node_id,
204
+ animated=True
205
+ ))
206
+ edges.append(StreamlitFlowEdge(
207
+ id=f"edge_{action_node_id}_{outcome_node_id}_{index}",
208
+ source=action_node_id,
209
+ target=outcome_node_id,
210
+ animated=True
211
+ ))
212
+
213
+ return nodes, edges
214
+
215
+ # 📝 Markdown Preview with Subpoints for Each Action
216
+ def create_markdown_preview(history_df):
217
+ markdown = "## 🌳 Journey Preview\n\n"
218
+ grouped = history_df.groupby(['situation_name', 'attempt'], sort=False)
219
+
220
+ for (situation_name, attempt), group in grouped:
221
+ markdown += f"### {group.iloc[0]['situation_emoji']} **{situation_name}** (Attempt {attempt})\n"
222
+ for _, row in group.iterrows():
223
+ outcome_str = '✅ Success' if row['outcome'] else '❌ Failure'
224
+ stars = '⭐' * int(row['score'])
225
+ markdown += f"- {row['action_emoji']} **{row['action_name']}**: {outcome_str} {stars}\n"
226
+ markdown += f" - {row['conclusion']}\n"
227
+ markdown += "\n"
228
+ return markdown
229
+
230
+ # 🔄 Update game state with the result of the action
231
+ def update_game_state(game_state, situation, action, outcome, timestamp):
232
+ # Generate the encounter conclusion (success or failure)
233
+ conclusion = generate_encounter_conclusion(situation, action, outcome)
234
+
235
+ # Update stats based on the outcome
236
+ game_state = update_character_stats(game_state, outcome)
237
+
238
+ # Update attempt count
239
+ attempt = game_state['current_attempt']
240
+
241
+ # Create a new record for the history
242
+ new_record = pd.DataFrame({
243
+ 'user_id': [game_state['user_id']],
244
+ 'timestamp': [timestamp],
245
+ 'situation_id': [situation['id']],
246
+ 'situation_name': [situation['name']],
247
+ 'situation_emoji': [situation['emoji']],
248
+ 'situation_type': [situation['type']],
249
+ 'attempt': [attempt],
250
+ 'action_id': [action['id']],
251
+ 'action_name': [action['name']],
252
+ 'action_emoji': [action['emoji']],
253
+ 'action_type': [action['type']],
254
+ 'outcome': [outcome],
255
+ 'conclusion': [conclusion],
256
+ 'gear_strength': [game_state['gear_strength']],
257
+ 'rider_skill': [game_state['rider_skill']],
258
+ 'score': [game_state['score']]
259
+ })
260
+
261
+ # Add the new record to the game history DataFrame
262
+ game_state['history_df'] = pd.concat([game_state['history_df'], new_record], ignore_index=True)
263
+
264
+ # Update the history of actions (tracking how many times each action was used)
265
+ if action['id'] in game_state['history']:
266
+ game_state['history'][action['id']] += 1 if outcome else -1
267
+ else:
268
+ game_state['history'][action['id']] = 1 if outcome else -1
269
+
270
+ return game_state
271
+
272
+ # 🏅 Display Scoreboard with Star Emojis and Buckyball Outline
273
+ def display_scoreboard(game_state):
274
+ # Calculate number of star emojis based on score
275
+ score = game_state['score']
276
+ stars = '⭐' * int(score)
277
+
278
+ # Create buckyball style outline (simplified)
279
+ outline = ''
280
+ if score > 0:
281
+ outline = '''
282
+ ⬡ ⬡ ⬡ ⬡ ⬡
283
+ ⬡ ⬡ ⬡ ⬡
284
+ ⬡ ⬡ ⬡ ⬡ ⬡
285
+ ⬡ ⬡ ⬡ ⬡
286
+ ⬡ ⬡ ⬡ ⬡ ⬡
287
+ '''
288
+ else:
289
+ outline = 'No successes yet.'
290
+
291
+ st.markdown("## 🏅 Scoreboard")
292
+ st.markdown(f"**Score:** {stars} ({score})")
293
+ st.markdown(outline)
294
+
295
+ # 🎮 Main Game Application
296
+ def main():
297
+ st.title("🐱 Cat Rider 🏇")
298
+
299
+ # 📜 Game Rules
300
+ st.markdown("""
301
+ ### 📜 Game Rules
302
+ | Step | Description |
303
+ |------|-------------|
304
+ | 1️⃣ | Choose your Cat Rider |
305
+ | 2️⃣ | Select your Riding Gear |
306
+ | 3️⃣ | Set off on an Adventure |
307
+ | 4️⃣ | Encounter Challenges and Make Decisions |
308
+ | 5️⃣ | Complete the Quest and Grow Stronger |
309
+ """)
310
+
311
+ # 🏁 Initialize game state
312
+ if 'game_state' not in st.session_state:
313
+ st.session_state.game_state = {
314
+ 'user_id': str(uuid.uuid4()),
315
+ 'score': 0,
316
+ 'history': {},
317
+ 'gear_strength': 0,
318
+ 'rider_skill': 0,
319
+ 'cat_rider': None,
320
+ 'riding_gear': None,
321
+ 'history_df': pd.DataFrame(columns=['user_id', 'timestamp', 'situation_id', 'situation_name', 'situation_emoji', 'situation_type', 'attempt', 'action_id', 'action_name', 'action_emoji', 'action_type', 'outcome', 'conclusion', 'gear_strength', 'rider_skill', 'score']),
322
+ 'current_situation': None,
323
+ 'current_attempt': 1,
324
+ 'actions': [],
325
+ 'succeeded': False
326
+ }
327
+
328
+ # Sidebar functionality
329
+ st.sidebar.header("📂 Saved Histories")
330
+ history_files = load_saved_histories()
331
+ if history_files:
332
+ selected_history = st.sidebar.selectbox("Select a history to load:", history_files)
333
+ if st.sidebar.button("Load Selected History"):
334
+ with open(selected_history, 'r', encoding='utf-8') as f:
335
+ st.session_state.game_state['loaded_history'] = f.read()
336
+ st.sidebar.success(f"Loaded {selected_history}")
337
+
338
+ # 🐱 Cat Rider Selection
339
+ if st.session_state.game_state['cat_rider'] is None:
340
+ st.markdown("## Choose Your Cat Rider:")
341
+ cols = st.columns(len(CAT_RIDERS))
342
+ for i, rider in enumerate(CAT_RIDERS):
343
+ if cols[i].button(f"{rider['emoji']} {rider['name']} ({rider['type']})", key=f"rider_{i}"):
344
+ st.session_state.game_state['cat_rider'] = rider
345
+ st.session_state.game_state['rider_skill'] = rider['skill']
346
+ st.session_state.game_state['user_id'] = rider['name'] # Use rider name as user ID
347
+
348
+ # 🏇 Riding Gear Selection
349
+ if st.session_state.game_state['riding_gear'] is None and st.session_state.game_state['cat_rider'] is not None:
350
+ st.markdown("## Select Your Riding Gear:")
351
+ cols = st.columns(len(RIDING_GEAR))
352
+ for i, gear in enumerate(RIDING_GEAR):
353
+ if cols[i].button(f"{gear['name']} ({gear['type']})", key=f"gear_{i}"):
354
+ st.session_state.game_state['riding_gear'] = gear
355
+ st.session_state.game_state['gear_strength'] = gear['strength']
356
+
357
+ # 🎭 Game Loop
358
+ game_state = st.session_state.game_state
359
+
360
+ if game_state['cat_rider'] is not None and game_state['riding_gear'] is not None:
361
+ # Check if current_situation is None or if the player succeeded in the previous situation
362
+ if game_state['current_situation'] is None or game_state['succeeded']:
363
+ # Generate a new situation
364
+ game_state['current_situation'] = generate_situation()
365
+ game_state['current_attempt'] = 1
366
+ game_state['succeeded'] = False
367
+ # Clear actions for new situation
368
+ game_state['actions'] = []
369
+
370
+ situation = game_state['current_situation']
371
+ st.markdown(f"## {situation['emoji']} Current Situation: {situation['name']} ({situation['type']})")
372
+ st.markdown(situation['description'])
373
+ st.markdown("### 🎭 Choose your action:")
374
+
375
+ # Generate actions if not already generated
376
+ if not game_state['actions']:
377
+ game_state['actions'] = generate_actions()
378
+
379
+ cols = st.columns(3)
380
+ action_chosen = False
381
+ for i, action in enumerate(game_state['actions']):
382
+ if cols[i].button(f"{action['emoji']} {action['name']} ({action['type']})", key=f"action_{i}_{game_state['current_attempt']}"):
383
+ outcome, success_chance = evaluate_action(situation, action, game_state['gear_strength'], game_state['rider_skill'], game_state['history'])
384
+ timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
385
+
386
+ st.markdown(f"You decided to: **{action['name']}** ({action['type']})")
387
+ st.markdown(action['description'])
388
+ st.markdown(f"**Outcome:** {'✅ Success!' if outcome else '❌ Failure.'}")
389
+ st.markdown(f"**Success Chance:** {success_chance:.2f}%")
390
+
391
+ if outcome:
392
+ game_state['score'] += 1
393
+ game_state['succeeded'] = True
394
+ # Clear actions for next situation
395
+ game_state['actions'] = []
396
+ else:
397
+ game_state['current_attempt'] += 1
398
+ # Generate new actions for retry
399
+ game_state['actions'] = generate_actions()
400
+
401
+ # 🔄 Update game state
402
+ game_state = update_game_state(
403
+ game_state,
404
+ situation,
405
+ action,
406
+ outcome,
407
+ timestamp
408
+ )
409
+
410
+ # Display conclusion
411
+ conclusion = game_state['history_df'].iloc[-1]['conclusion']
412
+ st.markdown(f"**Encounter Conclusion:** {conclusion}")
413
+
414
+ # Display updated stats
415
+ st.markdown(f"**Updated Stats:**")
416
+ st.markdown(f"💪 Gear Strength: {game_state['gear_strength']:.2f}")
417
+ st.markdown(f"🏋️ Rider Skill: {game_state['rider_skill']:.2f}")
418
+
419
+ # 🏅 Display Scoreboard
420
+ display_scoreboard(game_state)
421
+
422
+ action_chosen = True
423
+ break # Exit the loop after action is taken
424
+
425
+ # If no action was chosen, show a message
426
+ if not action_chosen:
427
+ st.markdown("Please choose an action to proceed.")
428
+
429
+ # Integration point for both functions
430
+ if not game_state['history_df'].empty:
431
+ # 📝 Display Markdown Preview
432
+ st.markdown(create_markdown_preview(game_state['history_df']))
433
+
434
+ # 🌳 Display Heterogeneous Journey Graph
435
+ st.markdown("## 🌳 Your Journey (Heterogeneous Graph)")
436
+ nodes, edges = create_heterogeneous_graph(game_state['history_df'])
437
+ try:
438
+ streamlit_flow('cat_rider_flow',
439
+ nodes,
440
+ edges,
441
+ layout=TreeLayout(direction='down'),
442
+ fit_view=True,
443
+ height=600)
444
+ except Exception as e:
445
+ st.error(f"An error occurred while rendering the journey graph: {str(e)}")
446
+ st.markdown("Please try refreshing the page if the graph doesn't appear.")
447
+
448
+ # 📊 Character Stats Visualization
449
+ data = {"Stat": ["Gear Strength 🛡️", "Rider Skill 🏇"],
450
+ "Value": [game_state['gear_strength'], game_state['rider_skill']]}
451
+ df = pd.DataFrame(data)
452
+ fig = px.bar(df, x='Stat', y='Value', title="Cat Rider Stats 📊")
453
+ st.plotly_chart(fig)
454
+
455
+ # Save history to file
456
+ if st.button("💾 Save Game History"):
457
+ filename = save_history_to_file(game_state['history_df'], game_state['user_id'])
458
+ st.success(f"History saved to {filename}")
459
+ # Update history files list
460
+ history_files = load_saved_histories()
461
+
462
+ # Provide download buttons for saved histories
463
+ st.sidebar.markdown("### 📥 Download Histories")
464
+ for history_file in history_files:
465
+ with open(history_file, 'r', encoding='utf-8') as f:
466
+ st.sidebar.download_button(
467
+ label=f"Download {history_file}",
468
+ data=f.read(),
469
+ file_name=history_file,
470
+ mime='text/markdown'
471
+ )
472
+
473
+ if __name__ == "__main__":
474
+ main()