mantimon-tcg/backend/app/core
Cal Corum 934aa4c443 Add CardService and card data conversion pipeline
- Rename data/cards/ to data/raw/ for scraped data
- Add data/definitions/ as authoritative card data source
- Add convert_cards.py script to transform raw -> definitions
- Generate 378 card definitions (344 Pokemon, 24 Trainers, 10 Energy)
- Add CardService for loading and querying card definitions
  - In-memory indexes for fast lookups by type, set, pokemon_type
  - search() with multiple filter criteria
  - get_all_cards() for GameEngine integration
- Add SetInfo model for set metadata
- Update Attack model with damage_display field for variable damage
- Update CardDefinition with image_path, illustrator, flavor_text
- Add 45 tests (21 converter + 24 CardService)
- Update scraper output path to data/raw/

Card data is JSON-authoritative (no database) to support offline fork goal.
2026-01-27 14:16:40 -06:00
..
effects Add Active Effects system design and module README files 2026-01-26 22:39:02 -06:00
models Add CardService and card data conversion pipeline 2026-01-27 14:16:40 -06:00
__init__.py Move enums to app/core/enums.py and set up clean module exports 2026-01-26 14:45:26 -06:00
AGENTS.md Add core module AGENTS.md documentation (DOCS-001) 2026-01-26 14:50:52 -06:00
config.py Move enums to app/core/enums.py and set up clean module exports 2026-01-26 14:45:26 -06:00
engine.py Add weakness/resistance support to attack damage calculation 2026-01-26 16:04:41 -06:00
enums.py Move enums to app/core/enums.py and set up clean module exports 2026-01-26 14:45:26 -06:00
README.md Add Active Effects system design and module README files 2026-01-26 22:39:02 -06:00
rng.py Add game engine foundation: enums, config, and RNG modules 2026-01-24 22:14:45 -06:00
rules_validator.py Move enums to app/core/enums.py and set up clean module exports 2026-01-26 14:45:26 -06:00
turn_manager.py Move enums to app/core/enums.py and set up clean module exports 2026-01-26 14:45:26 -06:00
visibility.py Move enums to app/core/enums.py and set up clean module exports 2026-01-26 14:45:26 -06:00
win_conditions.py Move enums to app/core/enums.py and set up clean module exports 2026-01-26 14:45:26 -06:00

Core Game Engine Module

The app.core module contains the platform-independent game engine for Mantimon TCG. This module is designed to be completely decoupled from network and database concerns to enable both online multiplayer and a future offline/standalone version.

Architecture Principle

The core engine should remain forkable as a standalone offline game.

See ARCHITECTURE.md for details on this design goal.

Import Boundaries

# ALLOWED in app/core/
from app.core.models import CardDefinition, GameState
from app.core.config import RulesConfig
from app.core.rng import RandomProvider

# FORBIDDEN in app/core/
from app.services import CardService      # NO - DB dependency
from app.api.deps import get_current_user # NO - Auth dependency
from sqlalchemy import Session            # NO - DB dependency

Submodules

Directory/File Description
models/ Pydantic models for cards, game state, actions
effects/ Effect system for abilities and attacks
engine.py GameEngine - main orchestrator
config.py RulesConfig and sub-configs
turn_manager.py Turn/phase state machine
rules_validator.py Action validation
rng.py Random number generation
visibility.py Hidden information filtering
win_conditions.py Win/loss detection
enums.py Shared enumerations

Key Classes

GameEngine (engine.py)

The primary public API for all game operations.

from app.core import GameEngine, RulesConfig

engine = GameEngine(rules=RulesConfig())
result = engine.create_game(
    player_ids=["p1", "p2"],
    decks={"p1": deck1, "p2": deck2},
    card_registry=registry,
)
game = result.game

# Execute actions
action_result = await engine.execute_action(game, "p1", AttackAction(attack_index=0))

RulesConfig (config.py)

Configures all game rules - deck sizes, prize counts, per-turn limits, etc.

from app.core import RulesConfig

rules = RulesConfig(
    deck=DeckConfig(min_size=60, energy_deck_enabled=False),
    prizes=PrizeConfig(count=6),
)

GameState (models/game_state.py)

Complete state of a game in progress. Self-contained and serializable.

from app.core.models import GameState

# Access player zones
player = game.players["player1"]
active = player.get_active_pokemon()
hand_size = len(player.hand)

TurnManager (turn_manager.py)

Handles turn phases and transitions.

from app.core import TurnManager

manager = TurnManager()
manager.advance_phase(game)  # DRAW -> MAIN -> ATTACK -> END
manager.advance_turn(game)   # Switch to next player

RandomProvider (rng.py)

Protocol for random operations. Supports seeded RNG for testing.

from app.core import create_rng, SeededRandom

# Production: cryptographically secure
rng = create_rng()

# Testing: deterministic
rng = SeededRandom(seed=42)

Enumerations (enums.py)

Enum Description
CardType POKEMON, TRAINER, ENERGY
PokemonStage BASIC, STAGE_1, STAGE_2
EnergyType FIRE, WATER, GRASS, LIGHTNING, etc.
TrainerType ITEM, SUPPORTER, STADIUM, TOOL
StatusCondition POISONED, BURNED, ASLEEP, PARALYZED, CONFUSED
TurnPhase SETUP, DRAW, MAIN, ATTACK, END
GameEndReason PRIZES, DECK_OUT, NO_POKEMON, RESIGNATION, etc.
ModifierMode ADDITIVE, MULTIPLICATIVE

Action Types (models/actions.py)

Action Description
AttackAction Use an attack
AttachEnergyAction Attach energy to Pokemon
PlayPokemonAction Play Basic to bench/active
EvolvePokemonAction Evolve a Pokemon
PlayTrainerAction Play a Trainer card
UseAbilityAction Use a Pokemon's ability
RetreatAction Retreat active Pokemon
SelectActiveAction Choose new active (after KO)
PassAction End turn without attacking
ResignAction Forfeit the game

Visibility System (visibility.py)

Filters game state to hide information opponents shouldn't see.

from app.core import get_visible_state, get_spectator_state

# Player sees own hand, opponent sees card count
visible = get_visible_state(game, "player1")

# Spectator sees neither hand
spectator_view = get_spectator_state(game)

Effects System (effects/)

Handles card abilities and attack effects. See effects/README.md.

from app.core.effects import resolve_effect, EffectContext

result = resolve_effect("deal_damage", ctx)

Testing

cd backend && uv run pytest tests/core/ -v

All core module tests are in tests/core/ with ~800+ tests at 97% coverage.


See Also