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()