Files
scopone/docs/ARCHITECTURE.md
2026-04-02 20:16:27 +02:00

7.8 KiB

Architecture

Last Updated: 2026-04-02T18:12:18.000Z

Overview

Attribute Value
Primary language TypeScript
Secondary language Java (Capacitor Android shell)
Project type Browser card game with Android packaging
Framework Phaser 3.87.0
Tooling Vite 5, TypeScript 5.x, Capacitor 8.3
Runtime layout 1280 x 720, Phaser.Scale.FIT, centered in #game
Build command npm run build
Test command npx tsc --noEmit

The repository is a TypeScript-first Scopone Scientifico implementation. The web client contains the real game logic and presentation. The Android tree is a Capacitor wrapper with a custom immersive MainActivity.

Project Structure

scopone-phaser/
|- src/
|  |- main.ts
|  |- game/
|  |  |- types.ts
|  |  |- engine.ts
|  |  |- card-tracker.ts
|  |  `- ai.ts
|  `- scenes/
|     |- BootScene.ts
|     |- MenuScene.ts
|     `- GameScene.ts
|- public/
|- android/
|- docs/
|- prompts/
|- package.json
|- tsconfig.json
|- vite.config.ts
`- capacitor.config.ts

Key Directories

Directory Purpose
src/game/ Framework-independent rules, scoring, imperfect-information tracking, and AI search
src/scenes/ Phaser scene lifecycle, UI, animation, effects, and round orchestration
public/ Static web assets consumed by Phaser loaders
android/ Capacitor Android project, Gradle config, and immersive activity wrapper
docs/ Architecture, code style, findings, and cache metadata
prompts/ JIRA pipeline artifacts and iteration state

Design Patterns

No explicit GoF patterns were detected in the source or by semantic search.

Observed architectural patterns in the current codebase:

Pattern Where it appears
Scene-based flow BootScene -> MenuScene -> GameScene via Phaser scene registration
Functional core / imperative shell src/game/ stays free of Phaser imports, while src/scenes/ owns rendering and input
Clone-before-mutate state transitions applyMove() clones GameState before applying move effects
Determinization search Master AI samples hidden hands before alpha-beta evaluation
Callback-driven progress reporting chooseMove() reports AIDecisionProgress to GameScene for the think bar

Key Components

src/main.ts

  • Bootstraps Phaser.Game.
  • Registers BootScene, MenuScene, and GameScene.
  • Installs a one-shot fullscreen request handler on first user interaction.

src/game/types.ts

  • Defines the game model: Card, Capture, Player, GameState, TeamScore, ScoreBreakdown.
  • Encodes difficulty tiers as 'beginner' | 'advanced' | 'master'.
  • Stores the PRIMIERA_VALUES lookup table.

src/game/engine.ts (371 lines)

  • Builds and shuffles the 40-card deck.
  • Creates the initial round state for four players.
  • Implements capture selection rules: single direct matches take priority; subset sums are considered only when no direct match exists.
  • Applies moves immutably, detects scopas, assigns leftover table cards, and computes round scores.

src/game/card-tracker.ts (89 lines)

  • Tracks seen cards across a round without exposing hidden hands directly.
  • Computes unseen cards from played + myHand + table.
  • Supplies probability helpers used by the AI for value-based inference.

src/game/ai.ts (1210 lines)

  • Exposes chooseMove() as an async entry point.
  • Implements three difficulty levels:
    • beginner: noisy heuristic play.
    • advanced: stronger heuristics with race awareness, partner setup, and card-tracker inference.
    • master: determinization plus alpha-beta search with dynamic time budgets, batching, and progress callbacks.
  • Uses yieldToBrowser() between master-search batches so Phaser can repaint the think bar.

src/scenes/BootScene.ts (47 lines)

  • Loads the card atlas and card-back texture.
  • Shows a simple progress bar and transitions into the menu.

src/scenes/MenuScene.ts (103 lines)

  • Renders the title screen and rules summary.
  • Lets the player choose beginner, advanced, or master difficulty.
  • Starts GameScene with the selected difficulty in scene data.

src/scenes/GameScene.ts (1446 lines)

  • Owns the match loop, HUD, think bar, card interaction, animation, FX, audio, and round transitions.
  • Uses CardTracker to record played and captured cards after each move.
  • Bridges async AI progress into a visible top-of-screen think bar.
  • Handles end-of-round overlays and full-match restart flow.

android/app/src/main/java/com/phaser/scopa/MainActivity.java

  • Extends BridgeActivity.
  • Forces immersive mode by hiding status and navigation bars whenever the window gains focus.

Dependencies

JavaScript production dependencies

Package Version Purpose
phaser ^3.87.0 Game engine
@capacitor/core ^8.3.0 Capacitor runtime
@capacitor/cli ^8.3.0 Capacitor tooling
@capacitor/android ^8.3.0 Android platform integration

JavaScript development dependencies

Package Version Purpose
typescript ^5.0.0 Type-checking and TS compilation for builds
vite ^5.0.0 Dev server and bundling

Android / Gradle dependencies

Dependency Source Purpose
com.android.tools.build:gradle:8.13.0 android/build.gradle Android build plugin
com.google.gms:google-services:4.4.4 android/build.gradle Optional Google services integration
androidx.appcompat:appcompat android/app/build.gradle Android UI compatibility
androidx.coordinatorlayout:coordinatorlayout android/app/build.gradle Android layout support
androidx.core:core-splashscreen android/app/build.gradle Splash screen support
junit:junit android/app/build.gradle JVM-side Android tests
androidx.test.ext:junit android/app/build.gradle Instrumented Android testing
androidx.test.espresso:espresso-core android/app/build.gradle Android UI testing

Module Organization

main.ts
    -> BootScene
    -> MenuScene
    -> GameScene
             -> engine.ts
             -> ai.ts
             -> card-tracker.ts
             -> types.ts

Dependencies are one-directional at the application level:

  • src/game/ imports only from sibling game modules.
  • src/scenes/ imports from src/game/.
  • src/game/ never imports Phaser.

Data Flow

  1. main.ts creates the Phaser app and registers all scenes.
  2. BootScene loads assets, then starts MenuScene.
  3. MenuScene passes the chosen difficulty into GameScene.
  4. GameScene.create() initializes a new CardTracker, creates the initial GameState, and animates the opening deal.
  5. On each turn:
    • Human turns use click-driven selection and capture highlighting.
    • AI turns call chooseMove(state, playerIdx, difficulty, tracker, onProgress).
  6. chooseMove() either returns immediately for heuristic tiers or performs batched master search while reporting AIDecisionProgress.
  7. GameScene.executeMove() applies the move, updates the tracker, animates the result, refreshes the HUD, and advances the round.
  8. When all hands are empty, engine.ts finalizes scoring and GameScene displays the round summary or final match screen.

Build System

Command Source Purpose
npm run dev package.json Starts the Vite development server on port 3000 and opens the browser
npm run build user-provided build command Runs tsc && vite build and writes web output to dist/
npm run preview package.json Serves the built app locally via Vite preview
npx tsc --noEmit user-provided test command Type-checks the TypeScript codebase without emitting files