kards-env/kards_battle/cards/deck.py

259 lines
8.6 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""
卡组构建和验证系统
"""
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