155 lines
4.3 KiB
Python
155 lines
4.3 KiB
Python
"""
|
|
Player 玩家抽象基类
|
|
支持人类玩家和 AI 玩家
|
|
"""
|
|
from abc import ABC, abstractmethod
|
|
from typing import Optional, Dict, Any
|
|
from enum import Enum
|
|
import uuid
|
|
import time
|
|
|
|
|
|
class PlayerType(Enum):
|
|
HUMAN = "human"
|
|
AI = "ai"
|
|
|
|
|
|
class Player(ABC):
|
|
"""
|
|
玩家抽象基类
|
|
封装玩家的通用属性和行为
|
|
"""
|
|
|
|
def __init__(self, name: str, player_id: Optional[str] = None):
|
|
self.id = player_id or f"player_{uuid.uuid4().hex[:8]}"
|
|
self.name = name
|
|
self.type: PlayerType = PlayerType.HUMAN
|
|
|
|
# 连接状态
|
|
self.is_connected = False
|
|
self.socket_id: Optional[str] = None
|
|
self.connected_at: Optional[float] = None
|
|
|
|
# 房间状态
|
|
self.room_id: Optional[str] = None
|
|
self.seat_number: Optional[int] = None
|
|
|
|
# 游戏状态
|
|
self.is_ready = False
|
|
self.role: Optional[str] = None # landlord/farmer/red/black
|
|
|
|
# 断线托管
|
|
self.is_ai_controlled = False # 是否处于AI托管模式
|
|
self.offline_since: Optional[float] = None # 离线时间戳
|
|
self.original_ai_control = False # 记录原始状态,用于恢复
|
|
|
|
# 统计数据
|
|
self.total_games = 0
|
|
self.win_count = 0
|
|
self.score = 0
|
|
|
|
@property
|
|
@abstractmethod
|
|
def is_ai(self) -> bool:
|
|
"""是否为 AI 玩家"""
|
|
pass
|
|
|
|
def connect(self, socket_id: str):
|
|
"""玩家连接"""
|
|
self.socket_id = socket_id
|
|
self.is_connected = True
|
|
self.connected_at = time.time()
|
|
|
|
def disconnect(self):
|
|
"""玩家断开连接"""
|
|
self.socket_id = None
|
|
self.is_connected = False
|
|
self.offline_since = time.time()
|
|
|
|
def enable_ai_control(self):
|
|
"""启用AI托管"""
|
|
self.is_ai_controlled = True
|
|
|
|
def disable_ai_control(self):
|
|
"""取消AI托管,恢复人工控制"""
|
|
self.is_ai_controlled = False
|
|
self.offline_since = None
|
|
|
|
def join_room(self, room_id: str, seat: int):
|
|
"""加入房间"""
|
|
self.room_id = room_id
|
|
self.seat_number = seat
|
|
|
|
def leave_room(self):
|
|
"""离开房间"""
|
|
self.room_id = None
|
|
self.seat_number = None
|
|
self.is_ready = False
|
|
self.role = None
|
|
|
|
def set_ready(self, ready: bool = True):
|
|
"""设置准备状态"""
|
|
self.is_ready = ready
|
|
|
|
def to_dict(self, include_private: bool = False) -> Dict[str, Any]:
|
|
"""序列化为字典"""
|
|
data = {
|
|
'id': self.id,
|
|
'name': self.name,
|
|
'type': self.type.value,
|
|
'is_ai': self.is_ai,
|
|
'is_connected': self.is_connected,
|
|
'is_ai_controlled': self.is_ai_controlled,
|
|
'seat_number': self.seat_number,
|
|
'is_ready': self.is_ready,
|
|
'role': self.role,
|
|
}
|
|
|
|
if include_private:
|
|
data.update({
|
|
'room_id': self.room_id,
|
|
'socket_id': self.socket_id,
|
|
'offline_since': self.offline_since,
|
|
'total_games': self.total_games,
|
|
'win_count': self.win_count,
|
|
'score': self.score,
|
|
})
|
|
|
|
return data
|
|
|
|
def __repr__(self):
|
|
return f"<{self.__class__.__name__}(id={self.id[:8]}, name={self.name}, seat={self.seat_number})>"
|
|
|
|
|
|
class HumanPlayer(Player):
|
|
"""人类玩家"""
|
|
|
|
def __init__(self, name: str, player_id: Optional[str] = None):
|
|
super().__init__(name, player_id)
|
|
self.type = PlayerType.HUMAN
|
|
|
|
@property
|
|
def is_ai(self) -> bool:
|
|
return False
|
|
|
|
|
|
class AIPlayer(Player):
|
|
"""AI 玩家"""
|
|
|
|
def __init__(self, name: str, ai_type: str, ai_config: Optional[Dict] = None):
|
|
super().__init__(name)
|
|
self.type = PlayerType.AI
|
|
self.ai_type = ai_type # "rule", "minimax", "deepseek"
|
|
self.ai_config = ai_config or {}
|
|
self.is_connected = True # AI 始终在线
|
|
self.is_ready = True # AI 自动准备
|
|
|
|
@property
|
|
def is_ai(self) -> bool:
|
|
return True
|
|
|
|
def to_dict(self, include_private: bool = False) -> Dict[str, Any]:
|
|
data = super().to_dict(include_private)
|
|
data['ai_type'] = self.ai_type
|
|
return data
|