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
|
||
} |