All checks were successful
release / build-release (push) Successful in 1m35s
- level: Schedule (ankomst/intervall/uppehåll) med Status(t), spårnummer, avgift, skylttexter per i-ruta, Path (BFS) och UngatedPlatforms – regeln att perronger bara nås via spärrar testas för alla banor - sim.Run: klocka, tågkort (saldo dras vid spärr, tomt kort stoppas), ombordstigning med Enter när tåget är inne, vinst/förlust; headless bot-test klarar bana 001 och förlorar på fel tåg - game: perronginfo (avgår om / nästa tåg om), skyltruta, nekad spärr, tågvagn som ritas när tåget är inne, inforutan flyttas upp när spelaren står nära nederkanten; resultat med spärrpassager och saldo - bana 001 ombyggd så spärrarna är flaskhalsar; bana 002 omgenererad med spärrar runt perrongerna och skylttexter - tools/shots räknar ut vägar med BFS; skriptkommandot waittrain - docs/README/wiki uppdaterade med nya bilder Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
142 lines
9.3 KiB
Markdown
142 lines
9.3 KiB
Markdown
# Mål och tester
|
||
|
||
## Projektmål
|
||
|
||
### Vision
|
||
|
||
Ett pixel art-pusselspel där känslan av att vara vilse på en japansk
|
||
station är själva spelet – och där man faktiskt blir bättre på att läsa
|
||
skyltarna ju mer man spelar. Spelet ska vara en enda binär som är lika lätt
|
||
att bygga på Linux som på Windows.
|
||
|
||
### Konkreta mål
|
||
|
||
1. **Spelbar story** från flygplatsen till flygplatsen, med stigande
|
||
svårighet, flerbytesbanor, sidobanor, slutanimation och eftertexter.
|
||
2. **En binär + en `resources/`-mapp** per plattform. Inga installers, inga
|
||
runtime-beroenden utöver vad ett vanligt skrivbord redan har.
|
||
3. **Få byggverktyg.** Go är det enda kravet (Linux behöver dessutom en
|
||
C-kompilator och X11/GL-headers för fönsterhanteringen). Allt byggs med
|
||
`go run ./tools/build`.
|
||
4. **Debug och release i VS Code** med F5 respektive Ctrl+Shift+B, utan
|
||
extra skript.
|
||
5. **All spellogik testbar utan fönster.** Bara presentationslagret känner
|
||
till Ebitengine.
|
||
6. **Deterministiskt.** Samma seed ger samma minispel och samma mål i
|
||
oändligt läge.
|
||
7. **Windows utan omskrivning.** `-os windows` ska vara allt som krävs för
|
||
att få en fungerande Windows-binär från Linux.
|
||
|
||
### Mätbara mål
|
||
|
||
| Mål | Mått | Status 2026-10-23 |
|
||
|-----|------|-------------------|
|
||
| Inkrementellt debug-bygge | < 10 s | 4,7 s |
|
||
| Release-binär | < 20 MB | 10,2 MB (Linux), 10,8 MB (Windows) |
|
||
| Testsviten | `go test ./...` grön på < 30 s | ~0,1 s |
|
||
| Banor | 100 % passerar det automatiska lösbarhetstestet | 2 av 2 |
|
||
| Windows-korsbygge från Linux | fungerar utan extra verktyg | ✓ (CGO_ENABLED=0) |
|
||
| Linux-binärens länkade bibliotek | bara libc | ✓ (GL/X11 laddas dynamiskt vid körning) |
|
||
| Bildfrekvens | 60 fps vid 4× skala på integrerad grafik | ej mätt |
|
||
| Uppstart | < 2 s till första bildruta | ej mätt |
|
||
|
||
## Teststrategi
|
||
|
||
### Principer
|
||
|
||
- **Ren logik → enhetstester.** Paket under `internal/` som inte är
|
||
presentation får inte importera Ebitengine. Det kontrolleras av
|
||
`internal/archtest`, som läser beroendegrafen med `go list` och faller om
|
||
något annat paket än `internal/game`, `internal/ui`, `internal/audio`
|
||
eller `cmd/…` drar in Ebitengine.
|
||
- **Data testas som data.** Varje bana, språkfil och ordbok som ligger i
|
||
`resources/` valideras av tester, så att trasigt innehåll stoppar bygget
|
||
i stället för att krascha spelet.
|
||
- **Slump går alltid via `internal/rng`** med en känd seed. Då går
|
||
minispel och event-timing att testa deterministiskt.
|
||
- **Inga tester kräver display.** Smoke-testet av själva fönstret körs
|
||
manuellt (eller på en maskin med skärm) med `-smoke`.
|
||
|
||
### Testnivåer
|
||
|
||
| Nivå | Vad | Hur | Körs |
|
||
|------|-----|-----|------|
|
||
| 1. Enhet | Funktioner i ett paket | `*_test.go` bredvid koden | `go test ./...` |
|
||
| 2. Data | Allt under `resources/` | Datadrivna tester som läser filerna | `go test ./...` |
|
||
| 3. Arkitektur | Beroenderegler | `internal/archtest` | `go test ./...` |
|
||
| 4. Simulering | En bot spelar en bana headless | Deterministisk körning av spelloopen utan rendering (kommande) | `go test ./...` |
|
||
| 5. Smoke | Binären öppnar fönster och avslutar | `metro-puzzle-jp -smoke 90`, eller `tools/shots` som dessutom spelar igenom bana 001 i skriptläge | manuellt / med skärm |
|
||
| 6. Speltest | Känsla, svårighet, buggar | Checklistan nedan | före varje release |
|
||
|
||
### Tester som finns i dag
|
||
|
||
| Paket | Test | Verifierar |
|
||
|-------|------|------------|
|
||
| `internal/res` | `TestLocate_*` | Uppslagsordningen env → bredvid binären → uppåt från cwd |
|
||
| `internal/res` | `TestDir_RealRepo` | Att repots `resources/` hittas och att sv.json + placeholder.png går att läsa |
|
||
| `internal/rng` | `TestDeterministic`, `TestDeriveIsStableAndContextual` | Samma seed → samma sekvens; del-seeds per kontext |
|
||
| `internal/level` | `TestParseAndSolve`, `TestUnsolvableWhenWalledOff` | BFS hittar/hittar inte väg till rätt perrong |
|
||
| `internal/level` | `TestValidationErrors` | Ojämna rader, okända tecken, fel antal starter, tåg vid saknad perrong … |
|
||
| `internal/level` | `TestAllShippedLevels` | Varje bana i `resources/data/levels` parsar, har id = filnamn, är lösbar och har inga onåbara interaktiva rutor |
|
||
| `internal/level` | `TestListAndLoadFile` | Banlistan är sorterad, laddning från disk, `TrainAt` hittar rätt/fel tåg |
|
||
| `internal/sim` | `TestMoveFourDirections`, `TestBlockedByWallTurnsButStays` | Rörelse åt alla håll; vägg stoppar men vänder figuren |
|
||
| `internal/sim` | `TestContinuousMovementKeepsPace`, `TestStopsAtTileBoundaryWithoutInput`, `TestDirectionChangesOnlyAtTileBoundary` | Jämn fart med hållen tangent, stopp vid rutgräns, riktningsbyte bara vid rutgräns |
|
||
| `internal/sim` | `TestWorldPosInterpolates`, `TestFrameExactArrival`, `TestHugeDtIsBounded` | Pixelposition mellan rutor; exakt 10 bildrutor per ruta vid 6 rutor/s; inga oändliga loopar |
|
||
| `internal/sim` | `TestCamera*` | Kameran centrerar, klampas mot kanter och centrerar små världar |
|
||
| `internal/level` | `TestScheduleStatus`, `TestScheduleAndFareDefaults` | Tidtabellen ger rätt "inne/borta" och sekunder kvar; standardvärden fylls i |
|
||
| `internal/level` | `TestSignAt`, `TestPath`, `TestUngatedPlatforms` | Skylttext per ruta; BFS-väg är kortast och sammanhängande; perronger utan spärr framför upptäcks |
|
||
| `internal/level` | `TestAllShippedLevels` (utökat) | …plus: tidtabeller giltiga, alla skyltrutor har sv/en-text, alla tåg har spår, **inga perronger nås utan spärr** |
|
||
| `internal/sim` | `TestBotWinsLevel001` | **Simuleringstest M2:** bot går kortaste vägen, passerar spärren (saldo dras en gång), väntar in tåget, kliver på → vinst; Step är no-op efteråt |
|
||
| `internal/sim` | `TestBotLosesOnWrongTrain`, `TestBoardOnlyWhenTrainPresent` | Fel tåg → förlust; Enter utan tåg inne gör inget |
|
||
| `internal/sim` | `TestGateNeedsCardBalance`, `TestSignHereOnlyWhenStill` | Tomt kort stoppas och registreras för HUD; mellan två spärrutor gratis; skylt visas bara stilla |
|
||
| `internal/archtest` | `TestOnlyPresentationPackagesImportEbitengine` | Beroenderegeln ovan |
|
||
|
||
### Planerade tester per milstolpe
|
||
|
||
| Milstolpe (se roadmap) | Tester som ska finnas när den är klar |
|
||
|------------------------|----------------------------------------|
|
||
| ~~M1 Rörelse & kamera~~ ✓ | Kollision mot vägg, rörelse i 4 riktningar, kamera klampas till kartan – finns, se tabellen ovan |
|
||
| ~~M2 Stationen~~ ✓ | Tidtabell, spärr med/utan saldo, vinst/förlust, bot klarar bana 001 headless – finns, se tabellen ovan |
|
||
| M3 Japanska & skyltar | Delvis översättning ger exakt de ord spelaren kan; andel engelska följer svårighetstabellen; ordboken: alla nycklar har kana/romaji/en/sv; alla skyltord i banorna finns i ordboken; hjälptid = f(japanska-nivå) |
|
||
| M4 Lämmeltåget | Mätare sjunker med rätt takt; event-frekvens ökar med gruppstorlek; event väljs deterministiskt per seed |
|
||
| M5 Minikarta | Upptäckta rutor markeras, återställs per bana; avgångar syns från start |
|
||
| M6 Kort/biljetter/minispel | Saldo dras i spärr; tomt kort → automatkrav; biljettminispel: rätt/fel biljett; telefon-skanning misslyckas med given procent per seed; batteri tar bara slut över tröskeltid |
|
||
| M7 Svårighet/poäng/debuffs | Poängformeln (tid, pengar, mätare, läge); tidsgräns och maxantal missade tåg; varje debuff ändrar rätt stat; temporära debuffar räknar ned 1–4 banor |
|
||
| M8 Progression & sparfil | Sparfil round-trip (skriv → läs ger samma tillstånd inkl. seed); skill tree-krav; upplåsningar efter rätt bana; "< 33 %"-regeln kontrolleras mot itemlistan |
|
||
| M9 Navigeringslägen | Listläge genererar rätt ordning av tåg; skyltläge: 1–4 giltiga vägar; fel-riktnings-förlust triggar vid rätt slutstation |
|
||
| M10 Story-innehåll | Alla banor lösbara (redan automatiskt); flerbytesbanor har sammanhängande byten; sista banan slutar på flygplatsen |
|
||
| M11 Oändligt läge & NG+ | Målsekvens deterministisk per seed; NG+ behåller skills men nollställer items |
|
||
| M12 Ljud & polish | Alla ljudfiler som refereras finns och går att avkoda; Windows-binär startar (manuellt) |
|
||
|
||
### Acceptanskriterier för "klar"
|
||
|
||
En milstolpe är klar när:
|
||
|
||
1. Alla tester i raden ovan finns och är gröna.
|
||
2. `go vet ./...` och `go test -race ./...` är gröna.
|
||
3. Debug- och release-bygget går igenom för Linux och Windows.
|
||
4. Roadmapen är uppdaterad med datum och eventuella avsteg.
|
||
|
||
### Manuell testchecklista (speltest)
|
||
|
||
- [ ] Spelet startar till meny på under 2 s; ESC/avsluta fungerar.
|
||
- [ ] Fönstret kan skalas; pixlarna är skarpa (heltalsskalning).
|
||
- [ ] Bana 001 går att klara i både listläge och skyltläge.
|
||
- [ ] Fel tåg ger tydlig förlust med förklaring.
|
||
- [ ] Mätarna syns, sjunker och går att fylla på.
|
||
- [ ] Tomt kort tvingar till automaten; minispelet är begripligt första gången.
|
||
- [ ] Minikartan fylls i när man går runt och nollställs vid ny bana.
|
||
- [ ] Spara mitt i en bana, ladda, och få samma minispelsutfall.
|
||
- [ ] Ljud spelas vid ankomst och avgång; inget knaster vid loop.
|
||
- [ ] Samma sparfil fungerar på Linux och Windows.
|
||
|
||
### Kommandon
|
||
|
||
```bash
|
||
go test ./... # hela sviten
|
||
go test -race -v ./... # utförligt med race-detektor
|
||
go test ./internal/level/ -run TestAllShippedLevels -v # bara banorna
|
||
go vet ./...
|
||
go run ./tools/build -mode debug -run -- -smoke 90 # bygg + smoke-test med fönster
|
||
```
|