spin / app.py
Ninjasharp's picture
Upload app.py
ce51199 verified
import streamlit as st
import pandas as pd
from datetime import datetime
def initialize_session_state():
if 'spins_left' not in st.session_state:
st.session_state.spins_left = 3
if 'current_tickets' not in st.session_state:
st.session_state.current_tickets = 0
if 'high_scores' not in st.session_state:
st.session_state.high_scores = pd.DataFrame(
columns=['Player', 'Score', 'Date']
)
# Add a dummy score
dummy_score = pd.DataFrame({
'Player': ['Bill'],
'Score': [100],
'Date': [datetime.now().strftime("%Y-%m-%d %H:%M")]
})
st.session_state.high_scores = pd.concat([st.session_state.high_scores, dummy_score], ignore_index=True)
if 'game_active' not in st.session_state:
st.session_state.game_active = True
if 'spin_result' not in st.session_state:
st.session_state.spin_result = None
def submit_score():
player_name = st.session_state.player_name
if player_name.strip():
new_score = pd.DataFrame({
'Player': [player_name],
'Score': [st.session_state.current_tickets],
'Date': [datetime.now().strftime("%Y-%m-%d %H:%M")]
})
st.session_state.high_scores = pd.concat([st.session_state.high_scores, new_score], ignore_index=True)
st.session_state.high_scores = st.session_state.high_scores.sort_values(by='Score', ascending=False).head(10)
# Reset game
st.session_state.spins_left = 3
st.session_state.current_tickets = 0
st.session_state.game_active = True
st.session_state.player_name = "" # Clear the name after submission
st.rerun()
def create_spin_wheel_app():
# Initialize session state
initialize_session_state()
# Set page config
st.set_page_config(
page_title="Spin the Wheel Game!",
page_icon="🎯",
layout="wide"
)
# Create two columns for layout
col1, col2 = st.columns([2, 1])
with col1:
st.title("🎯 Spin the Wheel Game!")
st.write(f"Spins left: {st.session_state.spins_left} | Current Tickets: {st.session_state.current_tickets}")
# HTML and JavaScript code for the spinning wheel
html_code = """
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<script src="https://d3js.org/d3.v3.min.js" charset="utf-8"></script>
<style>
text {
font-family: Helvetica, Arial, sans-serif;
font-size: 19px;
pointer-events: none;
}
#chart {
position: relative;
width: 500px;
height: 500px;
margin: 0 auto;
}
#question {
text-align: center;
margin-top: 20px;
}
#question h1 {
font-size: 32px;
font-weight: bold;
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
margin: 0;
padding: 10px;
}
</style>
</head>
<body>
<div id="chart"></div>
<div id="question"><h1></h1></div>
<script>
var padding = {top:20, right:40, bottom:0, left:0},
w = 360 - padding.left - padding.right,
h = 360 - padding.top - padding.bottom,
r = Math.min(w, h) / 2,
rotation = 0,
oldrotation = 0,
picked = 100000,
oldpick = [],
color = d3.scale.category20();
var data = [
{"label": "10🎟️", "value": 10, "question": "10 Tickets"},
{"label": "20🎟️", "value": 20, "question": "20 Tickets"},
{"label": "30🎟️", "value": 30, "question": "30 Tickets"},
{"label": "40🎟️", "value": 40, "question": "40 Tickets"},
{"label": "50🎟️", "value": 50, "question": "50 Tickets"},
{"label": "60🎟️", "value": 60, "question": "60 Tickets"},
{"label": "70🎟️", "value": 70, "question": "70 Tickets"},
{"label": "80🎟️", "value": 80, "question": "80 Tickets"},
{"label": "90🎟️", "value": 90, "question": "90 Tickets"},
{"label": "100🎟️", "value": 100, "question": "100 Tickets"}
];
var svg = d3.select('#chart')
.append("svg")
.data([data])
.attr("width", w + padding.left + padding.right)
.attr("height", h + padding.top + padding.bottom);
var container = svg.append("g")
.attr("class", "chartholder")
.attr("transform", "translate(" + (w/2 + padding.left) + "," + (h/2 + padding.top) + ")");
var vis = container.append("g");
var pie = d3.layout.pie().sort(null).value(function(d){ return 1; });
var arc = d3.svg.arc().outerRadius(r);
var arcs = vis.selectAll("g.slice")
.data(pie)
.enter()
.append("g")
.attr("class", "slice");
arcs.append("path")
.attr("fill", function(d, i){ return color(i); })
.attr("d", function(d){ return arc(d); });
arcs.append("text").attr("transform", function(d){
d.innerRadius = 0;
d.outerRadius = r;
d.angle = (d.startAngle + d.endAngle) / 2;
return "rotate(" + (d.angle * 180 / Math.PI - 90) + ")translate(" + (d.outerRadius - 10) + ")";
})
.attr("text-anchor", "end")
.text(function(d, i){ return data[i].label; });
container.on("click", spin);
function spin(d){
if (window.parent.document.querySelector('[data-testid="stMarkdownContainer"]').textContent.includes("Spins left: 0")) {
return;
}
container.on("click", null);
var ps = 360/data.length,
pieslice = Math.round(1440/data.length),
rng = Math.floor((Math.random() * 1440) + 360);
rotation = (Math.round(rng / ps) * ps);
picked = Math.round(data.length - (rotation % 360)/ps);
picked = picked >= data.length ? (picked % data.length) : picked;
rotation += 90 - Math.round(ps/2);
vis.transition()
.duration(3000)
.attrTween("transform", rotTween)
.each("end", function(){
d3.select("#question h1")
.text(data[picked].question);
oldrotation = rotation;
container.on("click", spin);
// Send message to Streamlit
window.parent.postMessage({
type: "spin_result",
value: data[picked].value
}, "*");
});
}
svg.append("g")
.attr("transform", "translate(" + (w + padding.left + padding.right) + "," + ((h/2)+padding.top) + ")")
.append("path")
.attr("d", "M-" + (r*.15) + ",0L0," + (r*.05) + "L0,-" + (r*.05) + "Z")
.style({"fill":"black"});
container.append("circle")
.attr("cx", 0)
.attr("cy", 0)
.attr("r", 60)
.style({"fill":"white","cursor":"pointer"});
container.append("text")
.attr("x", 0)
.attr("y", 15)
.attr("text-anchor", "middle")
.text("SPIN")
.style({"font-weight":"bold", "font-size":"30px"});
function rotTween(to) {
var i = d3.interpolate(oldrotation % 360, rotation);
return function(t) { return "rotate(" + i(t) + ")"; };
}
// Listen for messages from Streamlit
window.addEventListener("message", function(event) {
if (event.data.type === "spin_result") {
// Handle spin result from JavaScript and send to Streamlit
window.streamlitAPI.setComponentValue(event.data.value);
}
});
</script>
</body>
</html>
"""
# Handle spin result
components_kwargs = dict(height=600)
if st.session_state.game_active:
components_kwargs["html"] = html_code
else:
st.write("Game Over! Submit your score to play again.")
st.components.v1.html(**components_kwargs)
with col2:
st.title("🏆 High Scores")
# Display high scores table
if not st.session_state.high_scores.empty:
st.dataframe(
st.session_state.high_scores,
hide_index=True,
use_container_width=True
)
else:
st.write("No high scores yet!")
# Submit score section
if st.session_state.spins_left == 0 and st.session_state.game_active:
st.markdown("### Submit Your Score")
st.text_input("Enter your name:", key="player_name")
st.button("Submit Score", on_click=submit_score, disabled=not st.session_state.get('player_name', '').strip())
# Add instructions
st.sidebar.image("p1.png")
with st.sidebar.expander("How to Play"):
st.write("""
1. You have 3 spins per game
2. Click the 'SPIN' button in the center of the wheel
3. Collect as many tickets as possible
4. After 3 spins, enter your name and submit your score
5. Try to get on the leaderboard!
""")
st.sidebar.info("build by darryl")
# Handle spin result from JavaScript
spin_result = st.session_state.get("spin_result")
if st.session_state.spins_left > 0 and st.session_state.game_active and spin_result is not None:
st.session_state.current_tickets += int(spin_result)
st.session_state.spins_left -= 1
st.session_state.spin_result = None # Clear the spin result
if st.session_state.spins_left == 0:
st.session_state.game_active = False
st.rerun()
if __name__ == "__main__":
create_spin_wheel_app()