awacke1 commited on
Commit
b80c026
β€’
1 Parent(s): bb5f8ef

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +226 -0
app.py ADDED
@@ -0,0 +1,226 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ import pandas as pd
3
+ import plotly.express as px
4
+ import random
5
+ import json
6
+ import csv
7
+ import base64
8
+ import uuid
9
+ from io import StringIO
10
+ from datetime import datetime
11
+ from streamlit_flow import streamlit_flow
12
+ from streamlit_flow.elements import StreamlitFlowNode, StreamlitFlowEdge
13
+ from streamlit_flow.layouts import TreeLayout
14
+
15
+ # Rich data structures for game content
16
+ SITUATIONS = [
17
+ {
18
+ "id": "village_peril",
19
+ "name": "The Village in Peril",
20
+ "description": "A once-peaceful village is shrouded in dark miasma. Villagers cower in fear as shadowy figures lurk in the mist.",
21
+ "emoji": "🏘️"
22
+ },
23
+ {
24
+ "id": "cursed_artifact",
25
+ "name": "The Cursed Artifact",
26
+ "description": "Deep in an ancient tomb, a glowing artifact pulses with malevolent energy, its whispers echoing in your mind.",
27
+ "emoji": "🏺"
28
+ },
29
+ {
30
+ "id": "sacred_pact",
31
+ "name": "The Sacred Pact",
32
+ "description": "At a moonlit shrine, spirits of the land gather, awaiting a mediator to forge a new covenant between realms.",
33
+ "emoji": "πŸŒ™"
34
+ },
35
+ {
36
+ "id": "shapeshifter_challenge",
37
+ "name": "The Shapeshifter's Challenge",
38
+ "description": "A rival kitsune issues a challenge, their forms flickering between human and fox. The air crackles with competitive energy.",
39
+ "emoji": "🦊"
40
+ },
41
+ {
42
+ "id": "fox_fire_trial",
43
+ "name": "The Fox Fire Trial",
44
+ "description": "Sacred blue flames dance before you, a test of your mastery over kitsune magic. The heat is both inviting and intimidating.",
45
+ "emoji": "πŸ”₯"
46
+ }
47
+ ]
48
+
49
+ ACTIONS = [
50
+ {
51
+ "id": "fox_fire",
52
+ "name": "Use Fox Fire",
53
+ "description": "Summon mystical flames to illuminate the darkness or ward off evil spirits.",
54
+ "emoji": "πŸ”₯"
55
+ },
56
+ {
57
+ "id": "shapeshift",
58
+ "name": "Shapeshift",
59
+ "description": "Transform your appearance to blend in or deceive others.",
60
+ "emoji": "🦊"
61
+ },
62
+ {
63
+ "id": "possess_object",
64
+ "name": "Possess an Object",
65
+ "description": "Infuse your spirit into an inanimate object to manipulate or gather information.",
66
+ "emoji": "πŸ‘»"
67
+ },
68
+ {
69
+ "id": "call_spirits",
70
+ "name": "Call Upon Ancient Spirits",
71
+ "description": "Invoke the wisdom and power of your ancestors to guide you.",
72
+ "emoji": "🌟"
73
+ },
74
+ {
75
+ "id": "use_artifact",
76
+ "name": "Use Mystical Artifact",
77
+ "description": "Activate a powerful magical item to unleash its effects.",
78
+ "emoji": "πŸ—‘οΈ"
79
+ }
80
+ ]
81
+
82
+ def generate_situation():
83
+ return random.choice(SITUATIONS)
84
+
85
+ def generate_actions():
86
+ return random.sample(ACTIONS, 3)
87
+
88
+ def evaluate_action(action, power_level, mystical_energy, history):
89
+ base_success_chance = (power_level + mystical_energy) / 2
90
+ if action['id'] in history:
91
+ success_chance = base_success_chance + (history[action['id']] * 2)
92
+ else:
93
+ success_chance = base_success_chance
94
+ outcome = random.randint(1, 100) <= success_chance
95
+ return outcome, success_chance
96
+
97
+ def create_graph_from_history(history_df):
98
+ nodes = []
99
+ edges = []
100
+ for index, row in history_df.iterrows():
101
+ node_id = f"{index}-{row['situation_id']}-{row['action_id']}"
102
+ content = f"{row['situation_emoji']} {row['situation_name']}\n{row['action_emoji']} {row['action_name']}\nOutcome: {'βœ… Success' if row['outcome'] else '❌ Failure'}\nπŸ•’ {row['timestamp']}"
103
+ new_node = StreamlitFlowNode(node_id, (0, 0), {'content': content}, 'output', 'bottom', 'top')
104
+ nodes.append(new_node)
105
+
106
+ if index > 0:
107
+ prev_node_id = f"{index-1}-{history_df.iloc[index-1]['situation_id']}-{history_df.iloc[index-1]['action_id']}"
108
+ new_edge = StreamlitFlowEdge(f"{prev_node_id}-{node_id}", prev_node_id, node_id, animated=True, dashed=True)
109
+ edges.append(new_edge)
110
+
111
+ return nodes, edges
112
+
113
+ def save_history_to_csv(history_df):
114
+ csv_buffer = StringIO()
115
+ history_df.to_csv(csv_buffer, index=False)
116
+ csv_string = csv_buffer.getvalue()
117
+ b64 = base64.b64encode(csv_string.encode()).decode()
118
+ return b64
119
+
120
+ def load_history_from_csv(csv_string):
121
+ csv_buffer = StringIO(csv_string)
122
+ history_df = pd.read_csv(csv_buffer)
123
+ return history_df
124
+
125
+ def app():
126
+ st.markdown("# 🦊 Kitsune - The Mystical Shape-Shifter Game 🦊")
127
+
128
+ if 'user_id' not in st.session_state:
129
+ st.session_state.user_id = str(uuid.uuid4())
130
+
131
+ if 'game_state' not in st.session_state:
132
+ st.session_state.game_state = {
133
+ 'score': 0,
134
+ 'history': {},
135
+ 'power_level': 50,
136
+ 'mystical_energy': 75,
137
+ 'history_df': pd.DataFrame(columns=['user_id', 'timestamp', 'situation_id', 'situation_name', 'situation_emoji', 'action_id', 'action_name', 'action_emoji', 'outcome', 'score'])
138
+ }
139
+
140
+ # Game Stats
141
+ st.sidebar.markdown("## πŸ“Š Game Stats")
142
+ st.sidebar.markdown(f"**Score:** {st.session_state.game_state['score']}")
143
+
144
+ # Character Stats
145
+ power_level = st.sidebar.slider('Power Level ⚑', 0, 100, st.session_state.game_state['power_level'])
146
+ mystical_energy = st.sidebar.slider('Mystical Energy ✨', 0, 100, st.session_state.game_state['mystical_energy'])
147
+
148
+ # Game Loop
149
+ situation = generate_situation()
150
+ actions = generate_actions()
151
+
152
+ st.markdown(f"## {situation['emoji']} Current Situation: {situation['name']}")
153
+ st.markdown(situation['description'])
154
+ st.markdown("### 🎭 Choose your action:")
155
+
156
+ cols = st.columns(3)
157
+ for i, action in enumerate(actions):
158
+ if cols[i].button(f"{action['emoji']} {action['name']}"):
159
+ outcome, success_chance = evaluate_action(action, power_level, mystical_energy, st.session_state.game_state['history'])
160
+ timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
161
+
162
+ st.markdown(f"You decided to: **{action['name']}**")
163
+ st.markdown(action['description'])
164
+ st.markdown(f"**Outcome:** {'βœ… Success!' if outcome else '❌ Failure.'}")
165
+ st.markdown(f"**Success Chance:** {success_chance:.2f}%")
166
+
167
+ if outcome:
168
+ st.session_state.game_state['score'] += 1
169
+
170
+ # Update history
171
+ if action['id'] in st.session_state.game_state['history']:
172
+ st.session_state.game_state['history'][action['id']] += 1 if outcome else -1
173
+ else:
174
+ st.session_state.game_state['history'][action['id']] = 1 if outcome else -1
175
+
176
+ # Add new record to history DataFrame
177
+ new_record = pd.DataFrame({
178
+ 'user_id': [st.session_state.user_id],
179
+ 'timestamp': [timestamp],
180
+ 'situation_id': [situation['id']],
181
+ 'situation_name': [situation['name']],
182
+ 'situation_emoji': [situation['emoji']],
183
+ 'action_id': [action['id']],
184
+ 'action_name': [action['name']],
185
+ 'action_emoji': [action['emoji']],
186
+ 'outcome': [outcome],
187
+ 'score': [st.session_state.game_state['score']]
188
+ })
189
+ st.session_state.game_state['history_df'] = pd.concat([st.session_state.game_state['history_df'], new_record], ignore_index=True)
190
+
191
+ # Save history to CSV and provide download link
192
+ csv_b64 = save_history_to_csv(st.session_state.game_state['history_df'])
193
+ href = f'<a href="data:file/csv;base64,{csv_b64}" download="kitsune_game_history.csv">Download Game History</a>'
194
+ st.markdown(href, unsafe_allow_html=True)
195
+
196
+ # Display Graph
197
+ if not st.session_state.game_state['history_df'].empty:
198
+ st.markdown("## 🌳 Your Journey")
199
+ nodes, edges = create_graph_from_history(st.session_state.game_state['history_df'])
200
+ streamlit_flow('kitsune_game_flow',
201
+ nodes,
202
+ edges,
203
+ layout=TreeLayout(direction='down'),
204
+ fit_view=True,
205
+ height=600)
206
+
207
+ # Character Stats Visualization
208
+ data = {"Stat": ["Power Level ⚑", "Mystical Energy ✨"],
209
+ "Value": [power_level, mystical_energy]}
210
+ df = pd.DataFrame(data)
211
+ fig = px.bar(df, x='Stat', y='Value', title="Kitsune Stats πŸ“Š")
212
+ st.plotly_chart(fig)
213
+
214
+ # Load Game State
215
+ st.markdown("## πŸ’Ύ Load Game")
216
+ uploaded_file = st.file_uploader("Load Game History", type="csv")
217
+ if uploaded_file is not None:
218
+ csv_string = uploaded_file.getvalue().decode()
219
+ loaded_history_df = load_history_from_csv(csv_string)
220
+ st.session_state.game_state['history_df'] = loaded_history_df
221
+ st.session_state.game_state['score'] = loaded_history_df['score'].iloc[-1]
222
+ st.session_state.user_id = loaded_history_df['user_id'].iloc[0]
223
+ st.success("Game history loaded successfully!")
224
+
225
+ if __name__ == "__main__":
226
+ app()