kards-env/archive/battlefield.py

269 lines
9.1 KiB
Python

"""
战场系统实现
包含HQ、前线、支援线的战场布局和管理
"""
from typing import List, Optional, Dict, Tuple
from dataclasses import dataclass
from uuid import UUID
from ..core.enums import LineType
from ..units.unit import Unit
@dataclass
class HQ:
"""总部类"""
defense: int = 20
current_defense: int = 20
player_id: str = ""
def take_damage(self, damage: int) -> int:
"""总部受到伤害"""
actual_damage = min(damage, self.current_defense)
self.current_defense -= actual_damage
return actual_damage
def is_destroyed(self) -> bool:
"""判断总部是否被摧毁"""
return self.current_defense <= 0
def __str__(self) -> str:
return f"HQ ({self.current_defense}/{self.defense})"
class BattleLine:
"""战线类(前线或支援线)"""
def __init__(self, line_type: LineType, max_positions: int = 5):
self.line_type = line_type
self.max_positions = max_positions
self.positions: List[Optional[Unit]] = [None] * max_positions
def deploy_unit(self, unit: Unit, position: int) -> bool:
"""在指定位置部署单位"""
if not self.is_position_valid(position):
return False
if self.positions[position] is not None:
return False # 位置被占用
self.positions[position] = unit
unit.position = (self.line_type, position)
return True
def remove_unit(self, position: int) -> Optional[Unit]:
"""移除指定位置的单位"""
if not self.is_position_valid(position):
return None
unit = self.positions[position]
if unit:
self.positions[position] = None
unit.position = None
return unit
def get_unit_at(self, position: int) -> Optional[Unit]:
"""获取指定位置的单位"""
if not self.is_position_valid(position):
return None
return self.positions[position]
def get_all_units(self) -> List[Unit]:
"""获取战线上所有单位"""
return [unit for unit in self.positions if unit is not None]
def find_unit_position(self, unit: Unit) -> Optional[int]:
"""查找单位在战线上的位置"""
try:
return self.positions.index(unit)
except ValueError:
return None
def is_position_valid(self, position: int) -> bool:
"""检查位置是否有效"""
return 0 <= position < self.max_positions
def is_position_empty(self, position: int) -> bool:
"""检查位置是否为空"""
return self.is_position_valid(position) and self.positions[position] is None
def get_adjacent_positions(self, position: int) -> List[int]:
"""获取相邻位置"""
if not self.is_position_valid(position):
return []
adjacent = []
if position > 0:
adjacent.append(position - 1)
if position < self.max_positions - 1:
adjacent.append(position + 1)
return adjacent
def get_adjacent_units(self, position: int) -> List[Unit]:
"""获取相邻单位"""
adjacent_positions = self.get_adjacent_positions(position)
return [self.positions[pos] for pos in adjacent_positions
if self.positions[pos] is not None]
def is_full(self) -> bool:
"""检查战线是否已满"""
return all(pos is not None for pos in self.positions)
def get_empty_positions(self) -> List[int]:
"""获取所有空位置"""
return [i for i, pos in enumerate(self.positions) if pos is None]
def __str__(self) -> str:
unit_strs = []
for i, unit in enumerate(self.positions):
if unit:
unit_strs.append(f"{i}:{unit.name}")
else:
unit_strs.append(f"{i}:空")
return f"{self.line_type} [{', '.join(unit_strs)}]"
class Battlefield:
"""战场类,管理整个战场状态"""
def __init__(self, player1_id: str, player2_id: str):
# 玩家信息
self.player1_id = player1_id
self.player2_id = player2_id
# HQ
self.player1_hq = HQ(player_id=player1_id)
self.player2_hq = HQ(player_id=player2_id)
# 战线
self.player1_support = BattleLine(LineType.SUPPORT)
self.player1_front = BattleLine(LineType.FRONT)
self.player2_support = BattleLine(LineType.SUPPORT)
self.player2_front = BattleLine(LineType.FRONT)
# 单位索引(快速查找)
self.unit_registry: Dict[UUID, Unit] = {}
def get_player_hq(self, player_id: str) -> Optional[HQ]:
"""获取玩家的HQ"""
if player_id == self.player1_id:
return self.player1_hq
elif player_id == self.player2_id:
return self.player2_hq
return None
def get_player_line(self, player_id: str, line_type: LineType) -> Optional[BattleLine]:
"""获取玩家的战线"""
if player_id == self.player1_id:
return self.player1_support if line_type == LineType.SUPPORT else self.player1_front
elif player_id == self.player2_id:
return self.player2_support if line_type == LineType.SUPPORT else self.player2_front
return None
def get_enemy_line(self, player_id: str, line_type: LineType) -> Optional[BattleLine]:
"""获取敌方的战线"""
enemy_id = self.get_enemy_player_id(player_id)
return self.get_player_line(enemy_id, line_type) if enemy_id else None
def get_enemy_player_id(self, player_id: str) -> Optional[str]:
"""获取敌方玩家ID"""
if player_id == self.player1_id:
return self.player2_id
elif player_id == self.player2_id:
return self.player1_id
return None
def deploy_unit(self, unit: Unit, player_id: str, line_type: LineType, position: int) -> bool:
"""部署单位到战场"""
battle_line = self.get_player_line(player_id, line_type)
if not battle_line:
return False
if battle_line.deploy_unit(unit, position):
unit.owner = player_id
self.unit_registry[unit.id] = unit
return True
return False
def remove_unit(self, unit: Unit) -> bool:
"""从战场移除单位"""
if unit.position is None:
return False
line_type, position = unit.position
battle_line = self.get_player_line(unit.owner, line_type)
if battle_line and battle_line.remove_unit(position):
if unit.id in self.unit_registry:
del self.unit_registry[unit.id]
return True
return False
def get_all_units(self, player_id: Optional[str] = None) -> List[Unit]:
"""获取所有单位,可按玩家筛选"""
all_units = []
lines = []
if player_id is None:
lines = [self.player1_support, self.player1_front,
self.player2_support, self.player2_front]
else:
support = self.get_player_line(player_id, LineType.SUPPORT)
front = self.get_player_line(player_id, LineType.FRONT)
if support and front:
lines = [support, front]
for line in lines:
all_units.extend(line.get_all_units())
return all_units
def find_unit(self, unit_id: UUID) -> Optional[Unit]:
"""通过ID查找单位"""
return self.unit_registry.get(unit_id)
def get_units_with_keyword(self, keyword: str, player_id: Optional[str] = None) -> List[Unit]:
"""获取具有特定关键词的所有单位"""
units = self.get_all_units(player_id)
return [unit for unit in units if unit.has_keyword(keyword)]
def is_game_over(self) -> Tuple[bool, Optional[str]]:
"""检查游戏是否结束,返回(是否结束, 胜利者ID)"""
if self.player1_hq.is_destroyed():
return True, self.player2_id
elif self.player2_hq.is_destroyed():
return True, self.player1_id
return False, None
def get_valid_attack_targets(self, attacker: Unit) -> List[Unit]:
"""获取单位可以攻击的所有目标"""
if not attacker.owner:
return []
enemy_id = self.get_enemy_player_id(attacker.owner)
if not enemy_id:
return []
enemy_units = self.get_all_units(enemy_id)
valid_targets = []
for target in enemy_units:
if (attacker.can_attack_target(target, self) and
target.can_be_attacked_by(attacker, self)):
valid_targets.append(target)
return valid_targets
def __str__(self) -> str:
return f"""
=== 战场状态 ===
玩家1 ({self.player1_id}):
HQ: {self.player1_hq}
{self.player1_support}
{self.player1_front}
玩家2 ({self.player2_id}):
HQ: {self.player2_hq}
{self.player2_support}
{self.player2_front}
==================
"""