kards-env/kards_battle/cards/deck.py

259 lines
8.6 KiB
Python
Raw Normal View History

2025-09-05 17:05:43 +08:00
"""
卡组构建和验证系统
"""
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