Реализует финальную модель scoring из data-contracts.md v3.10:
fixed center bumpers — по last-touch; setup-bumpers — defensive trap
(награждают владельца только когда мяч принадлежит сопернику).
Self-farm запрещён. Neutral ball не даёт очков нигде.
Code changes:
- types/index.ts: BumperScoreSource union ('fixed_last_touch' |
'player_setup' | 'ai_setup'); MatchResult.aiBumperPointsEarned +
aiBumperHitsCount.
- Bumper.ts: новый required field source: BumperScoreSource;
передаётся в onHit callback через bumper.source.
- scoring/MatchTracker.ts: pure helper computeCreditedTo(source, ballOwner)
→ реализует 9-cell credit matrix; recordBumperHit принимает
(rawPoints, source, ballOwner, type, ...) и возвращает {creditedTo,
pointsEarned}; новые getter'ы getAIBumperHits + getUncreditedBumperHits.
- scenes/MatchScene.ts:
* Fixed bumpers создаются с source='fixed_last_touch'
* placeSetupBumpers передаёт source per side
* handleBumperHit (новая сигнатура: bumper, points) рутит в tracker,
emit'ит spawn-particles + telemetry bumper_hit event с полным
набором полей per telemetry-spec.md v3.10
* MatchResult заполняется с AI BP/hits
* match_end telemetry также включает aiBumperPointsEarned/HitsCount
* HUD: BP теперь сравнительный «P x / AI y»
- scenes/ResultScene.ts: breakdown показывает обе стороны BP и hits.
Particle effects (DoD v3.10):
- 12 псевдо-частиц радиально от bumper'а (cubic ease-out, 320ms)
- цвет: player=magenta, ai=cyan, null=grey
- screenshake 80ms/0.0025 ТОЛЬКО на credited hit
(иначе экран дрожит на каждом нейтральном отскоке)
Tests: scoring/MatchTracker.test.ts — 21 теста:
- 9-cell credit matrix (computeCreditedTo, все source × ballOwner)
- recordBumperHit с counter assertions
- многократные hits (накопление BP per сторона)
- симметрия player/AI defensive trap scenarios
- fixed bumpers через смену владения
- events log для telemetry
- recordGoal с autogoal-flag
Итого 50/50 unit-тестов (16 calculateScores + 13 flipperGeometry +
21 MatchTracker). typecheck/lint/build все зелёные.
Несоответствия с docs остающиеся:
- DoD: «12 частиц per credited side» — done; SFX bumper hit (DoD line 247)
— TODO Phase 4 (asset pack).
- Particle effects через psecdoupartials (Arc + tween), не через
ParticleEmitter — упрощение, визуально эквивалентно.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
133 lines
7.8 KiB
Markdown
133 lines
7.8 KiB
Markdown
# Playtest Protocol — Phase 2 AI Distinguishability
|
||
|
||
**Цель.** Закрыть Phase 2 DoD «тестер различает 4 AI-личности после 5 матчей»
|
||
через blind attribution. Требуется внешний тестер (НЕ разработчик и НЕ автор AI кода).
|
||
|
||
**Pass-bar:** ≥ 75 % правильных attribution-ответов (≥ 15 / 20) ИЛИ ≥ 1 distinct tell
|
||
per личность, названный тестером без подсказки.
|
||
|
||
---
|
||
|
||
## Подготовка
|
||
|
||
| Шаг | Команда / действие |
|
||
|---|---|
|
||
| Build | `npm run build && npm run preview` (production build на `localhost:4173`) |
|
||
| Difficulty | **Medium** — Easy скрывает поведение за reaction-задержкой; Hard не реализован (Phase 3) |
|
||
| Mode | Quick Match → выбор личности → Medium |
|
||
| Device | Минимум 1 desktop + 1 mobile session (mobile важно — touch zones там единственный input) |
|
||
| Telemetry | Mock adapter логирует `trackEvent` в консоль — оставить открытой DevTools для пост-анализа |
|
||
|
||
---
|
||
|
||
## Per-match observation rubric
|
||
|
||
После каждого матча тестер заполняет строку:
|
||
|
||
| Поле | Что фиксировать | Источник |
|
||
|---|---|---|
|
||
| `match_index` | 1..20 | manual |
|
||
| `setup_pattern` | Какие bumper-типы AI поставил, где (углы / центр / далеко) | визуально, AI половина |
|
||
| `reaction_distance` | «early / normal / late» — насколько близко мяч долетает до AI-флипперов | субъективно |
|
||
| `miss_rate` | «низкий / средний / высокий» — как часто AI пропускает свой удар | визуально |
|
||
| `special_behaviour` | Любой характерный приём (двойной свинг, странный угол отскока, агрессивная атака центром) | free-text |
|
||
| `final_score` | Player : AI | HUD post-match |
|
||
| `duration_sec` | Длина матча | HUD timer / `match_end` telemetry |
|
||
| `personality_guess` | Бэтти / Турбо / Хитрый Хо / Эхо | blind по завершению ВСЕХ 20 матчей |
|
||
|
||
---
|
||
|
||
## Expected tells (для оценщика; тестеру НЕ показывать до конца сессии)
|
||
|
||
| Личность | Tells |
|
||
|---|---|
|
||
| **Defensive (Бэтти)** | Setup: 2 slingshot в углах ворот + 1 турбо центр + 1 curve + 1 пусто. Поведение: реакция надёжная (`reliabilityMul: 1.1`, capped 1.0 = почти 100 %), чуть быстрее (`reactionMul: 0.9`). AI пропускает редко; матчи длиннее обычного. |
|
||
| **Aggressive (Турбо)** | Setup: 2 турбо в своей зоне (defensive trap против мяча игрока) + 1 slingshot угол + 1 curve + 1 standard. Поведение: реагирует с большего расстояния (`triggerDistBonus: +80px`), чаще промахивается (`reliabilityMul: 0.85`). Быстрые матчи; игрок, застрявший в setup Турбо, быстро отдаёт ему очки. |
|
||
| **Trickster (Хитрый Хо)** | Setup: 4 curve bumper'а (лабиринт) + 1 турбо центр. Поведение: 15 % случайный спайк jitter (×1.3) — реакция «дёргается». Непредсказуемый счёт; необычные траектории мяча. |
|
||
| **Ghost (Эхо)** | Setup: balanced (2 slingshot + 1 турбо + 1 curve + 1 standard). Поведение: 15 % «echo double-swing» — обе стороны активируются одновременно, даже если мяч идёт только в одну. Медианный счёт; характерный двойной flip. |
|
||
|
||
---
|
||
|
||
## Процедура
|
||
|
||
1. **Randomize order.** Использовать random.org pick из `[defensive, aggressive, trickster, ghost]`,
|
||
5 раз для каждой → 20 матчей. **Не группировать по личности** — рассыпать.
|
||
Пример последовательности: `[T, D, G, A, T, A, D, G, T, A, D, G, A, T, D, G, A, D, G, T]`.
|
||
|
||
2. **Играть в выбранном порядке.** После каждого матча — заполнить строку рубрики.
|
||
НЕ смотреть expected tells между матчами.
|
||
|
||
3. **Blind attribution.** По завершении всех 20 матчей — для каждой строки заполнить
|
||
`personality_guess` без обращения к памяти о выборе перед матчем.
|
||
|
||
4. **Score.** Сравнить `personality_guess` с фактическим выбором. Подсчитать accuracy.
|
||
|
||
5. **Subjective rating.** Тестер ставит общую оценку «AI feels different» по 5-балльной
|
||
шкале (≥ 4 = pass).
|
||
|
||
6. **Report.** Заполнить шаблон ниже, приложить к Phase 2 sign-off.
|
||
|
||
---
|
||
|
||
## Failure modes & follow-ups
|
||
|
||
| Результат | Что делать |
|
||
|---|---|
|
||
| Accuracy < 50 % | Модификаторы слишком слабые. Удвоить `triggerDistBonus`, опустить `reliabilityMul` ниже 0.7. |
|
||
| Accuracy 50-74 % | Две личности путаются между собой. Развести их setup'ом сильнее (например, поменять Defensive curve → second slingshot для большего «защитного» паттерна). |
|
||
| Accuracy ≥ 75 %, subjective < 4 | Поведение различимо, но не интересно. Это не блокер Phase 2, но завести задачу на «character polish» в Phase 4. |
|
||
| Тестер жалуется «AI слишком сложный/лёгкий на Medium» | Тюнить `reactionMs` в `src/config/defaults.ts` — не personality-specific. |
|
||
|
||
---
|
||
|
||
## Codex automation (опционально)
|
||
|
||
`codex exec` потенциально может прогнать матчи через headless Phaser
|
||
и replay-log; но для Phase 2 sign-off **достаточно ручного playtest'а**.
|
||
Маппинг рубрики в telemetry events:
|
||
|
||
| Поле рубрики | Telemetry source |
|
||
|---|---|
|
||
| `setup_pattern` (AI) | `MatchResult.aiSetup.slots` |
|
||
| `reaction_distance` | derivable: ball trajectory + `goal_scored.ballOwnershipBeforeGoal` |
|
||
| `miss_rate` | `1 − (AI flipper hit count / ball-passes-through-AI-zone count)` (нужен новый event `flipper_hit` — не в Phase 2 scope) |
|
||
| `final_score` | `match_end.goalsScored / goalsAgainst` |
|
||
| `duration_sec` | `match_end.durationSeconds` |
|
||
|
||
Автоматизация — backlog Phase 5+.
|
||
|
||
---
|
||
|
||
## Report template
|
||
|
||
```markdown
|
||
# Playtest Report — Phase 2 AI Distinguishability
|
||
|
||
**Tester:** <имя / handle>
|
||
**Date:** <YYYY-MM-DD>
|
||
**Build:** HEAD <git-sha>
|
||
**Devices:** desktop=<browser/os>, mobile=<browser/os>
|
||
|
||
## Match log
|
||
| # | Personality (actual) | Setup observed | Reaction | Miss rate | Special | Score | Duration | Guess | Match? |
|
||
|---|---|---|---|---|---|---|---|---|---|
|
||
| 1 | trickster | 4 curve + turbo | normal | medium | hectic angles | 5:3 | 4m12s | trickster | ✅ |
|
||
| 2 | ... | | | | | | | | |
|
||
|
||
## Results
|
||
- Accuracy: __ / 20 = __ %
|
||
- Subjective rating: __ / 5
|
||
- Per-personality breakdown:
|
||
- Defensive: __ / 5
|
||
- Aggressive: __ / 5
|
||
- Trickster: __ / 5
|
||
- Ghost: __ / 5
|
||
|
||
## Free-text observations
|
||
<распознанные tells, неожиданные моменты, баги>
|
||
|
||
## Verdict
|
||
- [ ] Phase 2 AI DoD PASS (≥75% accuracy + ≥4/5 subjective)
|
||
- [ ] Phase 2 AI DoD FAIL — see follow-ups
|
||
```
|