kards-env/archive/battlefield.py

269 lines
9.1 KiB
Python
Raw Normal View History

2025-09-05 17:05:43 +08:00
"""
战场系统实现
包含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}
==================
"""