Spaces:
Sleeping
Sleeping
| """The turn loop. | |
| GameEngine ties the pieces together: | |
| player action ββΆ build prompt from GameState ββΆ model.chat() ββΆ parser | |
| ββ narrative + updated state ββββββββββββββββββββββ | |
| It also enforces a couple of rules the model should not be trusted with: | |
| * if the model forgets to make a defeated enemy stop attacking, combat still ends | |
| when enemy HP hits 0 (handled in the parser); | |
| * a guaranteed enemy counter-attack option exists even if the model is lazy | |
| (the engine never *adds* damage on its own β it only ever clamps). | |
| """ | |
| from __future__ import annotations | |
| from .game_state import GameState | |
| from .llm import Backend | |
| from . import prompts, parser | |
| class GameEngine: | |
| def __init__(self, backend: Backend, state: GameState | None = None): | |
| self.backend = backend | |
| self.state = state or GameState() | |
| self.history: list[parser.TurnResult] = [] | |
| # ------------------------------------------------------------------ public | |
| def start(self) -> parser.TurnResult: | |
| """Generate the opening scene.""" | |
| user = prompts.build_opening_prompt(self.state.context_snapshot()) | |
| return self._turn(user) | |
| def act(self, player_action: str) -> parser.TurnResult: | |
| """Process one player action.""" | |
| if self.state.game_over: | |
| return parser.TurnResult( | |
| narrative="Your tale has ended. Start a new adventure to play again.", | |
| choices=[], | |
| applied=[], | |
| raw="", | |
| ) | |
| action = player_action.strip() or "look around" | |
| user = prompts.build_turn_prompt(self.state.context_snapshot(), action) | |
| return self._turn(user) | |
| def reset(self) -> "GameEngine": | |
| self.state = GameState() | |
| self.history.clear() | |
| return self | |
| # ----------------------------------------------------------------- internal | |
| def _turn(self, user_message: str) -> parser.TurnResult: | |
| try: | |
| raw = self.backend.chat(prompts.SYSTEM_PROMPT, user_message) | |
| except Exception as exc: # network/model errors shouldn't crash the UI | |
| return parser.TurnResult( | |
| narrative=f"(The mists swirl β the storyteller faltered: {exc})", | |
| choices=["Try again."], | |
| applied=[], | |
| raw="", | |
| ) | |
| result = parser.run_turn(self.state, raw) | |
| self.history.append(result) | |
| return result | |