Kitsune / kitsune3.app.py
awacke1's picture
Rename app.py to kitsune3.app.py
bb5f8ef verified
import streamlit as st
import pandas as pd
import plotly.express as px
import random
import json
from datetime import datetime
from streamlit_flow import streamlit_flow
from streamlit_flow.elements import StreamlitFlowNode, StreamlitFlowEdge
from streamlit_flow.layouts import TreeLayout
# Rich data structures for game content
SITUATIONS = [
{
"id": "village_peril",
"name": "The Village in Peril",
"description": "A once-peaceful village is shrouded in dark miasma. Villagers cower in fear as shadowy figures lurk in the mist.",
"emoji": "🏘️"
},
{
"id": "cursed_artifact",
"name": "The Cursed Artifact",
"description": "Deep in an ancient tomb, a glowing artifact pulses with malevolent energy, its whispers echoing in your mind.",
"emoji": "🏺"
},
{
"id": "sacred_pact",
"name": "The Sacred Pact",
"description": "At a moonlit shrine, spirits of the land gather, awaiting a mediator to forge a new covenant between realms.",
"emoji": "πŸŒ™"
},
{
"id": "shapeshifter_challenge",
"name": "The Shapeshifter's Challenge",
"description": "A rival kitsune issues a challenge, their forms flickering between human and fox. The air crackles with competitive energy.",
"emoji": "🦊"
},
{
"id": "fox_fire_trial",
"name": "The Fox Fire Trial",
"description": "Sacred blue flames dance before you, a test of your mastery over kitsune magic. The heat is both inviting and intimidating.",
"emoji": "πŸ”₯"
}
]
ACTIONS = [
{
"id": "fox_fire",
"name": "Use Fox Fire",
"description": "Summon mystical flames to illuminate the darkness or ward off evil spirits.",
"emoji": "πŸ”₯"
},
{
"id": "shapeshift",
"name": "Shapeshift",
"description": "Transform your appearance to blend in or deceive others.",
"emoji": "🦊"
},
{
"id": "possess_object",
"name": "Possess an Object",
"description": "Infuse your spirit into an inanimate object to manipulate or gather information.",
"emoji": "πŸ‘»"
},
{
"id": "call_spirits",
"name": "Call Upon Ancient Spirits",
"description": "Invoke the wisdom and power of your ancestors to guide you.",
"emoji": "🌟"
},
{
"id": "use_artifact",
"name": "Use Mystical Artifact",
"description": "Activate a powerful magical item to unleash its effects.",
"emoji": "πŸ—‘οΈ"
}
]
def generate_situation():
return random.choice(SITUATIONS)
def generate_actions():
return random.sample(ACTIONS, 3)
def evaluate_action(action, power_level, mystical_energy, history):
base_success_chance = (power_level + mystical_energy) / 2
if action['id'] in history:
success_chance = base_success_chance + (history[action['id']] * 2)
else:
success_chance = base_success_chance
outcome = random.randint(1, 100) <= success_chance
return outcome, success_chance
def update_graph(nodes, edges, situation, action, outcome, timestamp):
new_node_id = f"{len(nodes)}-{situation['id']}-{action['id']}"
content = f"{situation['emoji']} {situation['name']}\n{action['emoji']} {action['name']}\nOutcome: {'βœ… Success' if outcome else '❌ Failure'}\nπŸ•’ {timestamp}"
new_node = StreamlitFlowNode(new_node_id, (0, 0), {'content': content}, 'output', 'bottom', 'top')
nodes.append(new_node)
if len(nodes) > 1:
new_edge = StreamlitFlowEdge(f"{nodes[-2].id}-{new_node.id}", nodes[-2].id, new_node.id, animated=True, dashed=True)
edges.append(new_edge)
return nodes, edges
def save_game_state(state):
return json.dumps(state, default=str) # Use default=str to handle datetime objects
def load_game_state(state_json):
return json.loads(state_json)
def app():
st.markdown("# 🦊 Kitsune - The Mystical Shape-Shifter Game 🦊")
if 'game_state' not in st.session_state:
st.session_state.game_state = {
'nodes': [],
'edges': [],
'score': 0,
'history': {},
'power_level': 50,
'mystical_energy': 75
}
# Game Stats
st.sidebar.markdown("## πŸ“Š Game Stats")
st.sidebar.markdown(f"**Score:** {st.session_state.game_state['score']}")
# Character Stats
power_level = st.sidebar.slider('Power Level ⚑', 0, 100, st.session_state.game_state['power_level'])
mystical_energy = st.sidebar.slider('Mystical Energy ✨', 0, 100, st.session_state.game_state['mystical_energy'])
# Game Loop
situation = generate_situation()
actions = generate_actions()
st.markdown(f"## {situation['emoji']} Current Situation: {situation['name']}")
st.markdown(situation['description'])
st.markdown("### 🎭 Choose your action:")
cols = st.columns(3)
for i, action in enumerate(actions):
if cols[i].button(f"{action['emoji']} {action['name']}"):
outcome, success_chance = evaluate_action(action, power_level, mystical_energy, st.session_state.game_state['history'])
timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
st.markdown(f"You decided to: **{action['name']}**")
st.markdown(action['description'])
st.markdown(f"**Outcome:** {'βœ… Success!' if outcome else '❌ Failure.'}")
st.markdown(f"**Success Chance:** {success_chance:.2f}%")
if outcome:
st.session_state.game_state['score'] += 1
# Update history
if action['id'] in st.session_state.game_state['history']:
st.session_state.game_state['history'][action['id']] += 1 if outcome else -1
else:
st.session_state.game_state['history'][action['id']] = 1 if outcome else -1
st.session_state.game_state['nodes'], st.session_state.game_state['edges'] = update_graph(
st.session_state.game_state['nodes'],
st.session_state.game_state['edges'],
situation,
action,
outcome,
timestamp
)
# Display Graph
if st.session_state.game_state['nodes']:
st.markdown("## 🌳 Your Journey")
streamlit_flow('kitsune_game_flow',
st.session_state.game_state['nodes'],
st.session_state.game_state['edges'],
layout=TreeLayout(direction='down'),
fit_view=True,
height=600)
# Character Stats Visualization
data = {"Stat": ["Power Level ⚑", "Mystical Energy ✨"],
"Value": [power_level, mystical_energy]}
df = pd.DataFrame(data)
fig = px.bar(df, x='Stat', y='Value', title="Kitsune Stats πŸ“Š")
st.plotly_chart(fig)
# Save and Load Game State
st.markdown("## πŸ’Ύ Save/Load Game")
if st.button("Save Game"):
game_state_json = save_game_state(st.session_state.game_state)
st.download_button(
label="Download Game State",
data=game_state_json,
file_name="kitsune_game_state.json",
mime="application/json"
)
uploaded_file = st.file_uploader("Load Game State", type="json")
if uploaded_file is not None:
game_state_json = uploaded_file.getvalue().decode("utf-8")
st.session_state.game_state = load_game_state(game_state_json)
st.success("Game state loaded successfully!")
if __name__ == "__main__":
app()