Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
@@ -1,15 +1,3 @@
|
|
1 |
-
# 1. Configuration
|
2 |
-
import streamlit as st
|
3 |
-
import pandas as pd
|
4 |
-
import plotly.express as px
|
5 |
-
import random
|
6 |
-
import uuid
|
7 |
-
import os
|
8 |
-
import re
|
9 |
-
from datetime import datetime
|
10 |
-
from streamlit_flow import streamlit_flow
|
11 |
-
from streamlit_flow.elements import StreamlitFlowNode, StreamlitFlowEdge
|
12 |
-
from streamlit_flow.layouts import RadialLayout
|
13 |
|
14 |
# Set page configuration to wide mode
|
15 |
Site_Name = '๐ฆCatRider๐'
|
@@ -32,6 +20,18 @@ if useConfig:
|
|
32 |
}
|
33 |
)
|
34 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
35 |
# ๐ฑ Cat Rider and Gear Data
|
36 |
CAT_RIDERS = [
|
37 |
{"name": "Whiskers", "type": "Speed", "emoji": "๐พ", "strength": 3, "skill": 7},
|
@@ -55,30 +55,30 @@ RIDING_GEAR = [
|
|
55 |
|
56 |
# ๐ Game World Data (Expanded to 10 Situations)
|
57 |
SITUATIONS = [
|
58 |
-
{"id": "feline_escape", "name": "The Great Feline Escape", "description": "Your cat rider is trapped in an old mansion
|
59 |
-
{"id": "lost_temple", "name": "The Treasure of the Lost Temple", "description": "On a quest to retrieve an ancient artifact
|
60 |
-
{"id": "royal_tournament", "name": "The Royal Tournament", "description": "Compete in a grand tournament
|
61 |
-
{"id": "sky_race", "name": "The Sky Race", "description": "Compete in the annual Sky Race
|
62 |
-
{"id": "cheese_heist", "name": "The Great Cheese Heist", "description": "Your cat rider must sneak into the royal pantry
|
63 |
-
{"id": "pirate_cove", "name": "The Pirate Cove", "description": "Sail the high seas with your trusty crew
|
64 |
-
{"id": "feline_moon_mission", "name": "The Feline Moon Mission", "description": "Blast off into space
|
65 |
-
{"id": "purr_summit", "name": "The Purr Summit", "description": "Join a secret gathering of the most intellectual cats
|
66 |
-
{"id": "feline_invasion", "name": "The Feline Invasion", "description": "Aliens have invaded Earth
|
67 |
-
{"id": "eternal_catnap", "name": "The Eternal Catnap", "description": "You've entered a sacred temple
|
68 |
]
|
69 |
|
70 |
# ๐ง Expanded Actions (10 Actions)
|
71 |
ACTIONS = [
|
72 |
-
{"id": "stealth", "name": "Use Stealth", "description": "Sneak past obstacles
|
73 |
-
{"id": "agility", "name": "Showcase Agility", "description": "Perform impressive acrobatic maneuvers
|
74 |
-
{"id": "charm", "name": "Charm Others", "description": "Use your cat's natural charisma
|
75 |
-
{"id": "resourcefulness", "name": "Be Resourceful", "description": "Utilize the environment or items
|
76 |
-
{"id": "bravery", "name": "Show Bravery", "description": "Face dangers head-on
|
77 |
-
{"id": "strategy", "name": "Develop a Strategy", "description": "Use tactical thinking
|
78 |
-
{"id": "speed", "name": "Sprint Away", "description": "Run faster than you've ever run
|
79 |
-
{"id": "insight", "name": "Use Insight", "description": "Tap into ancient feline wisdom
|
80 |
-
{"id": "distraction", "name": "Create a Distraction", "description": "Use cunning tricks
|
81 |
-
{"id": "negotiation", "name": "Negotiate", "description": "Use diplomacy and clever negotiation
|
82 |
]
|
83 |
|
84 |
# Expanded conclusions for outcomes - 10 items each for success and failure
|
@@ -112,55 +112,15 @@ FAILURE_CONCLUSIONS = [
|
|
112 |
def save_history_to_file(history_df, user_id):
|
113 |
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
|
114 |
filename = f"history_{user_id}_{timestamp}.md"
|
115 |
-
markdown
|
116 |
with open(filename, 'w', encoding='utf-8') as f:
|
117 |
f.write(markdown)
|
118 |
return filename
|
119 |
|
120 |
-
# Function to load saved histories
|
121 |
-
def load_saved_histories(
|
122 |
-
history_files = [f for f in os.listdir('.') if f.startswith(
|
123 |
-
history_files
|
124 |
-
combined_history = ''
|
125 |
-
for history_file in history_files:
|
126 |
-
with open(history_file, 'r', encoding='utf-8') as f:
|
127 |
-
combined_history += f.read() + '\n'
|
128 |
-
return combined_history
|
129 |
-
|
130 |
-
# Function to parse markdown history and reconstruct history DataFrame
|
131 |
-
def parse_history_markdown(markdown_text):
|
132 |
-
lines = markdown_text.split('\n')
|
133 |
-
data = []
|
134 |
-
current_situation = None
|
135 |
-
for line in lines:
|
136 |
-
situation_match = re.match(r"### (\S+) \*\*(.+)\*\*", line)
|
137 |
-
if situation_match:
|
138 |
-
situation_emoji = situation_match.group(1)
|
139 |
-
situation_name = situation_match.group(2)
|
140 |
-
continue
|
141 |
-
attempt_match = re.match(r"Attempt (\d+): (\S+) \*\*(.+)\*\*: (โ
Success|โ Failure) (\S*)", line)
|
142 |
-
if attempt_match:
|
143 |
-
attempt = int(attempt_match.group(1))
|
144 |
-
action_emoji = attempt_match.group(2)
|
145 |
-
action_name = attempt_match.group(3)
|
146 |
-
outcome_str = attempt_match.group(4)
|
147 |
-
stars = attempt_match.group(5)
|
148 |
-
outcome = True if outcome_str == 'โ
Success' else False
|
149 |
-
score = len(stars)
|
150 |
-
conclusion_line_index = lines.index(line) + 1
|
151 |
-
conclusion = lines[conclusion_line_index] if conclusion_line_index < len(lines) else ''
|
152 |
-
data.append({
|
153 |
-
'situation_name': situation_name,
|
154 |
-
'situation_emoji': situation_emoji,
|
155 |
-
'attempt': attempt,
|
156 |
-
'action_name': action_name,
|
157 |
-
'action_emoji': action_emoji,
|
158 |
-
'outcome': outcome,
|
159 |
-
'score': score,
|
160 |
-
'conclusion': conclusion
|
161 |
-
})
|
162 |
-
history_df = pd.DataFrame(data)
|
163 |
-
return history_df
|
164 |
|
165 |
# ๐ง Game Mechanics
|
166 |
def generate_situation():
|
@@ -209,95 +169,63 @@ def update_character_stats(game_state, outcome):
|
|
209 |
game_state['gear_strength'] = max(1, game_state['gear_strength'] - 0.1)
|
210 |
return game_state
|
211 |
|
212 |
-
# ๐ณ
|
213 |
-
def
|
214 |
-
markdown = "## ๐ณ Journey Preview\n\n"
|
215 |
nodes = []
|
216 |
edges = []
|
217 |
node_ids = {}
|
218 |
-
|
219 |
-
|
220 |
-
|
221 |
|
222 |
-
|
223 |
-
main_node_id = "main"
|
224 |
-
main_node = StreamlitFlowNode(
|
225 |
-
main_node_id,
|
226 |
-
pos=(0, 0),
|
227 |
-
data={'content': "# Your Journey"},
|
228 |
-
type='input',
|
229 |
-
target_position='bottom',
|
230 |
-
width=200
|
231 |
-
)
|
232 |
-
nodes.append(main_node)
|
233 |
-
|
234 |
-
for situation_name, group in grouped:
|
235 |
-
situation_emoji = group.iloc[0]['situation_emoji']
|
236 |
-
situation_id = group.iloc[0].get('situation_id', str(uuid.uuid4()))
|
237 |
-
situation_node_id = f"situation_{situation_id}"
|
238 |
-
|
239 |
-
markdown += f"### {situation_emoji} **{situation_name}**\n"
|
240 |
-
|
241 |
-
# Create situation node if not already created
|
242 |
if situation_node_id not in node_ids:
|
243 |
situation_node = StreamlitFlowNode(
|
244 |
situation_node_id,
|
245 |
pos=(0, 0),
|
246 |
-
data={'content': f"
|
247 |
type='default',
|
248 |
-
|
249 |
-
source_position='bottom',
|
250 |
-
width=200
|
251 |
)
|
252 |
nodes.append(situation_node)
|
253 |
node_ids[situation_node_id] = situation_node_id
|
254 |
|
255 |
-
|
256 |
-
|
257 |
-
|
258 |
-
|
259 |
-
|
260 |
-
|
261 |
-
)
|
262 |
-
|
263 |
-
|
264 |
-
|
265 |
-
|
266 |
-
|
267 |
-
|
268 |
-
|
269 |
-
|
270 |
-
|
271 |
-
|
272 |
-
|
273 |
-
|
274 |
-
|
275 |
-
|
276 |
-
|
277 |
-
|
278 |
-
|
279 |
-
|
280 |
-
|
281 |
-
pos=(0, 0),
|
282 |
-
data={'content': attempt_content},
|
283 |
-
type='output',
|
284 |
-
target_position='top',
|
285 |
-
source_position='bottom',
|
286 |
-
width=250
|
287 |
-
)
|
288 |
-
nodes.append(attempt_node)
|
289 |
-
|
290 |
-
# Edge from situation to attempt
|
291 |
-
edges.append(StreamlitFlowEdge(
|
292 |
-
id=f"edge_{situation_node_id}_{attempt_node_id}",
|
293 |
-
source=situation_node_id,
|
294 |
-
target=attempt_node_id,
|
295 |
-
animated=True
|
296 |
-
))
|
297 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
298 |
markdown += "\n"
|
299 |
-
|
300 |
-
return markdown, nodes, edges
|
301 |
|
302 |
# ๐ Update game state with the result of the action
|
303 |
def update_game_state(game_state, situation, action, outcome, timestamp):
|
@@ -310,10 +238,6 @@ def update_game_state(game_state, situation, action, outcome, timestamp):
|
|
310 |
# Update attempt count
|
311 |
attempt = game_state['current_attempt']
|
312 |
|
313 |
-
# Update score
|
314 |
-
if outcome:
|
315 |
-
game_state['score'] += 1
|
316 |
-
|
317 |
# Create a new record for the history
|
318 |
new_record = pd.DataFrame({
|
319 |
'user_id': [game_state['user_id']],
|
@@ -343,9 +267,6 @@ def update_game_state(game_state, situation, action, outcome, timestamp):
|
|
343 |
else:
|
344 |
game_state['history'][action['id']] = 1 if outcome else -1
|
345 |
|
346 |
-
# Automatically save history after each action
|
347 |
-
save_history_to_file(game_state['history_df'], game_state['user_id'])
|
348 |
-
|
349 |
return game_state
|
350 |
|
351 |
# ๐
Display Scoreboard with Star Emojis and Buckyball Outline
|
@@ -390,7 +311,7 @@ def main():
|
|
390 |
# ๐ Initialize game state
|
391 |
if 'game_state' not in st.session_state:
|
392 |
st.session_state.game_state = {
|
393 |
-
'user_id':
|
394 |
'score': 0,
|
395 |
'history': {},
|
396 |
'gear_strength': 0,
|
@@ -404,38 +325,38 @@ def main():
|
|
404 |
'succeeded': False
|
405 |
}
|
406 |
|
407 |
-
|
408 |
-
|
409 |
-
|
410 |
-
if
|
411 |
-
st.
|
412 |
-
|
413 |
-
|
414 |
-
|
|
|
|
|
|
|
|
|
|
|
415 |
cols = st.columns(len(CAT_RIDERS))
|
416 |
for i, rider in enumerate(CAT_RIDERS):
|
417 |
if cols[i].button(f"{rider['emoji']} {rider['name']} ({rider['type']})", key=f"rider_{i}"):
|
418 |
-
game_state['cat_rider'] = rider
|
419 |
-
game_state['rider_skill'] = rider['skill']
|
420 |
-
game_state['user_id'] = rider['name'] # Use rider name as user ID
|
421 |
-
|
422 |
-
# Load existing history if available
|
423 |
-
existing_history = load_saved_histories(game_state['user_id'])
|
424 |
-
if existing_history:
|
425 |
-
history_df = parse_history_markdown(existing_history)
|
426 |
-
game_state['history_df'] = history_df
|
427 |
-
game_state['score'] = history_df['score'].max() if not history_df.empty else 0
|
428 |
|
429 |
# ๐ Riding Gear Selection
|
430 |
-
if game_state['riding_gear'] is None and game_state['cat_rider'] is not None:
|
431 |
st.markdown("## Select Your Riding Gear:")
|
432 |
cols = st.columns(len(RIDING_GEAR))
|
433 |
for i, gear in enumerate(RIDING_GEAR):
|
434 |
if cols[i].button(f"{gear['name']} ({gear['type']})", key=f"gear_{i}"):
|
435 |
-
game_state['riding_gear'] = gear
|
436 |
-
game_state['gear_strength'] = gear['strength']
|
437 |
|
438 |
# ๐ญ Game Loop
|
|
|
|
|
439 |
if game_state['cat_rider'] is not None and game_state['riding_gear'] is not None:
|
440 |
# Check if current_situation is None or if the player succeeded in the previous situation
|
441 |
if game_state['current_situation'] is None or game_state['succeeded']:
|
@@ -468,6 +389,7 @@ def main():
|
|
468 |
st.markdown(f"**Success Chance:** {success_chance:.2f}%")
|
469 |
|
470 |
if outcome:
|
|
|
471 |
game_state['succeeded'] = True
|
472 |
# Clear actions for next situation
|
473 |
game_state['actions'] = []
|
@@ -506,21 +428,19 @@ def main():
|
|
506 |
|
507 |
# Integration point for both functions
|
508 |
if not game_state['history_df'].empty:
|
509 |
-
# ๐ Process Journey History to get markdown and graph data
|
510 |
-
markdown_preview, nodes, edges = process_journey_history(game_state['history_df'])
|
511 |
-
|
512 |
# ๐ Display Markdown Preview
|
513 |
-
st.markdown(
|
514 |
|
515 |
# ๐ณ Display Knowledge Journey Graph
|
516 |
st.markdown("## ๐ณ Your Journey (Knowledge Graph)")
|
|
|
517 |
try:
|
518 |
streamlit_flow('cat_rider_flow',
|
519 |
nodes,
|
520 |
edges,
|
521 |
-
layout=
|
522 |
fit_view=True,
|
523 |
-
height=
|
524 |
except Exception as e:
|
525 |
st.error(f"An error occurred while rendering the journey graph: {str(e)}")
|
526 |
st.markdown("Please try refreshing the page if the graph doesn't appear.")
|
@@ -532,12 +452,24 @@ def main():
|
|
532 |
fig = px.bar(df, x='Stat', y='Value', title="Cat Rider Stats ๐")
|
533 |
st.plotly_chart(fig)
|
534 |
|
535 |
-
|
536 |
-
|
537 |
-
|
538 |
-
|
539 |
-
|
540 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
541 |
|
542 |
if __name__ == "__main__":
|
543 |
main()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
|
2 |
# Set page configuration to wide mode
|
3 |
Site_Name = '๐ฆCatRider๐'
|
|
|
20 |
}
|
21 |
)
|
22 |
|
23 |
+
|
24 |
+
import streamlit as st
|
25 |
+
import pandas as pd
|
26 |
+
import plotly.express as px
|
27 |
+
import random
|
28 |
+
import uuid
|
29 |
+
import os
|
30 |
+
from datetime import datetime
|
31 |
+
from streamlit_flow import streamlit_flow
|
32 |
+
from streamlit_flow.elements import StreamlitFlowNode, StreamlitFlowEdge
|
33 |
+
from streamlit_flow.layouts import TreeLayout
|
34 |
+
|
35 |
# ๐ฑ Cat Rider and Gear Data
|
36 |
CAT_RIDERS = [
|
37 |
{"name": "Whiskers", "type": "Speed", "emoji": "๐พ", "strength": 3, "skill": 7},
|
|
|
55 |
|
56 |
# ๐ Game World Data (Expanded to 10 Situations)
|
57 |
SITUATIONS = [
|
58 |
+
{"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"},
|
59 |
+
{"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"},
|
60 |
+
{"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"},
|
61 |
+
{"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"},
|
62 |
+
{"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"},
|
63 |
+
{"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"},
|
64 |
+
{"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"},
|
65 |
+
{"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"},
|
66 |
+
{"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"},
|
67 |
+
{"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"}
|
68 |
]
|
69 |
|
70 |
# ๐ง Expanded Actions (10 Actions)
|
71 |
ACTIONS = [
|
72 |
+
{"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"},
|
73 |
+
{"id": "agility", "name": "Showcase Agility", "description": "Perform impressive acrobatic maneuvers to overcome challenges. Cats always land on their feet, right? ๐", "emoji": "๐", "type": "physical"},
|
74 |
+
{"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"},
|
75 |
+
{"id": "resourcefulness", "name": "Be Resourceful", "description": "Utilize the environment or items in creative ways to solve problems. Think on your paws! ๐ง ", "emoji": "๐ง ", "type": "mental"},
|
76 |
+
{"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"},
|
77 |
+
{"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"},
|
78 |
+
{"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"},
|
79 |
+
{"id": "insight", "name": "Use Insight", "description": "Tap into ancient feline wisdom to solve puzzles and mysteries. A cat always knows! ๐ฎ", "emoji": "๐ฎ", "type": "mental"},
|
80 |
+
{"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"},
|
81 |
+
{"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"}
|
82 |
]
|
83 |
|
84 |
# Expanded conclusions for outcomes - 10 items each for success and failure
|
|
|
112 |
def save_history_to_file(history_df, user_id):
|
113 |
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
|
114 |
filename = f"history_{user_id}_{timestamp}.md"
|
115 |
+
markdown = create_markdown_preview(history_df)
|
116 |
with open(filename, 'w', encoding='utf-8') as f:
|
117 |
f.write(markdown)
|
118 |
return filename
|
119 |
|
120 |
+
# Function to load saved histories
|
121 |
+
def load_saved_histories():
|
122 |
+
history_files = [f for f in os.listdir('.') if f.startswith('history_') and f.endswith('.md')]
|
123 |
+
return history_files
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
124 |
|
125 |
# ๐ง Game Mechanics
|
126 |
def generate_situation():
|
|
|
169 |
game_state['gear_strength'] = max(1, game_state['gear_strength'] - 0.1)
|
170 |
return game_state
|
171 |
|
172 |
+
# ๐ณ Journey Visualization
|
173 |
+
def create_knowledge_graph(history_df):
|
|
|
174 |
nodes = []
|
175 |
edges = []
|
176 |
node_ids = {}
|
177 |
+
for index, row in history_df.iterrows():
|
178 |
+
situation_node_id = f"situation_{row['situation_id']}"
|
179 |
+
action_node_id = f"action_{index}"
|
180 |
|
181 |
+
# Situation node
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
182 |
if situation_node_id not in node_ids:
|
183 |
situation_node = StreamlitFlowNode(
|
184 |
situation_node_id,
|
185 |
pos=(0, 0),
|
186 |
+
data={'content': f"{row['situation_emoji']} {row['situation_name']}"},
|
187 |
type='default',
|
188 |
+
shape='ellipse'
|
|
|
|
|
189 |
)
|
190 |
nodes.append(situation_node)
|
191 |
node_ids[situation_node_id] = situation_node_id
|
192 |
|
193 |
+
# Attempt node (action and outcome)
|
194 |
+
outcome_content = 'โ
Success' if row['outcome'] else 'โ Failure'
|
195 |
+
stars = 'โญ' * int(row['score'])
|
196 |
+
attempt_node = StreamlitFlowNode(
|
197 |
+
action_node_id,
|
198 |
+
pos=(0, 0),
|
199 |
+
data={'content': f"{row['action_emoji']} {row['action_name']} ({outcome_content})\n{row['conclusion']}\n{stars}"},
|
200 |
+
type='default',
|
201 |
+
shape='rectangle'
|
202 |
+
)
|
203 |
+
nodes.append(attempt_node)
|
204 |
+
|
205 |
+
# Edge from situation to attempt
|
206 |
+
edges.append(StreamlitFlowEdge(
|
207 |
+
id=f"edge_{situation_node_id}_{action_node_id}",
|
208 |
+
source=situation_node_id,
|
209 |
+
target=action_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'], sort=False)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
219 |
|
220 |
+
for situation_name, group in grouped:
|
221 |
+
markdown += f"### {group.iloc[0]['situation_emoji']} **{situation_name}**\n"
|
222 |
+
for _, row in group.iterrows():
|
223 |
+
outcome_str = 'โ
Success' if row['outcome'] else 'โ Failure'
|
224 |
+
stars = 'โญ' * int(row['score'])
|
225 |
+
markdown += f"- Attempt {row['attempt']}: {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):
|
|
|
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']],
|
|
|
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
|
|
|
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,
|
|
|
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']:
|
|
|
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'] = []
|
|
|
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 Knowledge Journey Graph
|
435 |
st.markdown("## ๐ณ Your Journey (Knowledge Graph)")
|
436 |
+
nodes, edges = create_knowledge_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.")
|
|
|
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()
|
475 |
+
|