Create app.py
Browse files
app.py
ADDED
@@ -0,0 +1,94 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import streamlit as st
|
2 |
+
import pandas as pd
|
3 |
+
import plotly.express as px
|
4 |
+
import random
|
5 |
+
from streamlit_flow import streamlit_flow
|
6 |
+
from streamlit_flow.elements import StreamlitFlowNode, StreamlitFlowEdge
|
7 |
+
from streamlit_flow.layouts import RadialLayout
|
8 |
+
|
9 |
+
def generate_situation():
|
10 |
+
situations = [
|
11 |
+
"The Village in Peril",
|
12 |
+
"The Cursed Artifact",
|
13 |
+
"The Sacred Pact",
|
14 |
+
"The Shapeshifter's Challenge",
|
15 |
+
"The Fox Fire Trial"
|
16 |
+
]
|
17 |
+
return random.choice(situations)
|
18 |
+
|
19 |
+
def generate_action():
|
20 |
+
actions = [
|
21 |
+
"Use Fox Fire",
|
22 |
+
"Shapeshift",
|
23 |
+
"Possess an Object",
|
24 |
+
"Call Upon Ancient Spirits",
|
25 |
+
"Use Mystical Artifact"
|
26 |
+
]
|
27 |
+
return random.choice(actions)
|
28 |
+
|
29 |
+
def evaluate_action(situation, action, power_level, mystical_energy):
|
30 |
+
success_chance = (power_level + mystical_energy) / 2
|
31 |
+
outcome = random.randint(1, 100) <= success_chance
|
32 |
+
return outcome, success_chance
|
33 |
+
|
34 |
+
def update_graph(nodes, edges, situation, action, outcome):
|
35 |
+
new_node_id = f"{situation}-{action}"
|
36 |
+
new_node = StreamlitFlowNode(new_node_id, (0, 0), {'content': f"{situation}\n{action}\nOutcome: {'Success' if outcome else 'Failure'}"}, 'output', 'bottom', 'top')
|
37 |
+
nodes.append(new_node)
|
38 |
+
|
39 |
+
if len(nodes) > 1:
|
40 |
+
new_edge = StreamlitFlowEdge(f"{nodes[-2].id}-{new_node.id}", nodes[-2].id, new_node.id, animated=True)
|
41 |
+
edges.append(new_edge)
|
42 |
+
|
43 |
+
return nodes, edges
|
44 |
+
|
45 |
+
def app():
|
46 |
+
st.markdown("# Kitsune - The Mystical Shape-Shifter Game π¦")
|
47 |
+
|
48 |
+
if 'nodes' not in st.session_state:
|
49 |
+
st.session_state.nodes = []
|
50 |
+
st.session_state.edges = []
|
51 |
+
st.session_state.score = 0
|
52 |
+
|
53 |
+
# Game Stats
|
54 |
+
st.sidebar.markdown("## Game Stats")
|
55 |
+
st.sidebar.markdown(f"Score: {st.session_state.score}")
|
56 |
+
|
57 |
+
# Character Stats
|
58 |
+
power_level = st.sidebar.slider('Power Level β‘', 0, 100, 50)
|
59 |
+
mystical_energy = st.sidebar.slider('Mystical Energy β¨', 0, 100, 75)
|
60 |
+
|
61 |
+
# Game Loop
|
62 |
+
if st.button('Next Turn'):
|
63 |
+
situation = generate_situation()
|
64 |
+
action = generate_action()
|
65 |
+
outcome, success_chance = evaluate_action(situation, action, power_level, mystical_energy)
|
66 |
+
|
67 |
+
st.markdown(f"## Current Situation: {situation}")
|
68 |
+
st.markdown(f"You decided to: {action}")
|
69 |
+
st.markdown(f"Outcome: {'Success!' if outcome else 'Failure.'}")
|
70 |
+
st.markdown(f"Success Chance: {success_chance:.2f}%")
|
71 |
+
|
72 |
+
if outcome:
|
73 |
+
st.session_state.score += 1
|
74 |
+
|
75 |
+
st.session_state.nodes, st.session_state.edges = update_graph(st.session_state.nodes, st.session_state.edges, situation, action, outcome)
|
76 |
+
|
77 |
+
# Display Graph
|
78 |
+
if st.session_state.nodes:
|
79 |
+
streamlit_flow('kitsune_game_flow',
|
80 |
+
st.session_state.nodes,
|
81 |
+
st.session_state.edges,
|
82 |
+
layout=RadialLayout(),
|
83 |
+
fit_view=True,
|
84 |
+
height=600)
|
85 |
+
|
86 |
+
# Character Stats Visualization
|
87 |
+
data = {"Stat": ["Power Level", "Mystical Energy"],
|
88 |
+
"Value": [power_level, mystical_energy]}
|
89 |
+
df = pd.DataFrame(data)
|
90 |
+
fig = px.bar(df, x='Stat', y='Value', title="Kitsune Stats π")
|
91 |
+
st.plotly_chart(fig)
|
92 |
+
|
93 |
+
if __name__ == "__main__":
|
94 |
+
app()
|