Files
Ajedrez_Purgatorio/docs/architecture/architecture.md
T

14 KiB

status, source, date, verified-by
status source date verified-by
reverse-documented Assets/Game/Scripts/ 2026-08-16 Usuario

Arquitectura — Ajedrez Purgatorio

Nota: Este documento fue generado mediante /reverse-document a partir de la implementación existente. Captura el comportamiento actual del código y la intención de diseño aclarada con el usuario. Las secciones marcadas como INCOMPLETAS corresponden a partes cuya integración aún no está terminada.


1. Resumen Ejecutivo

Ajedrez Purgatorio es un juego de ajedrez clásico con campaña narrativa de 3 capítulos, piezas con identidad, sistema de Purgatorio (dados contra la Muerte) y sistemas meta (Dead Kings y guardado). Desarrollado en Unity 6 (6000.3.13f1) con URP 17.3.0.

Estado actual:

  • Código: 100% implementado en 5 sprints (Foundation, Chess+AI, Purgatorio, Narrative, Meta+Polish).
  • Escenas: MainMenu.unity y Chapter1.unity ensambladas en el editor (trabajo sin commitear).
  • Pendiente: Chapter2/3, cableado de GameStateManager/IA/Dead Kings UI, audio, tests.

2. Stack Tecnológico

Capa Tecnología
Engine Unity 6.3 (6000.3.13f1)
Render URP 17.3.0 (2D)
Lenguaje C# (.NET Standard 2.1)
Persistencia JSON (JsonUtility) en Application.persistentDataPath
Datos ScriptableObjects + JSON en Resources/ y Data/
Tests Unity Test Framework (Tests/)

3. Vista de Capas

La estructura se formaliza aquí como orgánica: creció a lo largo de los sprints y no fue una decisión deliberada de arquitectura. Sin embargo, el resultado es funcional y respeta razonablemente la separación presentación/lógica/datos.

Assets/Game/Scripts/
├── Mono/                        # Presentation + Logic (MonoBehaviours)
│   ├── Core/                    # Orquestadores y estado global
│   │   ├── GameManager.cs           # Motor de partida (reglas, turnos, eventos)
│   │   ├── BoardManager.cs          # Tablero runtime + SetupBoard(CampaignState)
│   │   ├── CampaignManager.cs       # Campaña (singleton DontDestroyOnLoad)
│   │   ├── DialogueSystem.cs        # Motor de diálogos (branching, JSON)
│   │   ├── GameStateManager.cs      # Máquina de estados global ⚠️ SIN CABLEAR
│   │   ├── PieceIdentityManager.cs  # Asigna identidades a piezas
│   │   ├── SceneTransitionManager.cs# Fades de transición
│   │   └── Services/                # Lógica POCO testable
│   │       ├── CheckDetector.cs     # Jaque / jaque mate
│   │       ├── DrawDetector.cs      # Tablas (50 movs, triple repetición, ahogado)
│   │       └── MoveValidator.cs     # Legalidad de movimientos
│   ├── Gameplay/                # Feedback visual (PieceSelectionFeedback)
│   ├── Pieces/                  # Piece + 6 tipos (King, Queen, Rook, Bishop, Knight, Pawn)
│   ├── AI/                      # AIController + IAIStrategy + Easy/Medium/Hard
│   ├── Purgatory/               # DiceSystem, PurgatoryManager + 3 UIs
│   ├── UI/                      # MainMenuController, GameHUD, PauseMenu, DialogueUI,
│   │                            # PromotionUI, PieceTooltip, DeadKingInput/Reveal
│   ├── Meta/                    # DeadKingPool, SaveSystem
│   ├── Audio/                   # AudioManager (SFX + música)
│   └── Data/                    # CampaignConfig, ChapterData, DialogueData
├── Data/                        # Modelos serializables (CampaignState, CampaignStats,
│                               # DeadKingData, SpeakerDatabase, BalanceConfig)
├── ScriptableObjects/           # PieceIdentity, AIPositionTables
└── Editor/                      # Herramientas de setup/reparación

Editor tools (Assets/Editor/ + Assets/Game/Scripts/Editor/):

  • ProjectSetup.cs — automatiza ensamblado ⚠️ referencia CameraFollow inexistente (no compila)
  • VerifySetup.cs — valida el cableado de escenas
  • FixErrors.cs — repara referencias rotas (p. ej. fade de transición)
  • FixDialogueLayout.cs — corrige layout de diálogos
  • PurgatorySetupValidator.cs — ventana Tools/Ajedrez Purgatorio

4. Patrones Dominantes

Cada patrón se documenta como mini-ADR con contexto, decisión y consecuencias.

4.1 Service Layer POCO — ADR-001

Contexto: GameManager concentraba 8 responsabilidades (~475 líneas) y era imposible de testear sin instanciar una escena Unity completa.

Decisión: Extraer la lógica a POCOs (CheckDetector, DrawDetector, MoveValidator) sin dependencia de MonoBehaviour, inyectados en GameManager.Awake(). MoveValidator depende de CheckDetector (dependency injection con validación null).

Razón confirmada: testabilidad — los servicios son 100% testeables sin Unity.

