import streamlit as st
def _init_state():
if "sk_players" not in st.session_state:
st.session_state.sk_players = []
if "sk_game_started" not in st.session_state:
st.session_state.sk_game_started = False
if "sk_scores" not in st.session_state:
st.session_state.sk_scores = {}
def _setup_phase():
st.subheader("Player Setup")
def _sk_add_player():
name = st.session_state.sk_new_player.strip()
if name and name not in st.session_state.sk_players:
st.session_state.sk_players.append(name)
st.session_state.sk_new_player = ""
col1, col2 = st.columns([3, 1])
with col1:
st.text_input("Player name", key="sk_new_player")
with col2:
st.write("")
st.write("")
st.button("Add Player", key="sk_add_btn", on_click=_sk_add_player)
if st.session_state.sk_players:
st.markdown("**Players:**")
for i, p in enumerate(st.session_state.sk_players):
col_name, col_del = st.columns([4, 1])
col_name.write(f"{i + 1}. {p}")
if col_del.button("Remove", key=f"sk_rm_{i}"):
st.session_state.sk_players.pop(i)
st.rerun()
if len(st.session_state.sk_players) >= 2:
if st.button("Start Game", type="primary"):
st.session_state.sk_game_started = True
st.session_state.sk_scores = {}
st.rerun()
else:
st.info("Add at least 2 players to start.")
def _game_phase():
players = st.session_state.sk_players
scores = st.session_state.sk_scores
completed_rounds = sorted(scores.keys())
next_round = (completed_rounds[-1] + 1) if completed_rounds else 1
if st.button("Reset Game"):
st.session_state.sk_game_started = False
st.session_state.sk_players = []
st.session_state.sk_scores = {}
st.rerun()
if completed_rounds:
st.subheader("Scoreboard")
_render_scoreboard(players, scores, completed_rounds)
if next_round <= 10:
st.subheader(f"Round {next_round}")
st.caption(f"Each player is dealt {next_round} card{'s' if next_round > 1 else ''}.")
round_scores = {}
cols = st.columns(len(players))
for i, player in enumerate(players):
with cols[i]:
round_scores[player] = st.number_input(
player,
value=0,
step=10,
key=f"sk_input_r{next_round}_{player}",
)
if st.button("Save Round", type="primary", key=f"sk_save_r{next_round}"):
st.session_state.sk_scores[next_round] = round_scores
st.rerun()
else:
st.success("Game complete! All 10 rounds played.")
_render_final_standings(players, scores, completed_rounds)
def _render_scoreboard(players, scores, completed_rounds):
header_cols = ["Round"] + players
rows_html = []
cumsum = {p: 0 for p in players}
prev_cumsum = {p: 0 for p in players}
for r in completed_rounds:
row = [f"**{r}**"]
for p in players:
pts = scores[r].get(p, 0)
prev_cumsum[p] = cumsum[p]
cumsum[p] += pts
change = cumsum[p] - prev_cumsum[p]
if change > 0:
indicator = f' ▲ +{change}'
elif change < 0:
indicator = f' ▼ {change}'
else:
indicator = ""
row.append(f"**{cumsum[p]}**{indicator}")
rows_html.append(row)
md = "| " + " | ".join(header_cols) + " |\n"
md += "| " + " | ".join(["---"] * len(header_cols)) + " |\n"
for row in rows_html:
md += "| " + " | ".join(str(c) for c in row) + " |\n"
st.markdown(md, unsafe_allow_html=True)
def _render_final_standings(players, scores, completed_rounds):
st.subheader("Final Standings")
totals = {p: sum(scores[r].get(p, 0) for r in completed_rounds) for p in players}
ranked = sorted(totals.items(), key=lambda x: x[1], reverse=True)
for i, (player, total) in enumerate(ranked):
medal = ["1st", "2nd", "3rd"][i] if i < 3 else f"{i+1}th"
st.write(f"**{medal}** - {player}: **{total}** points")
# Page entry point
st.title("Skull King")
_init_state()
if not st.session_state.sk_game_started:
_setup_phase()
else:
_game_phase()