226 lines
6.5 KiB
Python
226 lines
6.5 KiB
Python
"""
|
|
MTG Rules Engine - Keyword Validator Module
|
|
|
|
Validates keyword usage in card text, spell resolution, and game actions.
|
|
Uses the hardcoded keyword database from keywords_db.py.
|
|
"""
|
|
|
|
from .keywords_db import (
|
|
KEYWORD_ACTIONS,
|
|
KEYWORD_ABILITIES,
|
|
ABILITY_WORDS,
|
|
KEYWORD_VARIANTS,
|
|
KEYWORD_TYPES,
|
|
get_keyword_definition,
|
|
get_all_keywords,
|
|
get_keyword_by_rule,
|
|
search_keywords,
|
|
)
|
|
|
|
|
|
class KeywordValidationError(Exception):
|
|
"""Raised when a keyword usage violates Magic: The Gathering rules."""
|
|
def __init__(self, message: str, keyword: str = None, rule: str = None):
|
|
super().__init__(message)
|
|
self.keyword = keyword
|
|
self.rule = rule
|
|
|
|
|
|
class KeywordValidator:
|
|
"""
|
|
Validates keyword usage in card text and game actions.
|
|
|
|
This validator ensures:
|
|
1. Keywords are valid MTG keywords
|
|
2. Keywords are used in appropriate contexts (actions vs abilities)
|
|
3. Keyword variants are properly recognized
|
|
4. Ability words are distinguished from keyword abilities
|
|
"""
|
|
|
|
def __init__(self):
|
|
self._all_keywords = get_all_keywords()
|
|
|
|
def validate_keyword(self, keyword: str) -> dict:
|
|
"""
|
|
Validate a keyword and return its metadata.
|
|
|
|
Args:
|
|
keyword: The keyword to validate.
|
|
|
|
Returns:
|
|
Dictionary with keyword metadata.
|
|
|
|
Raises:
|
|
KeywordValidationError: If the keyword is not recognized.
|
|
"""
|
|
definition = get_keyword_definition(keyword)
|
|
|
|
if definition is None:
|
|
raise KeywordValidationError(
|
|
f"Unknown keyword: '{keyword}'. "
|
|
f"Valid keywords: {len(self._all_keywords)} total.",
|
|
keyword=keyword,
|
|
)
|
|
|
|
return definition
|
|
|
|
def validate_keyword_in_context(self, keyword: str, context: str) -> str:
|
|
"""
|
|
Validate a keyword in a specific context (action or ability).
|
|
|
|
Args:
|
|
keyword: The keyword to validate.
|
|
context: The context ('action' or 'ability').
|
|
|
|
Returns:
|
|
A validation message.
|
|
|
|
Raises:
|
|
KeywordValidationError: If the keyword is invalid in context.
|
|
"""
|
|
definition = get_keyword_definition(keyword)
|
|
|
|
if definition is None:
|
|
raise KeywordValidationError(
|
|
f"Unknown keyword: '{keyword}'.",
|
|
keyword=keyword,
|
|
)
|
|
|
|
if context == "action" and definition["type"] == "keyword_ability":
|
|
raise KeywordValidationError(
|
|
f"Keyword '{keyword}' is a keyword ability, not a keyword action. "
|
|
f"Rule reference: {definition['rule']}",
|
|
keyword=keyword,
|
|
rule=definition["rule"],
|
|
)
|
|
|
|
if context == "ability" and definition["type"] == "keyword_action":
|
|
raise KeywordValidationError(
|
|
f"Keyword '{keyword}' is a keyword action, not a keyword ability. "
|
|
f"Rule reference: {definition['rule']}",
|
|
keyword=keyword,
|
|
rule=definition["rule"],
|
|
)
|
|
|
|
return f"Valid keyword: '{keyword}' ({definition['type']})"
|
|
|
|
def validate_card_text(self, text: str) -> list[dict]:
|
|
"""
|
|
Validate keyword usage in card text.
|
|
|
|
Args:
|
|
text: The card text to validate.
|
|
|
|
Returns:
|
|
List of validation results for each keyword found.
|
|
"""
|
|
keywords_found = []
|
|
results = []
|
|
|
|
# Extract keywords from text (simple word-based matching)
|
|
for kw in self._all_keywords:
|
|
# Check for exact matches (case-insensitive)
|
|
if kw.lower() in text.lower():
|
|
definition = get_keyword_definition(kw)
|
|
if definition:
|
|
keywords_found.append(kw)
|
|
results.append({
|
|
"keyword": kw,
|
|
"type": definition["type"],
|
|
"rule": definition["rule"],
|
|
"valid": True,
|
|
})
|
|
|
|
return results
|
|
|
|
def validate_action(self, action: str) -> bool:
|
|
"""
|
|
Check if a string is a valid keyword action.
|
|
|
|
Args:
|
|
action: The action to validate.
|
|
|
|
Returns:
|
|
True if valid, False otherwise.
|
|
"""
|
|
return action.lower() in [kw.lower() for kw in KEYWORD_ACTIONS]
|
|
|
|
def validate_ability(self, ability: str) -> bool:
|
|
"""
|
|
Check if a string is a valid keyword ability.
|
|
|
|
Args:
|
|
ability: The ability to validate.
|
|
|
|
Returns:
|
|
True if valid, False otherwise.
|
|
"""
|
|
return ability.lower() in [kw.lower() for kw in KEYWORD_ABILITIES]
|
|
|
|
def is_evasion_ability(self, ability: str) -> bool:
|
|
"""
|
|
Check if an ability is an evasion ability.
|
|
|
|
Args:
|
|
ability: The ability to check.
|
|
|
|
Returns:
|
|
True if the ability is an evasion ability.
|
|
"""
|
|
definition = get_keyword_definition(ability)
|
|
if definition and definition["ability_type"] == "evasion":
|
|
return True
|
|
return False
|
|
|
|
def get_variant_base(self, variant: str) -> str | None:
|
|
"""
|
|
Get the base keyword for a variant.
|
|
|
|
Args:
|
|
variant: The variant keyword.
|
|
|
|
Returns:
|
|
The base keyword or None if not a variant.
|
|
"""
|
|
return KEYWORD_VARIANTS.get(variant.lower(), None)
|
|
|
|
|
|
def validate_card_keywords(card_text: str) -> list[dict]:
|
|
"""
|
|
Validate all keywords found in a card's text.
|
|
|
|
Args:
|
|
card_text: The full text of the card.
|
|
|
|
Returns:
|
|
List of validation results.
|
|
"""
|
|
validator = KeywordValidator()
|
|
return validator.validate_card_text(card_text)
|
|
|
|
|
|
def is_valid_keyword(keyword: str) -> bool:
|
|
"""
|
|
Quick check if a keyword is valid.
|
|
|
|
Args:
|
|
keyword: The keyword to check.
|
|
|
|
Returns:
|
|
True if the keyword is valid.
|
|
"""
|
|
return get_keyword_definition(keyword) is not None
|
|
|
|
|
|
def get_keyword_info(keyword: str) -> dict | None:
|
|
"""
|
|
Get detailed information about a keyword.
|
|
|
|
Args:
|
|
keyword: The keyword to look up.
|
|
|
|
Returns:
|
|
Dictionary with keyword information or None.
|
|
"""
|
|
return get_keyword_definition(keyword)
|