""" 卡组构建和验证系统 """ from typing import List, Dict, Optional, Set, Tuple from collections import defaultdict, Counter from ..core.enums import Nation, Rarity from .card import BaseCard, UnitCard class DeckValidationError(Exception): """卡组验证错误""" pass class Deck: """卡组类""" def __init__( self, major_nation: Nation, minor_nation: Nation, hq_card: BaseCard, cards: List[BaseCard] ): self.major_nation = major_nation self.minor_nation = minor_nation self.hq_card = hq_card self.cards = cards.copy() # 39张正常卡牌 # 验证卡组 self._validate() def _validate(self): """验证卡组的合法性""" # 基础数量检查 if len(self.cards) != 39: raise DeckValidationError(f"卡组必须包含39张卡牌,当前有{len(self.cards)}张") # 国家验证 if self.major_nation not in Nation.get_majors(): raise DeckValidationError(f"主国{self.major_nation}不在允许的主要国家列表中") if self.minor_nation not in Nation.get_all(): raise DeckValidationError(f"盟国{self.minor_nation}不是有效的国家") if self.major_nation == self.minor_nation: raise DeckValidationError("主国和盟国不能相同") # 稀有度验证 self._validate_rarity_limits() # 国家限制验证 self._validate_nation_limits() def _validate_rarity_limits(self): """验证稀有度限制""" # 按卡牌名称统计每种稀有度的卡牌数量 card_name_counts = defaultdict(int) for card in self.cards: card_name_counts[card.name] += 1 # 检查每种卡牌是否超过稀有度限制 for card in self.cards: card_name = card.name card_count = card_name_counts[card_name] max_allowed = card.stats.rarity.max_copies_in_deck() if card.stats.rarity == Rarity.SPECIAL: if card_count > 0: raise DeckValidationError("0级卡牌不能带入初始卡组") elif card_count > max_allowed: raise DeckValidationError( f"卡牌'{card_name}'({card.stats.rarity})最多只能带{max_allowed}张,当前有{card_count}张" ) # 避免重复检查同名卡牌 card_name_counts[card_name] = 0 def _validate_nation_limits(self): """验证国家限制""" major_cards = 0 minor_cards = 0 invalid_cards = [] for card in self.cards: if self._is_major_nation_card(card): major_cards += 1 elif self._is_minor_nation_card(card): minor_cards += 1 # 检查是否违反盟国1级卡限制 if card.stats.rarity == Rarity.ELITE: raise DeckValidationError("不能带盟国的1级稀有度卡牌") else: invalid_cards.append(card) # 检查无效卡牌 if invalid_cards: invalid_names = [card.name for card in invalid_cards] raise DeckValidationError( f"以下卡牌不属于主国或盟国,无法带入卡组: {', '.join(invalid_names)}" ) # 检查盟国卡牌数量限制 if minor_cards > 12: raise DeckValidationError(f"盟国卡牌最多只能带12张,当前有{minor_cards}张") # 检查总数 total_expected = 39 total_actual = major_cards + minor_cards if total_actual != total_expected: raise DeckValidationError( f"卡组总数不匹配: 预期{total_expected}张,实际{total_actual}张" ) def _is_major_nation_card(self, card: BaseCard) -> bool: """检查卡牌是否属于主国""" # 原国家匹配 if card.stats.nation == self.major_nation: return True # 流亡国家匹配 if card.stats.exile_nations and self.major_nation in card.stats.exile_nations: return True return False def _is_minor_nation_card(self, card: BaseCard) -> bool: """检查卡牌是否属于盟国""" # 如果已经是主国卡,就不算盟国卡 if self._is_major_nation_card(card): return False # 原国家匹配 if card.stats.nation == self.minor_nation: return True # 流亡国家匹配 if card.stats.exile_nations and self.minor_nation in card.stats.exile_nations: return True return False def get_all_cards(self) -> List[BaseCard]: """获取包含HQ在内的所有卡牌(40张)""" return [self.hq_card] + self.cards def get_deck_cards(self) -> List[BaseCard]: """获取抽牌堆卡牌(39张,不包括HQ)""" return self.cards.copy() def get_statistics(self) -> Dict: """获取卡组统计信息""" stats = { 'total_cards': len(self.cards), 'major_nation': self.major_nation, 'minor_nation': self.minor_nation, 'rarity_distribution': defaultdict(int), 'nation_distribution': {'major': 0, 'minor': 0}, 'cost_distribution': defaultdict(int), 'card_type_distribution': defaultdict(int) } for card in self.cards: # 稀有度分布 stats['rarity_distribution'][card.stats.rarity] += 1 # 国家分布 if self._is_major_nation_card(card): stats['nation_distribution']['major'] += 1 else: stats['nation_distribution']['minor'] += 1 # 费用分布 stats['cost_distribution'][card.stats.cost] += 1 # 卡牌类型分布 stats['card_type_distribution'][card.card_type] += 1 return stats class DeckBuilder: """卡组构建器""" @staticmethod def build_deck( major_nation: Nation, minor_nation: Nation, cards: List[BaseCard], hq_card: Optional[BaseCard] = None ) -> Deck: """构建卡组""" # 如果没有提供HQ卡,创建默认HQ卡 if hq_card is None: hq_card = DeckBuilder.create_default_hq_card(major_nation) return Deck(major_nation, minor_nation, hq_card, cards) @staticmethod def create_default_hq_card(nation: Nation) -> BaseCard: """为指定国家创建默认HQ卡""" from .card import BaseCard, CardType # 创建一个简单的HQ卡实现 class HQCard(BaseCard): def can_be_played(self, game_state): return False # HQ卡不能被打出 def play_effect(self, game_state, target=None): return False # HQ卡没有打出效果 # 根据国家确定首都名称 capital_names = { Nation.GERMANY: "柏林", Nation.USA: "华盛顿", Nation.UK: "伦敦", Nation.JAPAN: "东京", Nation.SOVIET: "莫斯科", Nation.FINLAND: "赫尔辛基", Nation.POLAND: "华沙", Nation.FRANCE: "巴黎", Nation.ITALY: "罗马" } capital_name = capital_names.get(nation, "未知首都") return HQCard( name=f"{capital_name} HQ", card_type=CardType.ORDER, # 临时使用ORDER类型 cost=0, nation=nation, rarity=Rarity.SPECIAL, description=f"{nation}的指挥总部" ) @staticmethod def validate_deck_legality( major_nation: Nation, minor_nation: Nation, cards: List[BaseCard] ) -> Tuple[bool, List[str]]: """验证卡组合法性,返回(是否合法, 错误列表)""" errors = [] try: # 尝试构建卡组,会自动进行验证 hq_card = DeckBuilder.create_default_hq_card(major_nation) Deck(major_nation, minor_nation, hq_card, cards) return True, [] except DeckValidationError as e: errors.append(str(e)) return False, errors except Exception as e: errors.append(f"未知错误: {str(e)}") return False, errors