252 lines
7.5 KiB
Python
252 lines
7.5 KiB
Python
|
|
"""
|
|||
|
|
卡牌管理器 - 管理手牌、抽牌堆、弃牌堆
|
|||
|
|
"""
|
|||
|
|
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
|
|||
|
|
}
|