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