Files
metro-puzzle-jp/doc/mal-och-tester.md
claude f762f9554e
All checks were successful
release / build-release (push) Successful in 1m34s
M9: navigeringslägen, linjenät och terminal
internal/nav med resources/data/network.json (76 stationer, 11 linjer,
Yamanote som ringlinje). Tåg bedöms från lineId + terminus mot banans
station/to: rätt, fel håll, för långt bort (fler än 12 stationer) eller
ingen trafik; correct räknas ut för nätkopplade banor, 1-4 rätta tåg.
Tågresan visar linjens riktiga stationer. Nya förlustorsaker "Fel håll"
och "För långt bort". Listläge (nästa tåg nere till vänster) och
skyltläge (+50 % poäng) växlas med N på bankartan och sparas; -mode.
Terminalen: biljettautomaten visar linjetavlan på nätbanor. Perronger
P p Q q R r. Bana 006 Ikebukuro med fyra perronger. Banorna 001-005
kopplade till nätet. Skript: waitover och pick calm; poängraden
radbryts; skärmdumpar uppdaterade.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-24 13:07:36 +02:00

18 KiB
Raw Blame History

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 7 av 7
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.
  • Innehållet testas mot ordboken. Ny japansk text i en bana som inte finns i jp-dictionary.json fäller go test – det är så vi garanterar att skyltsystemet alltid kan översätta allt spelaren kan möta.

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/lang TestTokenizeLongestMatchAndKinds Längsta matchning, ord/okänt/övrigt, Unknown pekar ut vad ordboken saknar
internal/lang TestRenderPartialTranslation, TestKanaReadingWithoutMeaning, TestReadingsShownFromLevel2 Samma skylt visar exakt det spelaren kan: kända ord översatta, okända kvar, kana som romaji när kana kan, läsningar från nivå 2
internal/lang TestLearnUnlocksKanaAndLevels, TestFirstUnknownWord Nivåformeln, kana låses upp efter tre kana-ord, vilket ord hjälpen lär ut
internal/lang TestHelpSeconds, TestEnglishShareAndDeterminism Hjälptiden sjunker med nivån men inte under golvet; engelska-andelen per svårighet (1 = alltid, 5 = aldrig), deterministisk, ~60 % på svårighet 2
internal/lang TestParseDictionaryValidation, TestShippedDictionary, TestAllJapaneseInLevelsIsInDictionary Ordboken är komplett per post och täcker all japanska i banorna
internal/sim TestAskHelpRevealsSignAndTeachesWord, TestHelpIsCancelledByWalkingAway, TestNoHelpOffSign Hjälpen tar rätt tid, avslöjar skylten, lär första okända ordet; avbryts när man går; kräver skylt
internal/lang TestProgressLearnsAfterEnoughReads, TestBuyWordsWithPoints Tre framsteg lär ordet; köp för poäng (kostnad = tier), stjärnor ger poäng
internal/level TestPartyAndParDefaults Sällskap/par-standardvärden, max sällskap, toalett/kiosk passerbara, avgångstavlans text
internal/sim TestStarsFromParTime, TestGoodResultTeachesDestination Par från kortaste vägen eller bandatan, stjärntrösklar; tre stjärnor lär resmålet och ger poäng, långsam vinst gör det inte
internal/sim TestReadingGivesSeededProgress Att stanna på en skylt ger seedade framsteg; samma seed = samma utfall; ord lossnar efter många läsningar
internal/sim TestMetersDecayAtRates, TestUrgeArisesBelowThreshold Mätarnas takt; behov under tröskeln
internal/sim TestMoreMembersMoreEvents, TestEventsAreSeeded M4: fyra i sällskapet ger minst 3× så många händelser som en; samma seed = samma logg
internal/sim TestUrgesSlowAndFacilitiesRestore, TestFollowersTrailLeader, TestPartySizeIsClamped Fartstraff, toalett/kiosk återställer och kostar, distraktion går över, följarna står på ledarens spår
internal/sim TestToiletAndKioskInRun, TestPartySlowsLeader Enter på W startar ett besök som tar tid och avbryts om man går; K drar från kortet; sällskapet saktar ledaren
internal/sim TestFogRevealsAlongCorridorsNotThroughWalls, TestLandmarksAlwaysVisible, TestFogGrowsWithMovementAndResetsPerRun M5: dimman lättar längs gångar men inte genom väggar; perronger/start/spärrar syns alltid; dimman växer när man går och nollställs per omgång
internal/minigame TestTopUpFlowAndDeterminism, TestTicketBoardSeededAndAffordable, TestCrowdZoneAndAttempts, TestRideStopsAndGettingOff, TestRideWithoutFillersStillHasDestination M6: varje minispel är deterministiskt per seed; fel knapp straffar, sedlar rinner tillbaka; taxor och råd; zon och försök; kliva av rätt/fel/förbi; fel tåg saknar resmålet
internal/sim TestWalletPayTopUpAndPhone Kort, kontanter, påfyllning, spenderat, batteri gör kortet i telefonen oanvändbart
internal/sim TestTopUpFlowAtMachine, TestTicketLevelFlow, TestCrowdFailureMissesTrain Tomt kort → automaten → påfyllning → spärren släpper; hela bana 002 headless med fel/rätt biljett, trängsel och resa; två bom = missat tåg
internal/sim TestPhoneSpeedRescanAndBattery, TestRideWrongOrMissedStopLoses Fartbuff, seedad omskanning som fryser spelaren, dött batteri stoppar spärren; fel station / åka förbi förlorar
internal/sim TestDebuffEffectsAndProfile M7: varje debuff påverkar något, kombineras multiplikativt, profilen förlänger i stället för dubblerar och räknar ned per bana
internal/sim TestTimeLimitAndMissedTrainsLose, TestScoreBreakdown Tidsgräns och maxantal missade tåg förlorar banan (001 har inga gränser); poängformeln och avdragen
internal/sim TestDebuffsAffectRunAndAreEarned Skoskav/matförgiftning/hunger sänker fart, snabbar mätare och förlänger hjälptiden; många steg, lång tid och tom matmätare ger debuffar
internal/sim TestIndividualCardsAtGateAndMachine, TestLevel003Flow Egna kort: spärren kräver allas saldo, automaten frågar vems kort, spärren drar från alla; hela bana 003 headless med biljetter åt alla, sittplatser, trängsel och resa
internal/minigame TestTopUpPicksMemberWithIndividualCards, TestSeatSelectionPreferences Personval och 2×2-rutnät; seedade önskemål, upptagna platser, missnöje, fönster/gång/sida/bredvid, Esc avbryter köpet
internal/level TestSchedulePhases, TestScheduleValidationForPhases, TestTrackTile M7b: faserna away→approaching→arriving→dwelling→closing→leaving ur tidtabellen, ombordstigning bara med öppna dörrar, Status och Phase konsekventa; för korta uppehåll/borta-tider avvisas; rälsrutan
internal/sim TestNearTrackAndPhases Närmaste perrong inom två rutor, inte tre; under inrullningen syns tåget men man kan inte kliva på; med öppna dörrar kan man
internal/progress TestShippedCatalogAndThirdRule, TestCatalogValidation M8: katalogerna parsar och validerar; billigaste tredjedelen av items kostar mer än startkassan; banornas belöningar/butiker pekar på riktiga items
internal/progress TestXPLevelsAndSkillPoints, TestSkillTreeRequirementsAndCost Nivåtrösklar, skillpoäng per level-up, krav och kostnad, effekter multipliceras
internal/progress TestItemsBuyEquipAndEffects, TestLevelRecordsAndUnlocking Köp, bär/ta av, en per plats, tint, genvägar; bästa resultat behålls, upplåsning av huvud- och sidobanor
internal/save TestRoundTrip, TestCorruptAndFutureVersions, TestDefaultPath Skriv → läs ger samma tillstånd inkl. seed; trasig/nyare fil ger fel; version 0 migreras
internal/sim TestRunOptionsFromProgression Extra stats, sikt, landmärken, gratis spärrar, hela kartan, powerbank
internal/minigame TestCrowdLuckWidensZone Tur gör zonen bredare, otur smalare, klampat
internal/level TestFloorsStairsAndPaths, TestFloorsValidation M9a: flera våningar läses, trappor länkar, BFS-vägen byter våning bara via trappa, spärregeln och skyltar per våning; trappa utan motpart, olika storlekar, grid+floors och fel våning avvisas
internal/sim TestStairsMoveBetweenFloors Att kliva på trappan flyttar spelaren en våning, dimman lättar runt andra änden, perrongen hörs bara på egen våning, boten går hela vägen över våningar
internal/level TestCarsWomenOnlyAndCrowdFields M9b: vagnar, kvinnovagnens tidsfönster, crowd/clutter/noise 0–3, filrutor
internal/nav TestJudge, TestTooFarOnLongLoop, TestStopsRoutesAndNames, TestValidation, TestShippedNetwork M9: rätt/fel håll/för långt/ingen trafik på raka linjer och ringlinjer, stationer i färdriktningen, giltiga vägar sorterade, nätets validering, det riktiga nätets förutsättningar för banorna
internal/level TestAnnotateWithNetwork, TestPlatformTilesAndShippedVerdicts M9: correct räknas ut från nätet, felaktiga kopplingar ger fel, okopplade banor orörda; perrongtecknen P p Q q R r; 005/006 får väntade bedömningar
internal/sim TestNetworkRideUsesRealStops, TestWrongDirectionLoses, TestTooFarLoses, TestSignsModeBonus, TestTerminalLines M9: resan visar linjens riktiga stationer med resmålet på rätt plats; fel håll och för långt bort förlorar med rätt orsak; skyltläget ger +50 %; terminalen listar linjer med grannstationer
internal/lang TestNetworkNamesInDictionary M9: alla stations- och linjenamn i nätet finns i ordboken
internal/minigame TestCarPickAlightingAndChoice, TestCrowdLevelNarrowsZone, TestRideCrowdLetPass Folk av först (för tidigt räknas), seedad trängsel med minst en lugn vagn, val; trängsel smalnar zonen; resan: kortare tid per station, passagerare som vill förbi, blockerade räknas
internal/sim TestNPCsWanderStayOnFloorAndBlockPlayer, TestAlightingNPCsSpawnAndLeave Folk rör sig på golv, seedat, blockerar spelaren; avstigande spawnar när dörrarna öppnas och lämnar via utgången
internal/sim TestLanesSlowWrongSide, TestCarsWomenOnlyEarlyAndCrowd Fel sida i filen bromsar; kvinnovagn med man ger grova minus, för tidigt ombord räknas, resan ärver vagnens trängsel, lugn vagn ger bonus
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, engelska-andel, ordbokens fullständighet och täckning, hjälptid – finns, se tabellen ovan
M4 Lämmeltåget ✓ Mätare, händelsefrekvens efter gruppstorlek, seedade händelser – finns, se tabellen ovan
M5 Minikarta ✓ Upptäckta rutor, nollställning per bana, avgångar från start – finns, se tabellen ovan
M6 Kort/biljetter/minispel ✓ Saldo, automat, biljetter, omskanning, batteri – finns, se tabellen ovan
M7 Svårighet/poäng/debuffs ✓ Poäng, tidsgräns, debuffar, egna kort, sittplatsval – finns, se tabellen ovan
M7b Tåg som kommer och går ✓ Faser, ombordstigning, indikatoravstånd – finns, se tabellen ovan; ljud och animation verifieras manuellt/med skärmdumpar
M9b Folk, reklam, ljudröra, vagnar ✓ NPC:er, filer, röra, vagnval – finns, se tabellen ovan (bot med folk: testerna tömmer folket där det skulle störa, "fler NPC:er = längre tid" mäts manuellt)
M8 Progression & sparfil ✓ Round-trip, skillkrav, upplåsningar, 33 %-regeln – finns, se tabellen ovan
M9a Flera våningar ✓ Trappor, vägar över våningar, dimma per våning, gamla banor oförändrade – finns, se tabellen ovan
M9 Navigeringslägen ✓ Nätets bedömningar (rätt/fel håll/för långt/ingen trafik), 1–4 rätta tåg, riktiga stationer på resan, fel-håll- och för-långt-förlust, skyltbonus, terminal – finns, se tabellen ovan
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

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