Skip to content

Commit

Permalink
gui phase 1
Browse files Browse the repository at this point in the history
  • Loading branch information
Luncenok committed Oct 21, 2024
1 parent 2bab0c0 commit 0d3891b
Show file tree
Hide file tree
Showing 4 changed files with 96 additions and 9 deletions.
14 changes: 13 additions & 1 deletion src/demo_gui.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import json
import streamlit as st
from game.game_engine import GameEngine
from game.players.ai import AIPlayer
from game.gui_handler import GUIHandler
from game.game_state import GameState
from types import SimpleNamespace as Namespace



Expand All @@ -18,13 +21,22 @@ def main():

model_name = "gpt-4o-mini" # Or any other suitable model name

player_names = ["Wateusz", "Waciej", "Warek"]
player_names = ["Wateusz", "Waciej", "Warek", "Wojtek", "Wafał", "Wymek"]
players = [AIPlayer(name=player_names[i], llm_model_name=model_name) for i in range(3)]
game_engine.load_players(players, impostor_count=1)
game_engine.init_game()

# read game_state.json from file
# with open("game_state.json", "r") as file:
# game_state = file.read()
# json_game_state = json.loads(game_state, object_hook=lambda d: Namespace(**d))
# gui_handler.update_gui(json_game_state)
# json_game_state.players[0].state.tasks[0] = "DONE"
# gui_handler.update_gui(json_game_state)

try:
game_engine.enter_main_game_loop()
gui_handler.update_gui(game_engine.state)
st.json(game_engine.to_dict(), expanded=False) # Display final game state
st.text("\n".join(game_engine.state.playthrough)) # Display final game log

Expand Down
14 changes: 11 additions & 3 deletions src/game/game_engine.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,6 @@ def get_player_actions(self) -> list[GameAction]:
print(f"Player {player} actions: {possible_actions_str}")
action_int = player.prompt_action(possible_actions_str)
choosen_actions.append(possible_actions[action_int])
self.gui_handler.update_gui(self.state) # Update GUI after player action
if self.state.DEBUG:
print(f"Player {player} choosen action: {choosen_actions[-1]}")
return choosen_actions
Expand Down Expand Up @@ -160,6 +159,10 @@ def update_game_state(self, chosen_actions: list[GameAction]) -> bool:
f"you saw {action.spectator} when you were in {action.player.state.location.value}"
)

for player in self.state.players:
# update player history
player.log_state_new_round()

# update players in room
for player in self.state.players:
players_in_room = [
Expand All @@ -179,8 +182,6 @@ def update_game_state(self, chosen_actions: list[GameAction]) -> bool:
else:
player.state.player_in_room = "You are alone in the room"

# update player history
player.log_state_new_round()
return someone_reported

def get_actions(self, player: Player) -> list[GameAction]:
Expand Down Expand Up @@ -344,6 +345,13 @@ def check_impostors_win(self) -> bool:
p for p in self.state.get_alive_players() if not p.is_impostor
]
impostors_alive = [p for p in self.state.get_alive_players() if p.is_impostor]
if len(impostors_alive) >= len(crewmates_alive):
self.state.log_action(
f"Impostors win! Impostors: {impostors_alive}, Crewmates: {crewmates_alive}"
)
for impostor in impostors_alive:
impostor.state.tasks[0].complete(location=GameLocation.LOC_UNKNOWN)
return True
return len(impostors_alive) >= len(crewmates_alive)

def check_crewmates_win(self) -> bool:
Expand Down
74 changes: 70 additions & 4 deletions src/game/gui_handler.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,80 @@
from typing import Any
from typing import Any, List, Dict, Optional
import streamlit as st
from game.game_state import GameState
from pydantic import BaseModel, Field
from game.players.base_player import Player, PlayerRole
from streamlit.delta_generator import DeltaGenerator

from game.models.history import PlayerState


class GUIHandler(BaseModel):
player_states_placeholder: Any = Field(default_factory=st.empty)
game_log_placeholder: Any = Field(default_factory=st.empty)
player_states_placeholders: List[DeltaGenerator] = Field(default_factory=list)
game_log_placeholder: Optional[DeltaGenerator] = None
game_log_json: Optional[DeltaGenerator] = None
cols: List[DeltaGenerator] = Field(default_factory=list)
model_config = {"arbitrary_types_allowed": True}

def update_gui(self, game_state: GameState):
self.player_states_placeholder.json(game_state.to_dict(), expanded=False)
num_players = len(game_state.players)

# Create columns and placeholders only on the first call
if not self.cols:
self.cols = [col.empty() for col in st.columns(num_players)]
for col in self.cols:
self.player_states_placeholders.append(col.empty())
# self.player_states_placeholders = [st.empty() for _ in range(num_players)]
if not self.game_log_placeholder:
self.game_log_placeholder = st.empty()
if not self.game_log_json:
self.game_log_json = st.empty()

# Update existing widgets
for i, (player, col) in enumerate(zip(game_state.players, self.cols)):
with col:
self._display_player_info(player, self.player_states_placeholders[i])

self.game_log_placeholder.text("\n".join(game_state.playthrough))
self.game_log_json.json(game_state.to_dict(), expanded=True)

def _display_player_info(self, player: Player, placeholder: DeltaGenerator):
with placeholder.container(): # Clear previous content
st.subheader(player.name)
self._display_status(player)
self._display_role(player)
self._display_tasks(player)
self._display_location(player)
self._display_action_taken(player)
self._display_action_result(player)
self._display_recent_actions(player)


def _display_status(self, player: Player):
status_icon = "✅" if player.state.life == PlayerState.ALIVE else "❌"
st.write(f"Status: {status_icon} {player.state.life.value}")

def _display_role(self, player: PlayerRole):
role_icon = "🕵️‍♂️" if player.role == PlayerRole.IMPOSTOR else "👨‍🚀"
st.write(f"Role: {role_icon} {player.role.value}")

def _display_tasks(self, player: Player):
completed_tasks = sum(1 for task in player.state.tasks if "DONE" in str(task))
total_tasks = len(player.state.tasks)
st.progress(completed_tasks / total_tasks if total_tasks > 0 else 0) #Handle division by zero
st.write(f"Tasks: {completed_tasks}/{total_tasks}")

def _display_location(self, player: Player):
st.write(f"Location: {player.state.location.value} {player.state.player_in_room}")

def _display_action_taken(self, player: Player):
action = player.history.rounds[-1].response
st.write(f"Action Taken: {player.history.rounds[-1].actions[action]}")

def _display_action_result(self, player: Player):
st.write(f"Action Result: {player.history.rounds[-1].action_result}")

def _display_recent_actions(self, player: Player):
st.write("Seen Actions:")
for action in player.history.rounds[-1].seen_actions:
st.write(f"- {action}")

3 changes: 2 additions & 1 deletion src/game/players/base_player.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,9 @@ def get_task_to_complete(self) -> List[Task]:
def log_state_new_round(self) -> None:
# Create a deep copy of the state before adding it to the history
state_copy = copy.deepcopy(self.state)
print(f"Logging state: {state_copy}")
self.history.add_round(state_copy)
self.state.tasks = [task for task in self.state.tasks if not task.completed]
# self.state.tasks = [task for task in self.state.tasks if not task.completed]
self.state.llm_responses = []
self.state.prompt = ""
self.state.actions = []
Expand Down

0 comments on commit 0d3891b

Please sign in to comment.