Consecuencias: GameManager redujo a 3 responsabilidades; la lógica es reutilizable por IA y futuros sistemas (hints, variantes de reglas).

Código: Assets/Game/Scripts/Mono/Core/Services/*.cs, GameManager.cs

4.2 Strategy Pattern — IA — ADR-002

Contexto: 3 dificultades de IA que deben poder escalarse por capítulo.

Decisión: Interfaz IAIStrategy con AIStrategyEasy (random con prioridad a capturas), AIStrategyMedium (1-ply evaluation) y AIStrategyHard (minimax alpha-beta depth 2, timeout 5s). AIController selecciona la estrategia.

Consecuencias: Extensible a nuevas dificultades sin tocar el controlador. ⚠️ INCOMPLETO: la selección de dificultad por capítulo desde CampaignManager está como TODO (S4-005) y AIController no está instanciado en ninguna escena.

4.3 Event-Driven — ADR-003

Contexto: UI y sistemas (Purgatorio, HUD) necesitan reaccionar a eventos del juego sin acoplamiento directo.

Decisión: Eventos Action<T> en GameManager (OnCheckmate, OnDraw, OnPieceMoved, OnTurnChanged, OnCheck). PurgatoryManager se suscribe a capturas; la UI escucha eventos.

Consecuencias: Desacople UI ↔ lógica. ⚠️ Faltan OnPieceCaptured y OnCheckResolved que GameHUD espera (suscripciones comentadas como TODO).

4.4 Singleton dual — ADR-004

Contexto: Managers globales accesibles desde cualquier script.

Decisión: Dos variantes:

  • MonoBehaviour con DontDestroyOnLoadCampaignManager, SaveSystem, AudioManager
  • ScriptableObject singleton — DeadKingPool (persistencia + configuración en un asset)

Consecuencias: Acceso global simple. El patrón singleton añade acoplamiento implícito, aceptado para el alcance del proyecto.

4.5 ScriptableObject como data container — ADR-005

Contexto: Datos de diseño (identidades de 16-20 piezas, tablas de posición IA, balance) que deben editarse sin recompilar.

Decisión: PieceIdentity, AIPositionTables, BalanceConfig, CampaignConfig como ScriptableObjects; CampaignState y DeadKingPool cargados desde Resources/.

Consecuencias: Data-driven y editable en editor. La serialización de CampaignState requiere capa JSON propia para Save/Load (limitación de JsonUtility con objetos anidados).

4.6 Overlay UI en lugar de escenas separadas — ADR-006

Contexto: El Purgatorio debe interrumpir la partida sin perder el contexto del tablero.

Decisión: El flujo del Purgatorio (oferta → dados → resultado) son Canvas overlay sobre la escena de juego, no escenas separadas.

Consecuencias: Mejor UX y menor overhead de carga. Requiere pausar/resumir gameplay.

4.7 Time.timeScale para pausas — ADR-007

Contexto: Promoción y Purgatorio necesitan pausar el juego.

Decisión: Time.timeScale = 0 con coroutines que usan WaitForSecondsRealtime.

Consecuencias: Simple y sin estado global adicional. Riesgo: cualquier coroutine con WaitForSeconds normal se congela.

4.8 Position hashing FEN-like — ADR-008

Contexto: Detección de repetición triple.

Decisión: Hash de posición tipo FEN-string en lugar de Zobrist hashing.

Consecuencias: Suficiente para el volumen de partidas del juego; no óptimo para rendimiento extremo (irrelevante aquí). La repetición se rastrea en DrawDetector.


5. Flujos Principales

5.1 Partida (ajedrez)

GameManager ──▶ BoardManager (tablero runtime)
    │                └── SquareClick (por casilla)
    ├──▶ MoveValidator (legalidad) → CheckDetector (jaque/mate) → DrawDetector (tablas)
    ├──▶ Turnos (OnTurnChanged) → GameHUD
    └──▶ IA: AIController → IAIStrategy (Easy/Medium/Hard)

5.2 Campaña

MainMenuController (Nueva Campaña / Continuar)
    → CampaignManager.LoadChapter(index)
        → BoardManager.SetupBoard(CampaignState)   // piezas vivas
        → DialogueSystem (intro de capítulo)
        → Spawn de Dead King (ShouldSpawnDeadKing + GetRandomDeadKing)
    → Victoria: OnChapterVictory → autosave (SaveSystem)
    → Derrota: DeadKingInputUI (inscribir Rey Muerto) → pool → menú

5.3 Purgatorio

Captura de pieza blanca (GameManager)
    → PurgatoryManager.OnPieceCaptured
    → PurgatoryOfferUI ("¿Desafiar a la Muerte?")
    → DiceRollUI (2d6 + modificadores) → DiceResultUI
    → Muerte gana = pieza se pierde; jugador gana = se salva
    → Límite: 3 visitas por tablero

5.4 Meta

Derrota → DeadKingInputUI → DeadKingPool.AddDeadKing (JSON, filtro profanity, FIFO 100)
Victoria → SaveSystem.SaveGame (3 slots, autosave)
Nueva partida → DeadKingPool.ShouldSpawnDeadKing(chapter) → Rey enemigo como Dead King

6. Escenas y Cableado Actual

Estado verificado contra el working tree (NO commiteado). Assets/Scenes/.

MainMenu.unity (en Build Settings)

GameObject Componentes Estado
GameController MainMenuController (_firstChapterSceneName: Chapter1) cableado
CampaignManager CampaignConfig + CampaignState cableado
SaveSystem 3 slots
AudioManager SFX/música clips ⚠️ todos null
SceneTransitionManager (Core) FadeCanvas + FadeImage cableado

Chapter1.unity (en Build Settings)

Sistema Estado
BoardManager todos los prefabs asignados (12 piezas, casillas, MoveIndicator)
GameManager _pieceTooltip, _promotionUI asignados
PurgatoryManager + DiceSystem _diceSystem, _campaignState, 3 UIs asignados
DialogueSystem _campaignState + 6 TextAssets
PieceIdentityManager _campaignState
CampaignManager
SceneTransitionManager (UI) ⚠️ sin referencias de fade (versión duplicada)
GameHUD ⚠️ _pauseButton, _capturedPieceIconPrefab null
DialogueUI ⚠️ _speakerPortrait, _speakerDatabase, _advanceDialogueAction null
PauseMenuController ⚠️ _canvasGroup null

Ausentes de escena (scripts existen)

  • GameStateManager — previsto, pendiente de cablear
  • AIController — IA no juega hasta instanciarlo
  • DeadKingInputUI / DeadKingRevealUI
  • Chapter2/3 scenes (no existen)

Build Settings

MainMenu + Chapter1 habilitadas. SampleScene.unity huérfana (no referenciada).


7. Problemas Conocidos

  1. SceneTransitionManager duplicadoCore/SceneTransitionManager.cs (usado en MainMenu) y UI/SceneTransitionManager.cs (usado en Chapter1, sin fade). Decisión: consolidar en una sola clase; FixErrors.cs asume campos que solo existen en la versión Core.
  2. ProjectSetup.cs no compila — referencia CameraFollow, clase inexistente en el repo.
  3. Objetos basura en Chapter1 — GameObject suelto con SquareClick fuera del tablero (-43.98, -0.72); GameManager/board en posiciones extrañas (34, 30); BoardParent vacío.
  4. Audio mudo — AudioManager sin clips en ambas escenas.
  5. GameHUD incompleto — sin botón de pausa conectado ni iconos de capturadas.
  6. SaveSystem restore parcialTotalPiecesLost/LastChapterWasVictory no se restauran (props read-only en CampaignState).

8. Integraciones Pendientes

  • Cablear GameStateManager en escenas (transiciones de estado protegidas con null-check hoy)
  • Instanciar AIController y aplicar dificultad por capítulo (TODO S4-005)
  • Conectar DeadKingRevealUI/DeadKingInputUI al flujo de campaña (TODO en CampaignManager)
  • Añadir eventos OnPieceCaptured/OnCheckResolved a GameManager y suscribir GameHUD
  • Completar stats en DeadKingInputUI.GatherCampaignStats()
  • Restore completo de SaveSystem
  • BalanceConfig.LoadFromJSON() real (hoy placeholder con valores default)
  • Asignar AudioClips y referencias de UI faltantes (GameHUD, DialogueUI, PauseMenu)
  • Crear Chapter2/3 scenes y agregarlas a Build Settings

9. Estado de Testing

  • Tests/Unit/Campaign/CampaignStateTests.cs (18 tests)
  • Tests/Unit/Dialogue/DialogueSystemBranchingTests.cs (17 tests)
  • Tests/Unit/Meta/DeadKingPoolTests.cs (17 tests)
  • Pendientes: SaveSystem, servicios POCO (CheckDetector/DrawDetector/MoveValidator), integración
  • Sin test plan de Sprint 5 ni playtest documentado

10. Follow-Up Work

Inmediato:

  • Consolidar SceneTransitionManager (eliminar duplicado UI/)
  • Reparar ProjectSetup.cs (CameraFollow inexistente)
  • Commit del trabajo sin commitear (escenas, prefabs, editor tools, assets movidos)
  • Actualizar PROJECT_STATUS.md/roadmap.md (estado real: escenas ya existen)

Corto plazo:

  • Cablear GameStateManager + AIController en escenas
  • Escribir tests de SaveSystem y servicios POCO
  • Crear Chapter2/3 y playtest completo documentado

Largo plazo:

  • Generar ADRs formales (ADR-001..008 aquí son el borrador base)
  • Llenar docs/architecture/tr-registry.yaml con TR-IDs por sistema
  • Control Manifest a partir de ADRs aceptados

Referencias

Código principal: Assets/Game/Scripts/Mono/ (GameManager, CampaignManager, BoardManager), Assets/Game/Scripts/Mono/Core/Services/, Assets/Game/Scripts/Mono/Purgatory/, Meta/.

Documentos de diseño: design/gdd/ (game-concept, systems-index, dice-system, ai-system, dialogue-system, dead-kings, piece-identity, campaign-system), design/ux/.

GDDs y registro: design/registry/entities.yaml, docs/registry/architecture.yaml.