import uuid from typing import List, Optional, Dict from shortdeck_arena.simulation import Simulation from shortdeck_arena.agent import Agent, HumanAgent from shortdeck_arena.game_stage import BlindConfig class ArenaGame: def __init__(self, starting_stack: int = 1000, max_players: int = 6, small_blind: int = 1, big_blind: int = 2): self.agents = [] self.player_names: List[str] = [] self.starting_stack = starting_stack self.max_players = max_players self.sim: Optional[Simulation] = None self.blind_config = BlindConfig(small_blind, big_blind, ante=0) self.game_id = str(uuid.uuid4()) def join_game(self, name) -> int: if len(self.agents) >= self.max_players: raise ValueError("Game is full") player_id = len(self.agents) agent = HumanAgent(player_id) self.agents.append(agent) self.player_names.append(name) if len(self.agents) == 1: self.sim = Simulation(self.agents, blind_config=self.blind_config) # 筹码默认1000 self.sim.stacks = [self.starting_stack] * len(self.agents) elif self.sim: self.sim.agents = self.agents self.sim.player_states.append(self.sim.player_states[0].__class__.ACTIVE) self.sim.pot.append(0) self.sim.stacks.append(self.starting_stack) # 当有至少2个玩家时,触发新一轮 if len(self.agents) >= 2 and self.sim: self.sim.stacks = [self.starting_stack] * len(self.agents) self.sim.new_round() return player_id def apply_action(self, player_id, action, amount: Optional[int] = None) -> dict: if not self.sim: return {"success": False, "message": "游戏未开始"} try: self.sim.apply_action(player_id, action, amount) self.sim.dump_data() return {"success": True, "message": f"Applied {action}"} except Exception as e: return {"success": False, "message": str(e)} def info(self, player_id: Optional[int] = None) -> Dict: if not self.sim: return {"error": "游戏未初始化"} info_data = { "game_id": self.game_id, "players": self.player_names, "dealer_index": self.sim.dealer_position, "current_turn": self.sim.current_turn, "stage": self.sim.current_stage.value, "total_pot": self.sim.total_pot, "side_pots": [{"amount": pot.amount, "eligible_players": list(pot.eligible_players)} for pot in self.sim.get_side_pots()], } if player_id is not None and 0 <= player_id < len(self.sim.stacks): try: player_cards = self.sim.player_cards(player_id) info_data["player_cards"] = [str(card) for card in player_cards] except Exception: info_data["player_cards"] = [] info_data["actions"] = self.sim.get_available_actions(player_id) else: info_data["player_cards"] = [] info_data["actions"] = {"can_act": False, "reason": "Invalid player"} try: board_cards = self.sim.board_cards(self.sim.current_stage.value) info_data["board_cards"] = [str(card) for card in board_cards] except Exception: info_data["board_cards"] = [] info_data["stacks"] = self.sim.stacks.copy() info_data["player_states"] = [state.value for state in self.sim.player_states] info_data["current_pot"] = self.sim.pot.copy() return info_data def get_hand_strength(self, player_id: int) -> Dict: ranking = self.sim.evaluate_player_hand(player_id) if ranking is None: return {"error": "无法评估手牌"} return { "hand_type": ranking.hand_type.type_name, "description": str(ranking), "strength": ranking.get_strength(), "cards": [str(card) for card in ranking.cards] } def check_hand_complete(self) -> bool: return self.sim.is_hand_complete() if self.sim else False def get_winners(self) -> Dict: if not self.sim: return {"error": "游戏未初始化"} if not self.sim.is_hand_complete(): return {"error": "手牌未完成"} return self.sim.complete_hand() def showdown(self) -> Dict: if not self.sim: return {"error": "游戏未初始化"} winners = self.sim.determine_winners() showdown_info = {} for pid, ranking in winners.items(): if ranking is not None: showdown_info[pid] = { "cards": [str(card) for card in self.sim.player_cards(pid)], "hand_type": ranking.hand_type.type_name, "description": str(ranking), "strength": ranking.get_strength() } else: showdown_info[pid] = { "cards": [str(card) for card in self.sim.player_cards(pid)], "hand_type": "Winner by default", "description": "Other players folded", "strength": float('inf') } return { "showdown": showdown_info, "pot_distribution": self.sim.distribute_pot() } @property def pot(self) -> int: return self.sim.total_pot if self.sim else 0 @property def stacks(self) -> List[int]: return self.sim.stacks if self.sim else [] @property def current_turn(self) -> int: return self.sim.current_turn if self.sim else -1 @property def history(self) -> List[Dict]: return self.sim.history if self.sim else []