# coding: utf-8 # Author: Du Mingzhe (mingzhe@nus.edu.sg) # Date: 2025-09-11 import os import streamlit as st from pathlib import Path from typing import Tuple, List, Any from dixit import Player, OpenAIPlayer, Game, Card class OnlinePlayer(Player): def __init__(self, player_id: str): super().__init__(player_id) def storytell(self, card: Card) -> str: st.write("You are the Storyteller. Please tell a story about the card...") st.image(str(card.image_path.resolve()), width=100) return st.text_input("Story", "") def guess(self, story: str, cards: List[Card]) -> Card: if not st.session_state.guesser_status["player_human"]: st.write("You are the Guesser. Please guess a card...") st.success(f"Story: {story}") image_col = st.columns(6) for index, (card, image_col) in enumerate(zip(cards, image_col)): with image_col: st.image(str(card.image_path.resolve()), caption=f"Card {index}") card_index = st.selectbox("GuessCard", [index for index in range(len(cards))], on_change=None) if st.button("Guess"): return cards[card_index] return None def vote(self, story: str, cards: List[Card]) -> Card: if not st.session_state.vote_status["player_human"]: st.write("You are the Guesser. Please vote a card...") st.success(f"Story: {story}") card_index = st.selectbox("VoteCard", [index for index in range(len(cards))], on_change=None) if st.button("Vote"): cards[card_index].voted_by.append(self.player_id) return cards[card_index] return None def storytell_inference(self, card: Card) -> Tuple[str, str, float]: return (None, None, 0.0) def guess_inference(self, story: str, cards: List[Card]) -> Tuple[Card, str, float]: return (None, None, 0.0) def vote_inference(self, story: str, cards: List[Card]) -> Tuple[Card, str, float]: return (None, None, 0.0) st.title("Dixit :blue[Bench]") if "stage" not in st.session_state: token = st.text_input("OpenAI Token", type="password") if token: os.environ["OPENAI_API_KEY"] = token st.session_state.stage = "initialization" else: st.error("Please enter your OpenAI Token") st.stop() # Initialization if st.session_state.stage == "initialization": # Initialize Players st.session_state.player_list = [ OpenAIPlayer(player_id="player_1", model_name="gpt-4o-mini"), OpenAIPlayer(player_id="player_2", model_name="gpt-5"), OpenAIPlayer(player_id="player_3", model_name="gpt-5-mini"), OpenAIPlayer(player_id="player_4", model_name="gpt-5-nano"), OpenAIPlayer(player_id="player_5", model_name="gpt-4.1"), OnlinePlayer(player_id="player_human"), ] # Initialize Game st.session_state.game = Game(st.session_state.player_list, Path('asset/cards')) # Role Assignment st.session_state.game.role_assignment() st.session_state.human_player_role = "storyteller" if st.session_state.game.storyteller.player_id == "player_human" else "guesser" st.session_state.guesser_status = {guesser.player_id: False for guesser in st.session_state.game.guesser_list} st.session_state.vote_status = {guesser.player_id: False for guesser in st.session_state.game.guesser_list} # Dealing st.session_state.storyteller_card, st.session_state.guesser_card_dict = st.session_state.game.dealing() # Update Stage st.session_state.stage = "storytelling" st.rerun() # Context st.write(f"You are a *{st.session_state.human_player_role}* in this round.") # Storytelling if st.session_state.stage == "storytelling": st.write("## Storytelling") with st.spinner("Storyteller is thinking... (it may take 1 minute)", show_time=True): st.session_state.story = st.session_state.game.storyteller.storytell(st.session_state.storyteller_card) if st.session_state.story != "": st.success(f"Story: {st.session_state.story}") st.session_state.game.storyteller.selected_card_id = st.session_state.storyteller_card.card_id st.session_state.stage = "guessing" st.rerun() # Guessing if st.session_state.stage == "guessing": st.write("## Guessing") for guesser in st.session_state.game.guesser_list: if not st.session_state.guesser_status[guesser.player_id]: with st.spinner(f"Guesser {guesser.player_id} is guessing...", show_time=True): guessed_card = guesser.guess(st.session_state.story, st.session_state.guesser_card_dict[guesser.player_id]) if guessed_card: st.session_state.guesser_status[guesser.player_id] = True guessed_card.guessed_by = guesser.player_id guesser.guessed_card_id = guessed_card.card_id st.session_state.game.table_cards[guessed_card.card_id] = guessed_card st.rerun() if all(st.session_state.guesser_status.values()): st.session_state.game.table_cards[st.session_state.storyteller_card.card_id] = st.session_state.storyteller_card st.session_state.stage = "voting" st.rerun() # Voting if st.session_state.stage == "voting": st.write("## Voting") image_col = st.columns(6) for index, (card, image_col) in enumerate(zip(st.session_state.game.table_cards.values(), image_col)): with image_col: st.image(str(card.image_path.resolve()), caption=f"Card {index}") for guesser in st.session_state.game.guesser_list: if not st.session_state.vote_status[guesser.player_id]: with st.spinner(f"Guesser {guesser.player_id} is voting...", show_time=True): voted_card = guesser.vote(st.session_state.story, [st.session_state.game.table_cards[card_id] for card_id in st.session_state.game.table_cards]) if voted_card: st.session_state.vote_status[guesser.player_id] = True guesser.voted_card_id = voted_card.card_id st.session_state.game.table_cards[voted_card.card_id] = voted_card st.rerun() if all(st.session_state.vote_status.values()): st.session_state.stage = "scoring" st.rerun() # Scoring if st.session_state.stage == "scoring": st.write("## Scoring") st.session_state.game.calculate_score() st.write("Storytelling") st.image(str(st.session_state.storyteller_card.image_path.resolve()), caption=f"Story: {st.session_state.story}", width=200) st.write("Guessing") for guesser in st.session_state.game.guesser_list: cards = st.session_state.guesser_card_dict[guesser.player_id] image_col = st.columns(6) for index, (card, image_col) in enumerate(zip(cards, image_col)): with image_col: st.image(str(card.image_path.resolve()), caption=f"Card {index}") st.write("Voting") image_col = st.columns(6) for index, (card, image_col) in enumerate(zip(st.session_state.game.table_cards.values(), image_col)): with image_col: st.image(str(card.image_path.resolve()), caption=f"Card {index}") # Game Details game_details = dict() game_details["game_id"] = st.session_state.game.game_id game_details["storyteller"] = st.session_state.game.storyteller.player_id game_details["guessers"] = [guesser.player_id for guesser in st.session_state.game.guesser_list] game_details["guess_details"] = dict() game_details["vote_details"] = dict() game_details["score"] = st.session_state.game.score_dict # Guess Details for card in st.session_state.game.table_cards.values(): game_details["guess_details"][card.card_id] = card.guessed_by # Voted Details for card in st.session_state.game.table_cards.values(): game_details["vote_details"][card.card_id] = card.voted_by st.write(game_details) st.success("Game Finished!")