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

99 lines
4.9 KiB
Markdown

# Findings
> Last Updated: 2026-04-02T18:12:18.000Z
## Summary
Initializer refresh for the current Scopone Scientifico codebase. The existing findings were stale relative to the latest AI and tracker implementation, so the observations below reflect the current source tree.
## Codebase Observations
- Primary gameplay code lives in 8 TypeScript source files under `src/`; the Android wrapper adds 3 Java files.
- The largest modules are `src/scenes/GameScene.ts` (1446 lines) and `src/game/ai.ts` (1210 lines).
- `src/game/` remains framework-independent and contains the rules engine, score calculation, card tracker, and AI logic.
- The AI now has three distinct difficulty levels: `beginner`, `advanced`, and `master`.
- The `advanced` and `master` tiers use `CardTracker` to reason about unseen cards instead of reading hidden hands directly.
- The `master` tier performs determinization plus alpha-beta search and reports progress back to the scene.
- `GameScene` displays AI progress through a top think bar and updates it from the `AIDecisionProgress` callback.
- Audio remains fully procedural via Web Audio; no audio asset pipeline is present.
- No ESLint or Prettier config is present.
- The only repository-wide verification command supplied is `npx tsc --noEmit`.
## Potential Improvement Areas
- `GameScene.ts` still centralizes scene layout, input, effects, audio, HUD, and round transitions in one file, which raises maintenance cost.
- `ai.ts` mixes heuristic tiers, inference helpers, determinization, and alpha-beta evaluation in one module.
- The `master` profile allows up to 9800 ms of search budget, which may be expensive on slower devices even with batch yielding.
- There is still no dedicated automated test suite for rules or AI behavior beyond type-checking.
- Formatting rules are enforced socially rather than by a linter/formatter toolchain.
## Current Rule / Implementation Notes
### Capture behavior in `engine.ts`
- Direct-match capture has priority over subset-sum capture.
- When multiple direct matches exist, `findCaptures()` returns one single-card option per matching card.
- Subset-sum captures are explored only when no direct match exists.
- `applyMove()` defaults to the first legal capture if no explicit capture choice is supplied.
### AI implementation snapshot
- `beginner` adds randomness around a basic heuristic to remain beatable.
- `advanced` adds race awareness, anti-scopa logic, partner setup, anchor play, and tracker-based probability estimates.
- `master` orders legal moves with a quick evaluator, samples hidden hands, then scores moves with alpha-beta search under a deadline.
- `masterMove()` yields back to the browser between batches so Phaser can repaint the progress UI.
### Scene / UI implementation snapshot
- `MenuScene` exposes difficulty selection before match start.
- `GameScene` records every played card and captured table card in `CardTracker`.
- The HUD continuously displays cards, denari, settebello, primiera, scope, and total points for both teams.
- Round-end and game-over flows are managed in-scene rather than through separate overlay components.
## Research Performed
### Web Research: Scopone Scientifico Rules (2026-03-31)
**Sources**: Wikipedia (*Scopa* article, Scopone section), Pagat.com (*Scopone* page by John McLeod)
#### Core Rules (Scopone Scientifico variant)
- 4 players, 2 fixed teams of 2 (sit opposite): Team A = players 0+2, Team B = players 1+3.
- 40-card Napoletane deck: 4 suits (`bastoni`, `coppe`, `denara`, `spade`), values 1-10.
- All 40 cards are dealt at the start of the round; the table begins empty.
- Turns advance in the implementation as `0 -> 1 -> 2 -> 3`.
#### Capture Rules
1. If the played card matches one or more table cards by value, a direct match must be taken.
2. If multiple direct matches exist, one matching table card is chosen.
3. If no direct match exists, a subset of table cards may be captured when their values sum to the played value.
4. A direct match has priority over any possible sum capture.
5. Scopa awards a point only when the table is cleared before the final play of the round.
#### Scoring
| Category | Rule |
|----------|------|
| Carte | Majority of captured cards |
| Denari | Majority of `denara` suit cards |
| Settebello | Team that captures the 7 of `denara` |
| Primiera | Highest best-of-each-suit prime value |
| Scope | One point per scopa |
#### Primiera values used in code
| Card value | Primiera value |
|------------|----------------|
| 7 | 21 |
| 6 | 18 |
| 1 | 16 |
| 5 | 15 |
| 4 | 14 |
| 3 | 13 |
| 2 | 12 |
| 8, 9, 10 | 10 |
### SCOPONE-0008: AI progress rendering notes (2026-04-02)
- The current implementation does not use Phaser `TimerEvent` progress helpers.
- Instead, `chooseMove()` emits its own normalized progress payload through `AIDecisionProgress`.
- `GameScene.updateThinkBar()` renders remaining time from that callback.
- The yielding behavior in `masterMove()` is necessary so the browser can repaint while search batches continue.