Добавить общую систему весовых объектов

This commit is contained in:
2026-08-19 07:40:11 +03:00
parent 19bb64edfb
commit 259fcd316b
32 changed files with 1017 additions and 34 deletions
+11 -1
View File
@@ -160,6 +160,13 @@ baseline-задачи также имели явного владельца по
переход дальше; границы доступного human evidence зафиксированы в
`STAGE5_HUMAN_PLAYTEST_RESULT.md`. Stage 6 разблокирован.
Текущий статус Stage 6: foundation, production hazards, burned/crushed corpse
states и weighted objects приняты. Каталог содержит 17 уровней; последний exact
candidate прошёл `108` app JVM, `2` content-tool JVM и нефильтрованную Android 16
матрицу `48/48` за `2,223.695 s`. Следующий dependency-order slice — challenges
и production progression, после него начинается массовое производство четырёх
миров.
### Этап 6. Production content — P1, несколько итераций
Задачи:
@@ -191,7 +198,10 @@ data-driven модель. Завершён первый mechanics slice: product
99 JVM-тестов и Android 16 matrix `43/43` (`2004.172 s`). Следующая зависимая
итерация завершена: `CRUSHED` и `BURNED`, save migration и обучающие уровни
15–16 приняты clean gate `102 JVM` и unfiltered Android matrix `46/46`
(`1,842.248 s`). Доказательства зафиксированы в `STAGE6_CORPSE_STATES.md`.
(`1,842.248 s`). Weighted-object slice также принят: общий `IWeightedObject`,
Box/Rock/Ball/IceBlock/Counterweight, save v4 и обучающий уровень 17 прошли clean
gate `108` app JVM + `2` content-tool JVM и unfiltered Android matrix `48/48`
(`2,223.695 s`). Evidence зафиксирован в `STAGE6_WEIGHTED_OBJECTS.md`.
### Этап 7. Техническая стабилизация и release engineering — P0, 4–8 дней
+31 -2
View File
@@ -1,8 +1,8 @@
# Графы решений уровней 1–16
# Графы решений уровней 1–17
Документ фиксирует **авторский маршрут** каждого уровня текущего vertical slice. Он получен из `LevelCatalog`, моделей `LevelDefinition` и фактической логики `GameView`, затем проверен device-level ботами через production-команды движения и прыжка. `targetDeaths` ниже — целевое число жертв для результата уровня, но оно не доказывает минимальность решения.
На 19 августа 2026 года intended route всех уровней 1–16 автоматически выполнен по три раза подряд без retry masking. Device-тесты управляют production `GameView` через те же флаги, что и touch-контролы. Для уровня 8 отдельно проверено восстановление после истечения таймера на дальней стороне `PIT`.
На 19 августа 2026 года intended route всех уровней 1–17 автоматически выполнен по три раза подряд без retry masking. Device-тесты управляют production `GameView` через те же флаги, что и touch-контролы. Для уровня 8 отдельно проверено восстановление после истечения таймера на дальней стороне `PIT`.
## Семантика, общая для графов
@@ -405,6 +405,35 @@ Moving bridge над PIT управляется signal "burn-weight"
и нижней координатой моста. Save version 3 сохраняет флаг; Canvas добавляет
текстовую метку `BURNED`, поэтому состояние не кодируется только цветом.
## Уровень 17 — `The Whole Weight`
**Статус:** доказан production-input ботом, 3/3 последовательных прохождения.
**Ожидаемые и доказанные смерти:** `0`; дверь обязана удерживаться только
физическими объектами после отпускания player input.
```text
Door требует signal "weight-gate" с requiredMass=9
→ на PRESSURE уже стоят Box(1), Rock(2), Ball(1) и IceBlock(2): сумма 6
→ Counterweight(3) находится слева от плиты, поэтому Door закрыта
→ игрок подходит и толкает Counterweight вправо
→ при x≥920 Counterweight пересекает plate x=1000..1650
→ общий IWeightedObject resolver получает массу 6+3=9 и открывает Door
→ игрок отпускает input; объект продолжает удерживать сигнал без player mass
→ игрок двумя отдельными прыжками пересекает Counterweight и ряд объектов
→ проходит открытую Door и достигает goal
→ COMPLETE без смерти и без создания тел
```
**Контракт:** `Player`, `CorpseManager.Body` и `PhysicalObjectState` реализуют
один `IWeightedObject`; plate агрегирует только геометрически пересекающуюся
активную массу, не проверяя тип. Все пять authored типов имеют type/box/mass в
JSON, детерминированный runtime, non-color type+weight label, SVG/TSV preview и
save-v4 состояние. V1–v3 active sessions мигрируют с пустым runtime-object list.
**Bot checkpoints:** каталог публикует пять objects и Counterweight mass 3;
до push `allDoorsOpen=false`; после push `firstPhysicalObjectX≥920` и Door open;
после release Door остаётся open; затем два отдельных jump edge и `completed=true`.
## Проверки, следующие из графов
1. Сохранять полный integrated device-regression: intended route принятых уровней по три раза и отдельный recovery route уровня 8.
+12 -7
View File
@@ -2,7 +2,7 @@
## Назначение
Все десять уровней находятся в Android-independent модуле `level-format` и
Все уровни каталога находятся в Android-independent модуле `level-format` и
загружаются из `level-format/src/main/resources/levels`. Runtime, unit-тесты и
desktop-команды используют один и тот же JSON parser, catalog loader и validator.
Изменение геометрии или текста не требует изменения игрового Java-кода.
@@ -48,6 +48,9 @@ desktop-команды используют один и тот же JSON parser,
"spawn": {"x": 130, "y": 760},
"goal": {"x": 1810, "y": 770, "width": 86, "height": 110},
"targets": {"deaths": 1, "seconds": 50},
"objects": [
{"type": "COUNTERWEIGHT", "box": {"x": 300, "y": 780, "width": 80, "height": 100}, "mass": 3}
],
"platforms": [
{"box": {"x": 0, "y": 880, "width": 2050, "height": 200}}
],
@@ -68,7 +71,10 @@ desktop-команды используют один и тот же JSON parser,
Поддерживаемые значения:
- hazards: `SPIKES`, `SAW`, `FREEZER`, `ELECTRIC`, `PIT`;
- hazards: `SPIKES`, `SAW`, `FREEZER`, `ELECTRIC`, `PIT`, `CRUSHER`, `FIRE`,
`PROJECTILE`, `EXPLOSION`;
- physical objects: `BOX`, `ROCK`, `BALL`, `ICE_BLOCK`, `COUNTERWEIGHT`; каждый
задаёт `box` и положительный integer `mass`;
- switches: `PRESSURE`, `TOGGLE`, `TIMED`;
- static platform: только `box`;
- moving platform: `box`, ненулевой `travelX` или `travelY`, положительный
@@ -82,7 +88,7 @@ desktop-команды используют один и тот же JSON parser,
- известные format/physics versions;
- конечные положительные размеры мира и объектов;
- spawn, goal, платформы, hazards, switches, doors и конечную позицию moving
- spawn, goal, physical objects, платформы, hazards, switches, doors и конечную позицию moving
platform внутри мира;
- наличие хотя бы одной платформы;
- неотрицательный target deaths и положительный target seconds;
@@ -115,9 +121,9 @@ level-03.json.doors[0].requiredSignals[0] references missing signal 'missing'
Результат находится в `level-format/build/level-previews`:
- `level-01.svg` … `level-10.svg` — world-space схема spawn/goal, платформ,
hazards, switches и doors;
- `catalog.tsv` — координаты, размеры, travel и signal/control references.
- `level-01.svg` … последний уровень каталога — world-space схема spawn/goal,
objects, платформ, hazards, switches и doors;
- `catalog.tsv` — координаты, размеры, object mass, travel и signal/control references.
Вывод использует стабильный порядок и locale-independent числа. Два запуска на
неизменном каталоге должны давать byte-identical файлы.
@@ -136,4 +142,3 @@ Wall-clock, device identifiers и прямые mutation-команды не за
`traceId` — SHA-256 точного UTF-8 JSON и всегда включён в failure diagnostic.
Stage 4 сохраняет воспроизводимый артефакт расследования, но намеренно не добавляет
runtime replay executor.
+54
View File
@@ -0,0 +1,54 @@
# Stage 6 weighted objects
Date: 19 August 2026
Beads task: `goon-game-weighted-objects`
## Contract
`IWeightedObject` is the only pressure-mass contract. It exposes world geometry,
integer pressure mass, and whether the object may activate a mechanism. The live
player, retained corpse bodies, and authored physical objects implement it;
`PressureMassResolver` knows no concrete object types.
The version-1 level schema now accepts an optional `objects` array with a strict
`type`, `box`, and positive `mass`. Supported production types are `BOX`, `ROCK`,
`BALL`, `ICE_BLOCK`, and `COUNTERWEIGHT`, matching the Beads scope. Existing JSON
without `objects` stays source-compatible. Validation, deterministic SVG/TSV
preview, Canvas rendering, collision/push physics, moving-platform support,
automation and performance accounting all consume the same definitions.
Active-session save version 4 stores object type, geometry, velocity, mass,
grounding and moving-platform support. V1–v3 decode with an empty runtime object
list; levels from those versions had no authored physical objects, so restore
uses the level's initial definitions without inventing state.
## Teaching puzzle
Level 17, `The Whole Weight`, places Box(1), Rock(2), Ball(1), and IceBlock(2) on
a pressure plate. Their total 6 cannot open the mass-9 door. The player must push
Counterweight(3) onto the plate, release input to prove object-only retention,
then jump across the weighted row and pass the open door.
## TDD and acceptance evidence
- RED: missing `IWeightedObject`/resolver and all JSON object symbols (28 compile
errors); GREEN: shared pure mass aggregation and five parsed types.
- RED: missing runtime/save-v4 symbols (13 compile errors); GREEN: deterministic
state, corpse interface parity, v4 round-trip and v1–v3 migrations.
- RED: catalog expected 17 but contained 16; GREEN: validator `17/17` and bounded
two-page pagination.
- RED: Android scenario class absent; GREEN: compiled production-input route.
- RED: preview lacked object geometry; GREEN: byte-stable SVG and TSV include
object type and mass.
- Focused push/door/save integration: `1/1` GREEN in `9.128 s`.
- Level 17 intended route: `3/3` GREEN in `31.119 s`, exact zero deaths/bodies.
- Focused player/corpse/object pressure and restore matrix: `8/8` GREEN in
`315.926 s`.
- Clean gate: app JVM `108/108`, content-tool JVM `2/2`, validator `17/17`,
lint, app APK and test APK GREEN.
- Final exact-candidate unfiltered Android matrix: `48/48` GREEN in
`2,223.695 s`, with zero failures and zero skipped tests.
- Debug APK ZIP/signature: GREEN; packaged level JSON count: `17`.
- Debug APK SHA-256:
`141eecd3605d5cc5ab8ac20b52b666650b672c0723e2a3f8ea2187e75adca002`.
+1 -1
View File
@@ -65,7 +65,7 @@ Snapshot на 19 августа 2026 года:
| 3 | 5 | 0 |
| 4 | 4 | 0 |
| 5 | 15 | 0 |
| 6 | 18 | 10 |
| 6 | 18 | 8 |
| 7 | 9 | 9 |
| 8 | 1 | 1 |
| 9 | 1 | 1 |