|
from typing import Type |
|
|
|
import streamlit as st |
|
from streamlit import session_state |
|
|
|
from game import Game |
|
from agent_interfaces import HumanAgentInterface |
|
from message import Message |
|
from prompts import fetch_prompt, format_prompt |
|
|
|
st.set_page_config(layout="wide", page_title="Chameleon", page_icon="img/logo.svg") |
|
|
|
|
|
def display_message(message: Message): |
|
if message.type == "verbose": |
|
messages_container.markdown(f":green[{message.content}]") |
|
elif message.type == "debug": |
|
messages_container.markdown(f":orange[DEBUG: {message.content}]") |
|
else: |
|
messages_container.markdown(f"{message.content}") |
|
|
|
|
|
if "messages" not in session_state: |
|
session_state.messages = [] |
|
session_state.awaiting_human_input = False |
|
session_state.game_state = "game_start" |
|
|
|
|
|
class StreamlitInterface(HumanAgentInterface): |
|
def add_message(self, message: Message): |
|
super().add_message(message) |
|
session_state.messages.append(message) |
|
display_message(message) |
|
|
|
def _generate(self) -> str: |
|
return session_state.user_input |
|
|
|
|
|
class StreamlitGame(Game): |
|
"""A Streamlit version of the Game class that uses a state machine to manage the game state.""" |
|
|
|
def run_game(self): |
|
"""Starts the game.""" |
|
if session_state.game_state == "game_start": |
|
self.game_message(fetch_prompt("game_rules")) |
|
session_state.game_state = "setup_round" |
|
|
|
if session_state.game_state == "setup_round": |
|
self.setup_round() |
|
session_state.game_state = "animal_description" |
|
if session_state.game_state in ["animal_description", "chameleon_guess", "herd_vote"]: |
|
self.run_round() |
|
if session_state.game_state == "resolve_round": |
|
self.resolve_round() |
|
session_state.game_state = "setup_round" |
|
|
|
def run_round(self): |
|
"""Starts the round.""" |
|
|
|
|
|
if session_state.game_state == "animal_description": |
|
for current_player in self.players: |
|
if current_player.id not in [animal_description['player_id'] for animal_description in self.round_animal_descriptions]: |
|
if current_player.interface.is_human: |
|
if not session_state.awaiting_human_input: |
|
self.game_message(fetch_prompt("player_describe_animal"), current_player) |
|
session_state.awaiting_human_input = True |
|
break |
|
else: |
|
self.player_turn_animal_description(current_player) |
|
session_state.awaiting_human_input = False |
|
else: |
|
self.game_message(fetch_prompt("player_describe_animal"), current_player) |
|
self.player_turn_animal_description(current_player) |
|
if len(self.round_animal_descriptions) == len(self.players): |
|
session_state.game_state = "chameleon_guess" |
|
session_state.awaiting_human_input = False |
|
|
|
|
|
if session_state.game_state == "chameleon_guess": |
|
self.game_message("All players have spoken. The Chameleon will now guess the secret animal...") |
|
player_responses = self.format_animal_descriptions(exclude=self.chameleon) |
|
self.game_message(format_prompt("chameleon_guess_animal", player_responses=player_responses), self.chameleon) |
|
if self.players[self.human_index].role == "chameleon": |
|
if not session_state.awaiting_human_input: |
|
session_state.awaiting_human_input = True |
|
else: |
|
self.player_turn_chameleon_guess(self.chameleon) |
|
session_state.awaiting_human_input = False |
|
else: |
|
self.player_turn_chameleon_guess(self.chameleon) |
|
session_state.awaiting_human_input = False |
|
|
|
session_state.game_state = "herd_vote" |
|
|
|
|
|
if session_state.game_state == "herd_vote": |
|
for current_player in self.players: |
|
if current_player.role == "herd" and current_player.id not in [vote['voter_id'] for vote in self.herd_vote_tally]: |
|
player_responses = self.format_animal_descriptions(exclude=current_player) |
|
if current_player.interface.is_human: |
|
if not session_state.awaiting_human_input: |
|
self.game_message(format_prompt("vote", player_responses=player_responses), current_player) |
|
session_state.awaiting_human_input = True |
|
break |
|
else: |
|
self.player_turn_herd_vote(current_player) |
|
session_state.awaiting_human_input = False |
|
else: |
|
self.game_message(format_prompt("vote", player_responses=player_responses), current_player) |
|
self.player_turn_herd_vote(current_player) |
|
|
|
if len(self.herd_vote_tally) == len(self.players) - 1: |
|
session_state.game_state = "resolve_round" |
|
|
|
|
|
|
|
|
|
margin_size = 1 |
|
center_size = 3 |
|
|
|
title_left, title_center, title_right = st.columns([margin_size, center_size, margin_size]) |
|
|
|
with title_center: |
|
st.markdown("# :rainbow[Chameleon]") |
|
|
|
left, center, right = st.columns([margin_size, center_size, margin_size]) |
|
|
|
with center: |
|
messages_container = st.container() |
|
|
|
messages_container.write("Welcome to Chameleon! A social deduction game powered by LLMs.") |
|
|
|
messages_container.write("Enter your name to begin...") |
|
|
|
user_input = st.chat_input("Your response:") |
|
|
|
if st.session_state.messages: |
|
for message in st.session_state.messages: |
|
display_message(message) |
|
|
|
if user_input: |
|
if "game" not in st.session_state: |
|
st.session_state.game = StreamlitGame(human_name=user_input, verbose=True, human_interface=StreamlitInterface) |
|
session_state.user_input = user_input |
|
st.session_state.game.run_game() |
|
|
|
|
|
|