426 lines
15 KiB
Python
426 lines
15 KiB
Python
"""
|
||
卡牌参数定义系统
|
||
支持卡牌使用时的参数化操作
|
||
"""
|
||
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) |