Files
scopone/docs/ARCHITECTURE.md
2026-04-08 21:50:40 +02:00

9.3 KiB

Architecture

Last Updated: 2026-04-08T19:48:08.000Z

Overview

Attribute Value
Primary language TypeScript
Secondary language Java
Project type Phaser browser game packaged for Android with Capacitor
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 implementation of Scopone Scientifico. Gameplay rules, scoring, inference, and AI live in framework-independent modules under src/game/. Phaser scenes under src/scenes/ own rendering, input, UI, animation, and scene transitions. The android/ tree is a Capacitor wrapper with a small custom MainActivity for immersive full-screen behavior.

Project Structure

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

Key Directories

Directory Purpose
src/game/ Rules engine, score calculation, imperfect-information tracking, AI heuristics, and master search
src/scenes/ Phaser scene lifecycle, menus, board rendering, interaction, HUD, audio, and FX
public/ Atlas metadata and other static assets loaded by Phaser
android/ Capacitor Android project, Gradle configuration, generated wrapper assets, and the native activity
docs/ Architecture, code style, findings, and cache metadata
prompts/ JIRA workflow artifacts and iteration state

Design Patterns

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

Observed architectural patterns:

Pattern Where it appears
Scene-based flow BootScene -> MenuScene -> GameScene via Phaser scene registration
Functional core / imperative shell src/game/ avoids Phaser imports while src/scenes/ owns runtime side effects
Immutable state transitions applyMove() clones GameState before mutating round state
Worker offload with fallback AIWorkerClient uses ai.worker.ts when available and falls back to direct chooseMove() otherwise
Typed message protocol ai-worker-protocol.ts defines worker request, progress, result, and error shapes
Imperfect-information search CardTracker plus determinization sampling support the master AI tier

Key Components

src/main.ts

  • Creates the Phaser.Game instance.
  • Registers BootScene, MenuScene, and GameScene.
  • Installs a one-shot fullscreen request on first user input when supported.

src/game/types.ts

  • Defines the core game model: Card, Capture, Player, GameState, TeamScore, and ScoreBreakdown.
  • Models constrained domains with unions such as PlayerIndex and Difficulty.
  • Stores PRIMIERA_VALUES for end-of-round scoring.

src/game/engine.ts

  • Builds and shuffles the 40-card deck.
  • Creates a round state for four players with dealer-relative opening order.
  • Implements capture rules where direct value matches take priority over subset-sum captures.
  • Applies moves immutably, awards scope, assigns leftover table cards, and computes round and match scoring.

src/game/card-tracker.ts

  • Tracks cards visible through play and capture events without exposing hidden hands.
  • Reconstructs unseen cards from played + myHand + table.
  • Supplies value and suit residue helpers used by AI inference and probability estimates.

src/game/ai.ts

  • Exposes chooseMove() as the async AI entry point.
  • Implements three difficulty tiers: beginner, advanced, and master.
  • Uses table-driven search profiles, role-aware heuristics, tracker-based inference, and determinization plus alpha-beta search.
  • Configures the current master profile with a 4600 ms budget, 10 samples, depth 6, and batch size 2.

src/game/ai-worker-protocol.ts

  • Defines a single choose-move worker request type.
  • Defines typed progress, result, and serialized error responses.
  • Keeps worker communication schema isolated from UI code.

src/game/ai-worker-client.ts

  • Wraps worker lifecycle and pending-request tracking behind the same chooseMove() API that scenes consume.
  • Creates the worker as an ES module with new Worker(new URL('./ai.worker.ts', import.meta.url), { type: 'module' }).
  • Fails over pending requests to in-thread AI execution if worker creation, messaging, or deserialization fails.

src/game/ai.worker.ts

  • Rehydrates CardTracker from a serialized snapshot.
  • Delegates move selection to chooseMove().
  • Posts progress, result, or serialized error messages back to the main thread.

src/scenes/BootScene.ts

  • Loads the card atlas and card back.
  • Displays a simple loading bar.
  • Transitions into MenuScene after asset load.

src/scenes/MenuScene.ts

  • Renders the title, rules summary, and difficulty selection.
  • Starts GameScene with the chosen difficulty.

src/scenes/GameScene.ts

  • Owns match flow, dealing, selection, capture resolution, AI turn orchestration, score HUD, status UI, think bar, particles, and procedural audio.
  • Instantiates and disposes AIWorkerClient on scene lifecycle events.
  • Updates CardTracker after play and capture events so AI inference remains derived from visible information.

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

  • Extends BridgeActivity.
  • Applies immersive mode during onCreate() and whenever window focus returns.
  • Hides status and navigation bars with transient swipe behavior.

Dependencies

JavaScript production dependencies

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

JavaScript development dependencies

Package Version Purpose
typescript ^5.0.0 Static type checking and TS compilation step
vite ^5.0.0 Dev server and production bundler

Android / Gradle dependencies

Dependency Version Source Purpose
com.android.tools.build:gradle 8.13.0 android/build.gradle Android Gradle plugin
com.google.gms:google-services 4.4.4 android/build.gradle Optional Google services integration
androidx.appcompat:appcompat 1.7.1 android/variables.gradle Android app compatibility
androidx.coordinatorlayout:coordinatorlayout 1.3.0 android/variables.gradle Layout coordination helpers
androidx.core:core-splashscreen 1.2.0 android/variables.gradle Splash screen support
junit:junit 4.13.2 android/variables.gradle JVM Android tests
androidx.test.ext:junit 1.3.0 android/variables.gradle Instrumented test runner
androidx.test.espresso:espresso-core 3.7.0 android/variables.gradle Instrumented UI testing

Platform configuration

  • compileSdkVersion: 36
  • targetSdkVersion: 36
  • minSdkVersion: 24

Module Organization

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

Application-level dependency direction is one-way:

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

Data Flow

  1. main.ts creates the Phaser app and registers all scenes.
  2. BootScene loads textures and starts MenuScene.
  3. MenuScene passes the chosen difficulty to GameScene.
  4. GameScene.create() creates a fresh CardTracker, constructs a new GameState, and starts the opening deal.
  5. Human turns use pointer-driven card selection and findCaptures() output to choose legal captures.
  6. AI turns call AIWorkerClient.chooseMove(state, playerIdx, difficulty, tracker, onProgress).
  7. AIWorkerClient posts a typed request to ai.worker.ts; if workers are unavailable, it reruns the same request in-thread.
  8. chooseMove() returns a heuristic move for lower tiers or performs batched master search while emitting AIDecisionProgress.
  9. GameScene updates the think bar from progress callbacks, executes the returned move, records tracker state, and advances turn order.
  10. When every hand is empty, engine.ts finalizes scoring and GameScene presents the round or match outcome.

Build System

Command Source Purpose
npm run dev package.json Starts the Vite dev server
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 with Vite preview
npx tsc --noEmit user-provided test command Type-checks the TypeScript codebase without emitting files