kards-env/kards_battle/cards/card_params.py

426 lines
15 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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