kards-env/kards_battle/cards/card_manager.py

252 lines
7.5 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, Optional, Set
import random
from collections import deque
from .card import BaseCard
from .deck import Deck
class CardManager:
"""卡牌管理器 - 管理单个玩家的所有卡牌状态"""
def __init__(self, deck: Deck):
self.deck = deck
# 抽牌堆 - 使用deque提高性能
self.draw_pile: deque = deque(deck.get_deck_cards())
# 手牌
self.hand: List[BaseCard] = []
# 弃牌堆
self.discard_pile: List[BaseCard] = []
# 疲劳系统
self.fatigue_damage = 1 # 当前疲劳伤害
self.total_fatigue_taken = 0 # 总疲劳伤害
# 战略调度标记
self.strategic_deployment_completed = False
# 手牌大小限制(如果有的话)
self.max_hand_size = 10 # 默认最大手牌数
# 洗牌抽牌堆
self.shuffle_draw_pile()
def shuffle_draw_pile(self):
"""洗牌抽牌堆"""
draw_list = list(self.draw_pile)
random.shuffle(draw_list)
self.draw_pile = deque(draw_list)
def draw_card(self, hq_defense_callback: callable = None) -> Optional[BaseCard]:
"""
抽一张牌
如果抽牌堆为空对HQ造成疲劳伤害
Args:
hq_defense_callback: HQ受伤回调函数接收伤害值作为参数
Returns:
抽到的卡牌如果抽牌堆为空且造成疲劳伤害则返回None
"""
if self.draw_pile:
# 正常抽牌
card = self.draw_pile.popleft()
self.hand.append(card)
return card
else:
# 抽牌堆为空,造成疲劳伤害
if hq_defense_callback:
hq_defense_callback(self.fatigue_damage)
self.total_fatigue_taken += self.fatigue_damage
self.fatigue_damage += 1 # 疲劳伤害递增
return None
def draw_multiple_cards(self, count: int, hq_defense_callback: callable = None) -> List[BaseCard]:
"""
抽多张牌
Args:
count: 要抽的牌数
hq_defense_callback: HQ受伤回调函数
Returns:
成功抽到的卡牌列表
"""
drawn_cards = []
for _ in range(count):
card = self.draw_card(hq_defense_callback)
if card:
drawn_cards.append(card)
return drawn_cards
def initial_draw(self, count: int) -> List[BaseCard]:
"""
初始摸牌(不会触发疲劳伤害)
Args:
count: 要抽的牌数
Returns:
抽到的卡牌列表
"""
drawn_cards = []
for _ in range(min(count, len(self.draw_pile))):
if self.draw_pile:
card = self.draw_pile.popleft()
self.hand.append(card)
drawn_cards.append(card)
return drawn_cards
def play_card_from_hand(self, card: BaseCard) -> bool:
"""
从手牌打出一张卡
Args:
card: 要打出的卡牌
Returns:
是否成功从手牌移除
"""
if card in self.hand:
self.hand.remove(card)
return True
return False
def discard_card(self, card: BaseCard):
"""将卡牌放入弃牌堆"""
self.discard_pile.append(card)
def discard_from_hand(self, card: BaseCard) -> bool:
"""
从手牌弃置一张卡
Args:
card: 要弃置的卡牌
Returns:
是否成功弃置
"""
if card in self.hand:
self.hand.remove(card)
self.discard_card(card)
return True
return False
def strategic_deployment(self, cards_to_mulligan: List[BaseCard]) -> List[BaseCard]:
"""
战略调度 - 重新抽取不想要的卡牌
Args:
cards_to_mulligan: 要重抽的卡牌列表
Returns:
新抽到的卡牌列表
"""
if self.strategic_deployment_completed:
raise ValueError("战略调度已经完成,不能重复进行")
# 验证所有卡牌都在手牌中
for card in cards_to_mulligan:
if card not in self.hand:
raise ValueError(f"卡牌 {card.name} 不在手牌中")
# 移除要重抽的卡牌
for card in cards_to_mulligan:
self.hand.remove(card)
# 将这些卡牌放回抽牌堆
for card in cards_to_mulligan:
self.draw_pile.append(card)
# 重新洗牌
self.shuffle_draw_pile()
# 抽取相同数量的新卡
new_cards = []
for _ in range(len(cards_to_mulligan)):
if self.draw_pile:
card = self.draw_pile.popleft()
self.hand.append(card)
new_cards.append(card)
self.strategic_deployment_completed = True
return new_cards
def can_draw_safely(self) -> bool:
"""检查是否可以安全抽牌(不会触发疲劳)"""
return len(self.draw_pile) > 0
def cards_remaining_in_deck(self) -> int:
"""返回抽牌堆剩余卡牌数量"""
return len(self.draw_pile)
def hand_size(self) -> int:
"""返回当前手牌数量"""
return len(self.hand)
def is_hand_full(self) -> bool:
"""检查手牌是否已满"""
return len(self.hand) >= self.max_hand_size
def get_hand_copy(self) -> List[BaseCard]:
"""获取手牌的副本"""
return self.hand.copy()
def get_card_in_hand_by_name(self, name: str) -> Optional[BaseCard]:
"""根据名称在手牌中查找卡牌"""
for card in self.hand:
if card.name == name:
return card
return None
def get_playable_cards(self, current_kredits: int) -> List[BaseCard]:
"""
获取当前可以打出的卡牌(基于费用)
Args:
current_kredits: 当前可用的kredits
Returns:
可以打出的卡牌列表
"""
playable = []
for card in self.hand:
if card.stats.cost <= current_kredits:
playable.append(card)
return playable
def reshuffle_discard_into_deck(self):
"""
将弃牌堆重新洗入抽牌堆
这个功能可能在某些特殊卡牌效果中使用
"""
if self.discard_pile:
# 将弃牌堆的卡牌加入抽牌堆
for card in self.discard_pile:
self.draw_pile.append(card)
# 清空弃牌堆
self.discard_pile.clear()
# 重新洗牌
self.shuffle_draw_pile()
def get_statistics(self) -> dict:
"""获取卡牌管理器统计信息"""
return {
'hand_size': len(self.hand),
'cards_in_deck': len(self.draw_pile),
'cards_in_discard': len(self.discard_pile),
'fatigue_damage': self.fatigue_damage,
'total_fatigue_taken': self.total_fatigue_taken,
'strategic_deployment_used': self.strategic_deployment_completed,
'max_hand_size': self.max_hand_size
}