feat: add human http agent
This commit is contained in:
+39
-1
@@ -110,10 +110,14 @@ class TableGame:
|
||||
board=list(self.board),
|
||||
actions=list(self.action_history),
|
||||
awards=awards,
|
||||
showdown_hands=self._collect_showdown_hands(),
|
||||
started_at=started_at,
|
||||
finished_at=time(),
|
||||
)
|
||||
self.hand_summaries.append(summary)
|
||||
# Notify every agent so HTTP-backed clients can render the just
|
||||
# finished hand. Failures here must never abort the table.
|
||||
self._broadcast_game_update()
|
||||
return summary
|
||||
|
||||
def run_hands(self, max_hands: int, until_one_left: bool = False) -> list[HandSummary]:
|
||||
@@ -140,7 +144,10 @@ class TableGame:
|
||||
"big_blind": self.big_blind,
|
||||
"starting_stack": self.starting_stack,
|
||||
"players": [player.public_dict() for player in self.players],
|
||||
"last_hand": self.hand_summaries[-1].to_dict() if self.hand_summaries else None,
|
||||
# ``hands`` exposes every finished hand (each entry is the same
|
||||
# dict that was previously returned as ``last_hand``). Callers
|
||||
# that only want the most recent one can do ``hands[-1]``.
|
||||
"hands": [summary.to_dict() for summary in self.hand_summaries],
|
||||
}
|
||||
|
||||
def _advance_button(self) -> None:
|
||||
@@ -448,6 +455,37 @@ class TableGame:
|
||||
)
|
||||
return awards
|
||||
|
||||
def _collect_showdown_hands(self) -> dict[str, list]:
|
||||
"""Snapshot hole cards of every player still eligible at showdown.
|
||||
|
||||
We treat a hand as having reached showdown iff at least two players
|
||||
remain ``in_hand`` and unfolded after the river. Returning an empty
|
||||
dict for the one-player-left case keeps the wire format compact and
|
||||
avoids leaking hole cards when there was no real comparison.
|
||||
"""
|
||||
live_players = [player for player in self.players if self._is_live(player)]
|
||||
if len(live_players) < 2:
|
||||
return {}
|
||||
return {
|
||||
player.player_id: list(player.hole_cards) for player in live_players
|
||||
}
|
||||
|
||||
def _broadcast_game_update(self) -> None:
|
||||
"""Push the post-hand game snapshot to every agent's optional hook.
|
||||
|
||||
Agents may opt into receiving game updates by overriding
|
||||
:meth:`PokerAgent.on_game_update`. The default implementation is a
|
||||
no-op, so this loop is essentially free for non-HTTP agents. We
|
||||
swallow individual exceptions so a flaky remote endpoint cannot
|
||||
break the table flow.
|
||||
"""
|
||||
snapshot = self.to_dict()
|
||||
for agent in self.agents.values():
|
||||
try:
|
||||
agent.on_game_update(snapshot)
|
||||
except Exception:
|
||||
continue
|
||||
|
||||
def _record_action(
|
||||
self,
|
||||
player: PlayerState,
|
||||
|
||||
Reference in New Issue
Block a user