kards-env/kards_battle/cards/card_params.py

426 lines
15 KiB
Python
Raw Permalink Normal View History

2025-09-05 17:05:43 +08:00
"""
卡牌参数定义系统
支持卡牌使用时的参数化操作
"""
from typing import Dict, List, Any, Optional, Union, Set
from dataclasses import dataclass
from enum import Enum
class ParameterType(Enum):
"""参数类型枚举"""
SLOT = "slot" # 部署槽位 (0-4)
TARGET = "target" # 通用目标选择
MULTI_TARGET = "multi_target" # 多目标选择
POSITION = "position" # 位置选择 (区域+槽位)
VALUE = "value" # 数值参数
CHOICE = "choice" # 选择列表
class ZoneType(Enum):
"""区域类型枚举(卡牌使用时)"""
OWN = "O" # 己方支援线
FRONT = "F" # 前线
ENEMY = "E" # 敌方支援线
class TargetType(Enum):
"""目标类型枚举"""
UNIT = "unit" # 单位
HQ = "hq" # 总部
PLAYER = "player" # 玩家
ANY = "any" # 任意类型
class FilterType(Enum):
"""目标筛选类型"""
FRIENDLY = "friendly" # 友方
ENEMY = "enemy" # 敌方
ANY = "any" # 任意
@dataclass
class ParameterDefinition:
"""参数定义"""
name: str # 参数名称
param_type: ParameterType # 参数类型
required: bool = True # 是否必需
description: str = "" # 参数描述
# slot类型参数
slot_range: Optional[List[int]] = None # [min, max] 槽位范围
# target/multi_target类型参数
target_type: Optional[TargetType] = None # 目标类型
valid_zones: Optional[List[ZoneType]] = None # 有效区域
target_filter: Optional[FilterType] = None # 目标筛选
unit_type_filter: Optional[List[str]] = None # 单位类型筛选
nation_filter: Optional[List[str]] = None # 国家筛选
# multi_target特有
min_count: int = 1 # 最少选择数量
max_count: int = 1 # 最多选择数量
# position类型参数
must_be_empty: bool = False # 位置必须为空
# value类型参数
min_value: Optional[int] = None # 最小值
max_value: Optional[int] = None # 最大值
default_value: Optional[int] = None # 默认值
# choice类型参数
choices: Optional[List[str]] = None # 可选择的选项
@classmethod
def from_dict(cls, data: Dict[str, Any]) -> 'ParameterDefinition':
"""从字典创建参数定义"""
param_type = ParameterType(data['type'])
# 基础参数
definition = cls(
name=data['name'],
param_type=param_type,
required=data.get('required', True),
description=data.get('description', '')
)
# slot类型参数
if param_type == ParameterType.SLOT:
if 'range' in data:
definition.slot_range = data['range']
# target相关参数
elif param_type in [ParameterType.TARGET, ParameterType.MULTI_TARGET]:
if 'target_type' in data:
definition.target_type = TargetType(data['target_type'])
if 'valid_zones' in data:
definition.valid_zones = [ZoneType(zone) for zone in data['valid_zones']]
if 'filter' in data:
definition.target_filter = FilterType(data['filter'])
if 'unit_type_filter' in data:
definition.unit_type_filter = data['unit_type_filter']
if 'nation_filter' in data:
definition.nation_filter = data['nation_filter']
# multi_target特有
if param_type == ParameterType.MULTI_TARGET:
definition.min_count = data.get('min_count', 1)
definition.max_count = data.get('max_count', 1)
# position类型参数
elif param_type == ParameterType.POSITION:
if 'valid_zones' in data:
definition.valid_zones = [ZoneType(zone) for zone in data['valid_zones']]
definition.must_be_empty = data.get('must_be_empty', False)
# value类型参数
elif param_type == ParameterType.VALUE:
definition.min_value = data.get('min', None)
definition.max_value = data.get('max', None)
definition.default_value = data.get('default', None)
# choice类型参数
elif param_type == ParameterType.CHOICE:
definition.choices = data.get('choices', [])
return definition
@dataclass
class CardParameterValue:
"""卡牌参数值"""
name: str # 参数名称
value: Any # 参数值
def __str__(self) -> str:
return f"{self.name}={self.value}"
class CardParameterValidator:
"""卡牌参数验证器"""
@staticmethod
def validate_slot_parameter(definition: ParameterDefinition, value: int) -> bool:
"""验证槽位参数"""
if not isinstance(value, int):
return False
if definition.slot_range:
min_slot, max_slot = definition.slot_range
return min_slot <= value <= max_slot
# 默认0-4槽位
return 0 <= value <= 4
@staticmethod
def validate_target_parameter(
definition: ParameterDefinition,
value: Dict[str, Any],
game_state: Any = None
) -> bool:
"""验证目标参数"""
if not isinstance(value, dict):
return False
# 根据目标类型验证不同的结构
target_type = definition.target_type or TargetType.UNIT
if target_type == TargetType.HQ:
# HQ目标只需要指定哪个玩家的HQ
if 'player' not in value:
return False
# player应该是0或1
if not isinstance(value['player'], int) or value['player'] not in [0, 1]:
return False
elif target_type == TargetType.PLAYER:
# 玩家目标只需要指定玩家ID
if 'player' not in value:
return False
if not isinstance(value['player'], int) or value['player'] not in [0, 1]:
return False
elif target_type == TargetType.UNIT:
# 单位目标需要zone和slot
if 'zone' not in value or 'slot' not in value:
return False
zone = value['zone']
slot = value['slot']
# 验证zone是否在valid_zones中
if definition.valid_zones:
try:
zone_type = ZoneType(zone)
if zone_type not in definition.valid_zones:
return False
except ValueError:
return False
# 验证slot范围
if not isinstance(slot, int) or not (0 <= slot <= 4):
return False
# TODO: 如果提供了game_state验证目标是否存在且符合筛选条件
return True
@staticmethod
def validate_multi_target_parameter(
definition: ParameterDefinition,
value: List[Dict[str, Any]],
game_state: Any = None
) -> bool:
"""验证多目标参数"""
if not isinstance(value, list):
return False
# 验证数量
if len(value) < definition.min_count or len(value) > definition.max_count:
return False
# 验证每个目标
for target in value:
if not CardParameterValidator.validate_target_parameter(
definition, target, game_state
):
return False
return True
@staticmethod
def validate_position_parameter(
definition: ParameterDefinition,
value: Dict[str, Any],
game_state: Any = None
) -> bool:
"""验证位置参数"""
if not isinstance(value, dict):
return False
# 必须包含zone和slot
if 'zone' not in value or 'slot' not in value:
return False
zone = value['zone']
slot = value['slot']
# 验证zone
if definition.valid_zones:
try:
zone_type = ZoneType(zone)
if zone_type not in definition.valid_zones:
return False
except ValueError:
return False
# 验证slot
if not isinstance(slot, int) or not (0 <= slot <= 4):
return False
# TODO: 如果must_be_empty为True且提供了game_state验证位置是否为空
return True
@staticmethod
def validate_value_parameter(definition: ParameterDefinition, value: int) -> bool:
"""验证数值参数"""
if not isinstance(value, int):
return False
if definition.min_value is not None and value < definition.min_value:
return False
if definition.max_value is not None and value > definition.max_value:
return False
return True
@staticmethod
def validate_choice_parameter(definition: ParameterDefinition, value: str) -> bool:
"""验证选择参数"""
if not isinstance(value, str):
return False
if definition.choices and value not in definition.choices:
return False
return True
@staticmethod
def validate_parameter(
definition: ParameterDefinition,
value: Any,
game_state: Any = None
) -> bool:
"""验证参数值"""
if definition.param_type == ParameterType.SLOT:
return CardParameterValidator.validate_slot_parameter(definition, value)
elif definition.param_type == ParameterType.TARGET:
return CardParameterValidator.validate_target_parameter(
definition, value, game_state
)
elif definition.param_type == ParameterType.MULTI_TARGET:
return CardParameterValidator.validate_multi_target_parameter(
definition, value, game_state
)
elif definition.param_type == ParameterType.POSITION:
return CardParameterValidator.validate_position_parameter(
definition, value, game_state
)
elif definition.param_type == ParameterType.VALUE:
return CardParameterValidator.validate_value_parameter(definition, value)
elif definition.param_type == ParameterType.CHOICE:
return CardParameterValidator.validate_choice_parameter(definition, value)
return False
@staticmethod
def validate_card_parameters(
definitions: List[ParameterDefinition],
parameters: Dict[str, Any],
game_state: Any = None
) -> Dict[str, str]:
"""
验证卡牌参数集合
Returns:
错误信息字典空字典表示验证通过
"""
errors = {}
# 检查必需参数是否提供
for definition in definitions:
if definition.required and definition.name not in parameters:
errors[definition.name] = f"Missing required parameter: {definition.name}"
# 验证提供的参数
for param_name, param_value in parameters.items():
# 查找参数定义
definition = None
for param_def in definitions:
if param_def.name == param_name:
definition = param_def
break
if definition is None:
errors[param_name] = f"Unknown parameter: {param_name}"
continue
# 验证参数值
if not CardParameterValidator.validate_parameter(
definition, param_value, game_state
):
errors[param_name] = f"Invalid value for parameter {param_name}: {param_value}"
return errors
class CardParameterHelper:
"""卡牌参数辅助类"""
@staticmethod
def get_default_parameters(definitions: List[ParameterDefinition]) -> Dict[str, Any]:
"""获取参数默认值"""
defaults = {}
for definition in definitions:
if not definition.required:
if definition.param_type == ParameterType.VALUE and definition.default_value is not None:
defaults[definition.name] = definition.default_value
elif definition.param_type == ParameterType.SLOT:
# slot类型可以不指定让系统自动选择
pass
return defaults
@staticmethod
def format_parameter_value(definition: ParameterDefinition, value: Any) -> str:
"""格式化参数值显示"""
if definition.param_type == ParameterType.SLOT:
return f"slot {value}"
elif definition.param_type == ParameterType.TARGET:
if isinstance(value, dict):
target_type = definition.target_type or TargetType.UNIT
if target_type == TargetType.HQ:
return f"HQ{value.get('player', '?')}"
elif target_type == TargetType.PLAYER:
return f"Player{value.get('player', '?')}"
elif target_type == TargetType.UNIT:
if 'zone' in value and 'slot' in value:
return f"{value['zone']}{value['slot']}"
elif definition.param_type == ParameterType.POSITION:
if isinstance(value, dict) and 'zone' in value and 'slot' in value:
return f"{value['zone']}{value['slot']}"
elif definition.param_type == ParameterType.MULTI_TARGET:
if isinstance(value, list):
targets = []
target_type = definition.target_type or TargetType.UNIT
for target in value:
if isinstance(target, dict):
if target_type == TargetType.HQ:
targets.append(f"HQ{target.get('player', '?')}")
elif target_type == TargetType.PLAYER:
targets.append(f"Player{target.get('player', '?')}")
elif target_type == TargetType.UNIT:
if 'zone' in target and 'slot' in target:
targets.append(f"{target['zone']}{target['slot']}")
return ", ".join(targets)
elif definition.param_type == ParameterType.VALUE:
return str(value)
elif definition.param_type == ParameterType.CHOICE:
return str(value)
return str(value)