166 lines
5.9 KiB
Python
166 lines
5.9 KiB
Python
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 [] |