Move enums to app/core/enums.py and set up clean module exports
Architectural refactor to eliminate circular imports and establish clean module boundaries: - Move enums from app/core/models/enums.py to app/core/enums.py (foundational module with zero dependencies) - Update all imports across 30 files to use new enum location - Set up clean export structure: - app.core.enums: canonical source for all enums - app.core: convenience exports for full public API - app.core.models: exports models only (not enums) - Add module exports to app/core/__init__.py and app/core/effects/__init__.py - Remove circular import workarounds from game_state.py This enables app.core.models to export GameState without circular import issues, since enums no longer depend on the models package. All 826 tests passing.
This commit is contained in:
parent
c3623d9541
commit
e7431e2d1f
@ -2,13 +2,13 @@
|
||||
"meta": {
|
||||
"version": "1.0.0",
|
||||
"created": "2026-01-24",
|
||||
"lastUpdated": "2026-01-25",
|
||||
"lastUpdated": "2026-01-26",
|
||||
"planType": "feature",
|
||||
"projectName": "Mantimon TCG - Backend Game Engine",
|
||||
"description": "Core game engine scaffolding for a highly configurable Pokemon TCG-inspired card game. The engine must support campaign mode with fixed rules and free play mode with user-configurable rules.",
|
||||
"totalEstimatedHours": 48,
|
||||
"totalTasks": 32,
|
||||
"completedTasks": 29
|
||||
"completedTasks": 30
|
||||
},
|
||||
"categories": {
|
||||
"critical": "Foundation components that block all other work",
|
||||
@ -23,10 +23,12 @@
|
||||
"cardRegistry": "Hybrid - definitions loaded from DB via CardService, embedded in GameState at game creation for self-contained gameplay",
|
||||
"cardModels": "Separate CardDefinition (immutable template) from CardInstance (mutable in-game state)",
|
||||
"actionModeling": "Union types for type safety",
|
||||
"asyncSupport": "Async throughout for WebSocket compatibility"
|
||||
"asyncSupport": "Async throughout for WebSocket compatibility",
|
||||
"enumsLocation": "Enums in app/core/enums.py (foundational module with zero dependencies) - breaks circular imports and enables clean re-exports"
|
||||
},
|
||||
"directoryStructure": {
|
||||
"core": "backend/app/core/",
|
||||
"enums": "backend/app/core/enums.py",
|
||||
"models": "backend/app/core/models/",
|
||||
"effects": "backend/app/core/effects/",
|
||||
"tests": "backend/tests/core/"
|
||||
@ -536,21 +538,22 @@
|
||||
"description": "Set up clean public API exports in __init__.py files",
|
||||
"category": "medium",
|
||||
"priority": 30,
|
||||
"completed": false,
|
||||
"tested": false,
|
||||
"completed": true,
|
||||
"tested": true,
|
||||
"dependencies": ["HIGH-009"],
|
||||
"files": [
|
||||
{"path": "app/core/__init__.py", "issue": "Needs public API exports"},
|
||||
{"path": "app/core/models/__init__.py", "issue": "Needs model exports"},
|
||||
{"path": "app/core/effects/__init__.py", "issue": "Needs effect exports"}
|
||||
{"path": "app/core/__init__.py", "status": "updated"},
|
||||
{"path": "app/core/models/__init__.py", "status": "updated"},
|
||||
{"path": "app/core/effects/__init__.py", "status": "updated"}
|
||||
],
|
||||
"suggestedFix": "Export key classes: GameEngine, RulesConfig, GameState, CardDefinition, CardInstance, Action types, effect_handler decorator",
|
||||
"estimatedHours": 0.5,
|
||||
"notes": "Clean API surface for consumers of the core module"
|
||||
"notes": "Clean API surface for consumers of the core module. Exports: 34 items from core, 29 from models, 12 from effects. 14 effect handlers auto-registered.",
|
||||
"completedDate": "2026-01-26"
|
||||
},
|
||||
{
|
||||
"id": "DOCS-001",
|
||||
"name": "Create core module CLAUDE.md",
|
||||
"name": "Create core module AGENTS.md",
|
||||
"description": "Document the game engine architecture, patterns, and usage guidelines for AI agents",
|
||||
"category": "low",
|
||||
"priority": 31,
|
||||
@ -558,11 +561,11 @@
|
||||
"tested": false,
|
||||
"dependencies": ["HIGH-009"],
|
||||
"files": [
|
||||
{"path": "app/core/CLAUDE.md", "issue": "File does not exist"}
|
||||
{"path": "app/core/AGENTS.md", "issue": "File does not exist"}
|
||||
],
|
||||
"suggestedFix": "Document: module structure, key classes, effect handler pattern, configuration system, testing approach, security considerations (hidden info)",
|
||||
"estimatedHours": 1,
|
||||
"notes": "Reference doc as specified in CLAUDE.md"
|
||||
"notes": "Reference doc as specified in AGENTS.md"
|
||||
},
|
||||
{
|
||||
"id": "LOW-001",
|
||||
@ -654,7 +657,7 @@
|
||||
"estimatedHours": 14,
|
||||
"goals": ["GameEngine complete", "Full integration tested", "Documentation complete"],
|
||||
"status": "IN_PROGRESS",
|
||||
"progress": "HIGH-008, TEST-012, HIGH-009, TEST-013 complete. 711 tests passing. Remaining: MED-004 (module exports), DOCS-001 (documentation), LOW-001 (docstrings)."
|
||||
"progress": "HIGH-008, TEST-012, HIGH-009, TEST-013, MED-004 complete. Enums moved to app/core/enums.py (architectural improvement to eliminate circular imports). 826 tests passing. Remaining: DOCS-001 (documentation), LOW-001 (docstrings)."
|
||||
}
|
||||
},
|
||||
"testingStrategy": {
|
||||
|
||||
@ -14,4 +14,141 @@ Key Components:
|
||||
- win_conditions: Win/loss detection
|
||||
- visibility: Hidden information filtering for clients
|
||||
- rng: Random number generation with testable seeded implementation
|
||||
|
||||
Quick Start:
|
||||
from app.core import GameEngine, RulesConfig, create_rng
|
||||
|
||||
# Create engine with rules and RNG
|
||||
engine = GameEngine(rules=RulesConfig(), rng=create_rng())
|
||||
|
||||
# Create a game
|
||||
game = engine.create_game(
|
||||
player_ids=["player1", "player2"],
|
||||
decks={"player1": deck1, "player2": deck2},
|
||||
card_registry=registry,
|
||||
)
|
||||
|
||||
# Execute actions
|
||||
result = await engine.execute_action(game, "player1", action)
|
||||
|
||||
# Get client-safe view
|
||||
visible = engine.get_visible_state(game, "player1")
|
||||
"""
|
||||
|
||||
# Enums (foundational, no dependencies)
|
||||
# Configuration
|
||||
from app.core.config import (
|
||||
ActiveConfig,
|
||||
BenchConfig,
|
||||
CombatConfig,
|
||||
DeckConfig,
|
||||
EnergyConfig,
|
||||
EvolutionConfig,
|
||||
FirstTurnConfig,
|
||||
PrizeConfig,
|
||||
RetreatConfig,
|
||||
RulesConfig,
|
||||
StatusConfig,
|
||||
TrainerConfig,
|
||||
WinConditionsConfig,
|
||||
)
|
||||
|
||||
# Engine
|
||||
from app.core.engine import ActionResult, GameEngine
|
||||
from app.core.enums import (
|
||||
ActionType,
|
||||
CardType,
|
||||
EnergyType,
|
||||
GameEndReason,
|
||||
ModifierMode,
|
||||
PokemonStage,
|
||||
PokemonVariant,
|
||||
StatusCondition,
|
||||
TrainerType,
|
||||
TurnPhase,
|
||||
)
|
||||
|
||||
# Game state models (imported after config to avoid circular imports)
|
||||
from app.core.models.game_state import (
|
||||
ForcedAction,
|
||||
GameState,
|
||||
PlayerState,
|
||||
Zone,
|
||||
)
|
||||
|
||||
# RNG
|
||||
from app.core.rng import RandomProvider, SecureRandom, SeededRandom, create_rng
|
||||
|
||||
# Validation
|
||||
from app.core.rules_validator import ValidationResult, validate_action
|
||||
|
||||
# Turn management
|
||||
from app.core.turn_manager import TurnManager, TurnStartResult
|
||||
|
||||
# Visibility (for service layer)
|
||||
from app.core.visibility import (
|
||||
VisibleGameState,
|
||||
VisiblePlayerState,
|
||||
VisibleZone,
|
||||
get_spectator_state,
|
||||
get_visible_state,
|
||||
)
|
||||
|
||||
# Win conditions
|
||||
from app.core.win_conditions import WinResult, check_win_conditions
|
||||
|
||||
__all__ = [
|
||||
# Enums
|
||||
"ActionType",
|
||||
"CardType",
|
||||
"EnergyType",
|
||||
"GameEndReason",
|
||||
"ModifierMode",
|
||||
"PokemonStage",
|
||||
"PokemonVariant",
|
||||
"StatusCondition",
|
||||
"TrainerType",
|
||||
"TurnPhase",
|
||||
# Configuration
|
||||
"RulesConfig",
|
||||
"DeckConfig",
|
||||
"ActiveConfig",
|
||||
"BenchConfig",
|
||||
"EnergyConfig",
|
||||
"PrizeConfig",
|
||||
"FirstTurnConfig",
|
||||
"WinConditionsConfig",
|
||||
"StatusConfig",
|
||||
"TrainerConfig",
|
||||
"EvolutionConfig",
|
||||
"RetreatConfig",
|
||||
"CombatConfig",
|
||||
# RNG
|
||||
"RandomProvider",
|
||||
"SeededRandom",
|
||||
"SecureRandom",
|
||||
"create_rng",
|
||||
# Engine
|
||||
"GameEngine",
|
||||
"ActionResult",
|
||||
# Validation
|
||||
"ValidationResult",
|
||||
"validate_action",
|
||||
# Win conditions
|
||||
"WinResult",
|
||||
"check_win_conditions",
|
||||
# Turn management
|
||||
"TurnManager",
|
||||
"TurnStartResult",
|
||||
# Visibility
|
||||
"VisibleGameState",
|
||||
"VisiblePlayerState",
|
||||
"VisibleZone",
|
||||
"get_visible_state",
|
||||
"get_spectator_state",
|
||||
# Game state models
|
||||
"ForcedAction",
|
||||
"GameState",
|
||||
"PlayerState",
|
||||
"Zone",
|
||||
]
|
||||
|
||||
@ -24,7 +24,7 @@ Usage:
|
||||
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
from app.core.models.enums import EnergyType, ModifierMode, PokemonVariant
|
||||
from app.core.enums import EnergyType, ModifierMode, PokemonVariant
|
||||
|
||||
|
||||
class DeckConfig(BaseModel):
|
||||
|
||||
@ -8,4 +8,47 @@ Key Components:
|
||||
- base: EffectContext and EffectResult types
|
||||
- registry: Effect handler registration and lookup
|
||||
- handlers: Built-in effect handlers (deal_damage, heal, etc.)
|
||||
|
||||
Usage:
|
||||
from app.core.effects import effect_handler, resolve_effect, EffectContext, EffectResult
|
||||
|
||||
@effect_handler("custom_effect")
|
||||
def handle_custom(ctx: EffectContext) -> EffectResult:
|
||||
# Effect implementation
|
||||
return EffectResult.success("Effect applied")
|
||||
|
||||
# Resolve an effect by ID
|
||||
result = resolve_effect("deal_damage", context)
|
||||
"""
|
||||
|
||||
# Import handlers to register them
|
||||
from app.core.effects import handlers as _handlers # noqa: F401
|
||||
from app.core.effects.base import EffectContext, EffectResult, EffectType
|
||||
from app.core.effects.registry import (
|
||||
EffectHandler,
|
||||
clear_registry,
|
||||
effect_handler,
|
||||
get_handler,
|
||||
is_registered,
|
||||
list_effects,
|
||||
register_handler,
|
||||
resolve_effect,
|
||||
unregister_handler,
|
||||
)
|
||||
|
||||
__all__ = [
|
||||
# Base types
|
||||
"EffectContext",
|
||||
"EffectResult",
|
||||
"EffectType",
|
||||
# Registry
|
||||
"EffectHandler",
|
||||
"effect_handler",
|
||||
"resolve_effect",
|
||||
"list_effects",
|
||||
"get_handler",
|
||||
"is_registered",
|
||||
"register_handler",
|
||||
"unregister_handler",
|
||||
"clear_registry",
|
||||
]
|
||||
|
||||
@ -38,7 +38,7 @@ Available Effects:
|
||||
|
||||
from app.core.effects.base import EffectContext, EffectResult, EffectType
|
||||
from app.core.effects.registry import effect_handler
|
||||
from app.core.models.enums import ModifierMode, StatusCondition
|
||||
from app.core.enums import ModifierMode, StatusCondition
|
||||
|
||||
|
||||
@effect_handler("deal_damage")
|
||||
|
||||
@ -41,6 +41,7 @@ from typing import Any
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
from app.core.config import RulesConfig
|
||||
from app.core.enums import GameEndReason, StatusCondition, TurnPhase
|
||||
from app.core.models.actions import (
|
||||
Action,
|
||||
AttachEnergyAction,
|
||||
@ -56,7 +57,6 @@ from app.core.models.actions import (
|
||||
UseAbilityAction,
|
||||
)
|
||||
from app.core.models.card import CardDefinition, CardInstance
|
||||
from app.core.models.enums import GameEndReason, StatusCondition, TurnPhase
|
||||
from app.core.models.game_state import GameState, PlayerState
|
||||
from app.core.rng import RandomProvider, create_rng
|
||||
from app.core.rules_validator import ValidationResult, validate_action
|
||||
@ -623,7 +623,7 @@ class GameEngine:
|
||||
|
||||
# Update per-turn counters
|
||||
if card_def.trainer_type:
|
||||
from app.core.models.enums import TrainerType
|
||||
from app.core.enums import TrainerType
|
||||
|
||||
if card_def.trainer_type == TrainerType.SUPPORTER:
|
||||
player.supporters_played_this_turn += 1
|
||||
@ -837,7 +837,7 @@ class GameEngine:
|
||||
player.active.add(new_active)
|
||||
|
||||
# Clear status conditions (retreat clears confusion)
|
||||
from app.core.models.enums import StatusCondition
|
||||
from app.core.enums import StatusCondition
|
||||
|
||||
active.remove_status(StatusCondition.CONFUSED)
|
||||
|
||||
|
||||
@ -3,6 +3,9 @@
|
||||
This module defines all enum types used throughout the game engine. We use StrEnum
|
||||
for JSON serialization compatibility - enum values serialize as strings directly.
|
||||
|
||||
This is the foundational module with zero internal dependencies, allowing other
|
||||
core modules to import from it without circular import concerns.
|
||||
|
||||
Note on extensibility: While these enums define the standard types, the game engine
|
||||
is designed to be configurable. Custom energy types or card types could be added
|
||||
via configuration for free play mode.
|
||||
@ -199,3 +202,17 @@ class ModifierMode(StrEnum):
|
||||
|
||||
MULTIPLICATIVE = "multiplicative"
|
||||
ADDITIVE = "additive"
|
||||
|
||||
|
||||
__all__ = [
|
||||
"ActionType",
|
||||
"CardType",
|
||||
"EnergyType",
|
||||
"GameEndReason",
|
||||
"ModifierMode",
|
||||
"PokemonStage",
|
||||
"PokemonVariant",
|
||||
"StatusCondition",
|
||||
"TrainerType",
|
||||
"TurnPhase",
|
||||
]
|
||||
@ -1,20 +1,20 @@
|
||||
"""Core data models for the Mantimon TCG game engine.
|
||||
|
||||
This module contains all Pydantic models used throughout the game engine:
|
||||
- enums: Enumeration types (CardType, EnergyType, TurnPhase, etc.)
|
||||
- card: CardDefinition (template) and CardInstance (in-game state)
|
||||
- actions: Player action types as a discriminated union
|
||||
- game_state: GameState, PlayerState, and Zone models
|
||||
This module exports Pydantic models for cards, game state, and actions.
|
||||
|
||||
Note: To avoid circular imports, game_state is not imported at module level.
|
||||
Import directly from app.core.models.game_state when needed:
|
||||
For enums, import from app.core.enums or app.core:
|
||||
from app.core.enums import CardType, EnergyType, TurnPhase
|
||||
from app.core import CardType, EnergyType # convenience
|
||||
|
||||
from app.core.models.game_state import GameState, PlayerState, Zone
|
||||
|
||||
Or import after config is already loaded:
|
||||
|
||||
from app.core.models import enums, card, actions
|
||||
from app.core.models import game_state # Import after other modules
|
||||
Usage:
|
||||
from app.core.models import (
|
||||
# Card models
|
||||
CardDefinition, CardInstance, Attack, Ability,
|
||||
# Game state
|
||||
GameState, PlayerState, Zone, ForcedAction,
|
||||
# Actions
|
||||
Action, AttackAction, PlayPokemonAction, parse_action,
|
||||
)
|
||||
"""
|
||||
|
||||
from app.core.models.actions import (
|
||||
@ -40,38 +40,25 @@ from app.core.models.card import (
|
||||
CardInstance,
|
||||
WeaknessResistance,
|
||||
)
|
||||
from app.core.models.enums import (
|
||||
ActionType,
|
||||
CardType,
|
||||
EnergyType,
|
||||
GameEndReason,
|
||||
PokemonStage,
|
||||
PokemonVariant,
|
||||
StatusCondition,
|
||||
TrainerType,
|
||||
TurnPhase,
|
||||
from app.core.models.game_state import (
|
||||
ForcedAction,
|
||||
GameState,
|
||||
PlayerState,
|
||||
Zone,
|
||||
)
|
||||
|
||||
# Note: GameState, PlayerState, Zone are imported from game_state module directly
|
||||
# to avoid circular imports with app.core.config
|
||||
|
||||
__all__ = [
|
||||
# Enums
|
||||
"ActionType",
|
||||
"CardType",
|
||||
"EnergyType",
|
||||
"GameEndReason",
|
||||
"PokemonStage",
|
||||
"PokemonVariant",
|
||||
"StatusCondition",
|
||||
"TrainerType",
|
||||
"TurnPhase",
|
||||
# Card models
|
||||
"Ability",
|
||||
"Attack",
|
||||
"CardDefinition",
|
||||
"CardInstance",
|
||||
"WeaknessResistance",
|
||||
# Game state models
|
||||
"ForcedAction",
|
||||
"GameState",
|
||||
"PlayerState",
|
||||
"Zone",
|
||||
# Action models
|
||||
"Action",
|
||||
"AttachEnergyAction",
|
||||
|
||||
@ -33,7 +33,7 @@ from typing import Any
|
||||
|
||||
from pydantic import BaseModel, Field, model_validator
|
||||
|
||||
from app.core.models.enums import (
|
||||
from app.core.enums import (
|
||||
CardType,
|
||||
EnergyType,
|
||||
ModifierMode,
|
||||
|
||||
@ -10,7 +10,8 @@ so that the game can be serialized/deserialized without external dependencies.
|
||||
This supports both live multiplayer and offline/standalone play.
|
||||
|
||||
Usage:
|
||||
# Create a new game
|
||||
from app.core.config import RulesConfig
|
||||
|
||||
game = GameState(
|
||||
game_id="match-123",
|
||||
rules=RulesConfig(),
|
||||
@ -32,8 +33,8 @@ from typing import Any
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
from app.core.config import RulesConfig
|
||||
from app.core.enums import GameEndReason, TurnPhase
|
||||
from app.core.models.card import CardDefinition, CardInstance
|
||||
from app.core.models.enums import GameEndReason, TurnPhase
|
||||
from app.core.rng import RandomProvider
|
||||
|
||||
|
||||
|
||||
@ -24,6 +24,12 @@ Example:
|
||||
|
||||
from pydantic import BaseModel
|
||||
|
||||
from app.core.enums import (
|
||||
EnergyType,
|
||||
StatusCondition,
|
||||
TrainerType,
|
||||
TurnPhase,
|
||||
)
|
||||
from app.core.models.actions import (
|
||||
VALID_PHASES_FOR_ACTION,
|
||||
Action,
|
||||
@ -40,12 +46,6 @@ from app.core.models.actions import (
|
||||
UseAbilityAction,
|
||||
)
|
||||
from app.core.models.card import CardDefinition, CardInstance
|
||||
from app.core.models.enums import (
|
||||
EnergyType,
|
||||
StatusCondition,
|
||||
TrainerType,
|
||||
TurnPhase,
|
||||
)
|
||||
from app.core.models.game_state import GameState, PlayerState, Zone
|
||||
|
||||
|
||||
|
||||
@ -49,7 +49,7 @@ from typing import TYPE_CHECKING
|
||||
|
||||
from pydantic import BaseModel
|
||||
|
||||
from app.core.models.enums import GameEndReason, StatusCondition, TurnPhase
|
||||
from app.core.enums import GameEndReason, StatusCondition, TurnPhase
|
||||
from app.core.win_conditions import WinResult, check_cannot_draw
|
||||
|
||||
if TYPE_CHECKING:
|
||||
|
||||
@ -37,8 +37,8 @@ from typing import TYPE_CHECKING
|
||||
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
from app.core.enums import GameEndReason, TurnPhase
|
||||
from app.core.models.card import CardDefinition, CardInstance
|
||||
from app.core.models.enums import GameEndReason, TurnPhase
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from app.core.models.game_state import GameState
|
||||
|
||||
@ -39,7 +39,7 @@ from typing import TYPE_CHECKING
|
||||
|
||||
from pydantic import BaseModel
|
||||
|
||||
from app.core.models.enums import GameEndReason
|
||||
from app.core.enums import GameEndReason
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from app.core.models.game_state import GameState
|
||||
|
||||
@ -46,19 +46,19 @@ from app.core.config import (
|
||||
)
|
||||
from app.core.effects.base import EffectContext
|
||||
from app.core.effects.registry import list_effects
|
||||
from app.core.models.card import (
|
||||
Attack,
|
||||
CardDefinition,
|
||||
CardInstance,
|
||||
WeaknessResistance,
|
||||
)
|
||||
from app.core.models.enums import (
|
||||
from app.core.enums import (
|
||||
CardType,
|
||||
EnergyType,
|
||||
PokemonStage,
|
||||
TrainerType,
|
||||
TurnPhase,
|
||||
)
|
||||
from app.core.models.card import (
|
||||
Attack,
|
||||
CardDefinition,
|
||||
CardInstance,
|
||||
WeaknessResistance,
|
||||
)
|
||||
from app.core.models.game_state import GameState, PlayerState
|
||||
from app.core.rng import SeededRandom
|
||||
|
||||
|
||||
@ -16,14 +16,7 @@ Usage:
|
||||
import pytest
|
||||
|
||||
from app.core.config import RulesConfig
|
||||
from app.core.models.card import (
|
||||
Ability,
|
||||
Attack,
|
||||
CardDefinition,
|
||||
CardInstance,
|
||||
WeaknessResistance,
|
||||
)
|
||||
from app.core.models.enums import (
|
||||
from app.core.enums import (
|
||||
CardType,
|
||||
EnergyType,
|
||||
PokemonStage,
|
||||
@ -31,6 +24,13 @@ from app.core.models.enums import (
|
||||
TrainerType,
|
||||
TurnPhase,
|
||||
)
|
||||
from app.core.models.card import (
|
||||
Ability,
|
||||
Attack,
|
||||
CardDefinition,
|
||||
CardInstance,
|
||||
WeaknessResistance,
|
||||
)
|
||||
from app.core.models.game_state import GameState, PlayerState
|
||||
from app.core.rng import SeededRandom
|
||||
|
||||
@ -937,7 +937,7 @@ def game_over_state(extended_card_registry, card_instance_factory) -> GameState:
|
||||
|
||||
- Player1 has won
|
||||
"""
|
||||
from app.core.models.enums import GameEndReason
|
||||
from app.core.enums import GameEndReason
|
||||
|
||||
player1 = PlayerState(player_id="player1")
|
||||
player2 = PlayerState(player_id="player2")
|
||||
|
||||
@ -23,7 +23,7 @@ from app.core.config import (
|
||||
TrainerConfig,
|
||||
WinConditionsConfig,
|
||||
)
|
||||
from app.core.models.enums import EnergyType, PokemonVariant
|
||||
from app.core.enums import EnergyType, PokemonVariant
|
||||
|
||||
|
||||
class TestDeckConfig:
|
||||
|
||||
@ -16,6 +16,7 @@ import pytest
|
||||
from app.core.config import RulesConfig
|
||||
from app.core.effects.base import EffectContext
|
||||
from app.core.effects.handlers import handle_attack_damage, handle_coin_flip_damage
|
||||
from app.core.enums import TurnPhase
|
||||
from app.core.models.actions import (
|
||||
AttackAction,
|
||||
PassAction,
|
||||
@ -24,7 +25,6 @@ from app.core.models.actions import (
|
||||
SelectPrizeAction,
|
||||
)
|
||||
from app.core.models.card import CardInstance
|
||||
from app.core.models.enums import TurnPhase
|
||||
from app.core.models.game_state import ForcedAction, GameState, PlayerState
|
||||
from app.core.rng import SeededRandom
|
||||
from app.core.rules_validator import validate_action
|
||||
|
||||
@ -10,8 +10,8 @@ These tests verify:
|
||||
|
||||
from app.core.config import RulesConfig
|
||||
from app.core.effects.base import EffectContext, EffectResult, EffectType
|
||||
from app.core.enums import CardType, EnergyType, PokemonStage
|
||||
from app.core.models.card import CardDefinition, CardInstance
|
||||
from app.core.models.enums import CardType, EnergyType, PokemonStage
|
||||
from app.core.models.game_state import GameState, PlayerState
|
||||
from app.core.rng import SeededRandom
|
||||
|
||||
|
||||
@ -16,8 +16,8 @@ import app.core.effects.handlers # noqa: F401
|
||||
from app.core.config import RulesConfig
|
||||
from app.core.effects.base import EffectContext, EffectType
|
||||
from app.core.effects.registry import resolve_effect
|
||||
from app.core.enums import CardType, EnergyType, PokemonStage, StatusCondition
|
||||
from app.core.models.card import CardDefinition, CardInstance, WeaknessResistance
|
||||
from app.core.models.enums import CardType, EnergyType, PokemonStage, StatusCondition
|
||||
from app.core.models.game_state import GameState, PlayerState
|
||||
from app.core.rng import SeededRandom
|
||||
|
||||
@ -549,7 +549,7 @@ class TestAttackDamage:
|
||||
Verify attack_damage uses additive weakness when configured in RulesConfig.
|
||||
"""
|
||||
from app.core.config import CombatConfig
|
||||
from app.core.models.enums import ModifierMode
|
||||
from app.core.enums import ModifierMode
|
||||
|
||||
# Configure game to use additive weakness (+20)
|
||||
game_state.rules.combat = CombatConfig(
|
||||
@ -593,7 +593,7 @@ class TestAttackDamage:
|
||||
This test verifies the mode switching works with integer values.
|
||||
"""
|
||||
from app.core.config import CombatConfig
|
||||
from app.core.models.enums import ModifierMode
|
||||
from app.core.enums import ModifierMode
|
||||
|
||||
# Configure game to use multiplicative resistance (x1 = no change)
|
||||
game_state.rules.combat = CombatConfig(
|
||||
@ -631,7 +631,7 @@ class TestAttackDamage:
|
||||
Verify a card can override the game's default weakness mode.
|
||||
Even if game uses multiplicative x2, card can specify additive +40.
|
||||
"""
|
||||
from app.core.models.enums import ModifierMode
|
||||
from app.core.enums import ModifierMode
|
||||
|
||||
# Game uses default multiplicative x2, but card overrides to additive +40
|
||||
game_state.card_registry["charmander-001"] = CardDefinition(
|
||||
|
||||
@ -22,8 +22,8 @@ from app.core.effects.registry import (
|
||||
resolve_effect,
|
||||
unregister_handler,
|
||||
)
|
||||
from app.core.enums import CardType, EnergyType, PokemonStage
|
||||
from app.core.models.card import CardDefinition, CardInstance
|
||||
from app.core.models.enums import CardType, EnergyType, PokemonStage
|
||||
from app.core.models.game_state import GameState, PlayerState
|
||||
from app.core.rng import SeededRandom
|
||||
|
||||
|
||||
@ -17,6 +17,16 @@ import pytest
|
||||
|
||||
from app.core.config import RulesConfig
|
||||
from app.core.engine import GameEngine
|
||||
from app.core.enums import (
|
||||
CardType,
|
||||
EnergyType,
|
||||
GameEndReason,
|
||||
PokemonStage,
|
||||
PokemonVariant,
|
||||
StatusCondition,
|
||||
TrainerType,
|
||||
TurnPhase,
|
||||
)
|
||||
from app.core.models.actions import (
|
||||
AttachEnergyAction,
|
||||
AttackAction,
|
||||
@ -30,16 +40,6 @@ from app.core.models.actions import (
|
||||
UseAbilityAction,
|
||||
)
|
||||
from app.core.models.card import Ability, Attack, CardDefinition, CardInstance
|
||||
from app.core.models.enums import (
|
||||
CardType,
|
||||
EnergyType,
|
||||
GameEndReason,
|
||||
PokemonStage,
|
||||
PokemonVariant,
|
||||
StatusCondition,
|
||||
TrainerType,
|
||||
TurnPhase,
|
||||
)
|
||||
from app.core.models.game_state import ForcedAction, GameState
|
||||
from app.core.rng import SeededRandom
|
||||
|
||||
|
||||
@ -24,9 +24,7 @@ from app.core.config import RulesConfig
|
||||
from app.core.effects.base import EffectContext
|
||||
from app.core.effects.registry import resolve_effect
|
||||
from app.core.engine import GameEngine
|
||||
from app.core.models.actions import EvolvePokemonAction
|
||||
from app.core.models.card import Attack, CardDefinition, CardInstance
|
||||
from app.core.models.enums import (
|
||||
from app.core.enums import (
|
||||
CardType,
|
||||
EnergyType,
|
||||
PokemonStage,
|
||||
@ -35,6 +33,8 @@ from app.core.models.enums import (
|
||||
TrainerType,
|
||||
TurnPhase,
|
||||
)
|
||||
from app.core.models.actions import EvolvePokemonAction
|
||||
from app.core.models.card import Attack, CardDefinition, CardInstance
|
||||
from app.core.models.game_state import GameState, PlayerState
|
||||
from app.core.rng import SeededRandom
|
||||
from app.core.turn_manager import TurnManager
|
||||
|
||||
@ -8,14 +8,7 @@ These tests verify:
|
||||
5. JSON serialization round-trips work
|
||||
"""
|
||||
|
||||
from app.core.models.card import (
|
||||
Ability,
|
||||
Attack,
|
||||
CardDefinition,
|
||||
CardInstance,
|
||||
WeaknessResistance,
|
||||
)
|
||||
from app.core.models.enums import (
|
||||
from app.core.enums import (
|
||||
CardType,
|
||||
EnergyType,
|
||||
PokemonStage,
|
||||
@ -23,6 +16,13 @@ from app.core.models.enums import (
|
||||
StatusCondition,
|
||||
TrainerType,
|
||||
)
|
||||
from app.core.models.card import (
|
||||
Ability,
|
||||
Attack,
|
||||
CardDefinition,
|
||||
CardInstance,
|
||||
WeaknessResistance,
|
||||
)
|
||||
|
||||
|
||||
class TestAttack:
|
||||
|
||||
@ -12,7 +12,7 @@ import json
|
||||
import pytest
|
||||
from pydantic import BaseModel
|
||||
|
||||
from app.core.models.enums import (
|
||||
from app.core.enums import (
|
||||
ActionType,
|
||||
CardType,
|
||||
EnergyType,
|
||||
|
||||
@ -8,8 +8,8 @@ These tests verify:
|
||||
"""
|
||||
|
||||
from app.core.config import RulesConfig
|
||||
from app.core.enums import CardType, EnergyType, GameEndReason, PokemonStage, TurnPhase
|
||||
from app.core.models.card import CardDefinition, CardInstance
|
||||
from app.core.models.enums import CardType, EnergyType, GameEndReason, PokemonStage, TurnPhase
|
||||
from app.core.models.game_state import GameState, PlayerState, Zone
|
||||
from app.core.rng import SeededRandom
|
||||
|
||||
|
||||
@ -15,6 +15,10 @@ from app.core.config import (
|
||||
RetreatConfig,
|
||||
TrainerConfig,
|
||||
)
|
||||
from app.core.enums import (
|
||||
StatusCondition,
|
||||
TurnPhase,
|
||||
)
|
||||
from app.core.models.actions import (
|
||||
AttachEnergyAction,
|
||||
AttackAction,
|
||||
@ -29,10 +33,6 @@ from app.core.models.actions import (
|
||||
UseAbilityAction,
|
||||
)
|
||||
from app.core.models.card import CardInstance
|
||||
from app.core.models.enums import (
|
||||
StatusCondition,
|
||||
TurnPhase,
|
||||
)
|
||||
from app.core.models.game_state import ForcedAction, GameState
|
||||
from app.core.rules_validator import validate_action
|
||||
|
||||
|
||||
@ -16,8 +16,7 @@ import pytest
|
||||
from app.core.config import (
|
||||
RulesConfig,
|
||||
)
|
||||
from app.core.models.card import CardDefinition, CardInstance
|
||||
from app.core.models.enums import (
|
||||
from app.core.enums import (
|
||||
CardType,
|
||||
EnergyType,
|
||||
GameEndReason,
|
||||
@ -26,6 +25,7 @@ from app.core.models.enums import (
|
||||
StatusCondition,
|
||||
TurnPhase,
|
||||
)
|
||||
from app.core.models.card import CardDefinition, CardInstance
|
||||
from app.core.models.game_state import GameState, PlayerState
|
||||
from app.core.rng import SeededRandom
|
||||
from app.core.turn_manager import (
|
||||
@ -1497,7 +1497,7 @@ class TestPrizeCardModeKnockout:
|
||||
|
||||
EX/GX Pokemon are worth 2 prize cards.
|
||||
"""
|
||||
from app.core.models.enums import PokemonVariant
|
||||
from app.core.enums import PokemonVariant
|
||||
|
||||
# Add EX pokemon definition
|
||||
ex_def = CardDefinition(
|
||||
|
||||
@ -15,8 +15,7 @@ Test categories:
|
||||
import pytest
|
||||
|
||||
from app.core.config import RulesConfig
|
||||
from app.core.models.card import CardDefinition, CardInstance
|
||||
from app.core.models.enums import (
|
||||
from app.core.enums import (
|
||||
CardType,
|
||||
EnergyType,
|
||||
GameEndReason,
|
||||
@ -25,6 +24,7 @@ from app.core.models.enums import (
|
||||
TrainerType,
|
||||
TurnPhase,
|
||||
)
|
||||
from app.core.models.card import CardDefinition, CardInstance
|
||||
from app.core.models.game_state import ForcedAction, GameState, PlayerState
|
||||
from app.core.visibility import (
|
||||
VisibleGameState,
|
||||
|
||||
@ -16,7 +16,7 @@ Each test includes a docstring explaining the "what" and "why" of the test.
|
||||
import pytest
|
||||
|
||||
from app.core.config import PrizeConfig, RulesConfig, WinConditionsConfig
|
||||
from app.core.models.enums import GameEndReason, TurnPhase
|
||||
from app.core.enums import GameEndReason, TurnPhase
|
||||
from app.core.models.game_state import GameState, PlayerState
|
||||
from app.core.win_conditions import (
|
||||
WinResult,
|
||||
|
||||
Loading…
Reference in New Issue
Block a user