All checks were successful
release / build-release (push) Successful in 1m34s
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>
129 lines
4.5 KiB
Go
129 lines
4.5 KiB
Go
package sim
|
||
|
||
import (
|
||
"strings"
|
||
"testing"
|
||
|
||
"gitea.brasse-pc.eu/brasse/metro-puzzle-jp/internal/level"
|
||
"gitea.brasse-pc.eu/brasse/metro-puzzle-jp/internal/minigame"
|
||
"gitea.brasse-pc.eu/brasse/metro-puzzle-jp/internal/nav"
|
||
"gitea.brasse-pc.eu/brasse/metro-puzzle-jp/internal/rng"
|
||
)
|
||
|
||
// boardAt går till perrongen med tecknet tile, väntar in tåget, kliver på
|
||
// och väljer vagn; resan pågår när funktionen återvänder.
|
||
func boardAt(t *testing.T, r *Run, tile level.Tile) *level.Train {
|
||
t.Helper()
|
||
r.NPCs = nil // folket ska inte stå i vägen för testboten
|
||
r.Party.nextEventAt = 1e9
|
||
l := r.Level
|
||
path := l.Path(r.Player.Tile, l.Find(tile)[0], r.PathCanEnter)
|
||
if path == nil {
|
||
t.Fatalf("ingen väg till perrong %c", tile)
|
||
}
|
||
walk(t, r, path)
|
||
tr := waitForTrain(t, r)
|
||
r.Step(frame, None, true)
|
||
if r.MiniKind == MiniCarPick {
|
||
pickCar(t, r)
|
||
}
|
||
if r.MiniKind != MiniRide {
|
||
t.Fatalf("ingen tågresa (kind=%v)", r.MiniKind)
|
||
}
|
||
return tr
|
||
}
|
||
|
||
// TestNetworkRideUsesRealStops: på nätkopplade banor är tågresans stationer
|
||
// linjens riktiga stationer i färdriktningen, med resmålet på rätt plats.
|
||
func TestNetworkRideUsesRealStops(t *testing.T) {
|
||
l := loadLevel(t, "005-ueno")
|
||
if l.Net == nil {
|
||
t.Fatal("005 ska vara kopplad till nätet")
|
||
}
|
||
r := NewRun(l, RunOptions{Seed: rng.FromInt(5)})
|
||
tr := boardAt(t, r, level.Platform)
|
||
g := r.Mini.(*minigame.Ride)
|
||
if tr.Verdict != nav.Direct || g.Dest != 1 || g.Stops[0] != "御徒町" || g.Stops[1] != "秋葉原" || len(g.Stops) != l.RideStops {
|
||
t.Fatalf("Yamanote från Ueno: dest=%d stops=%v", g.Dest, g.Stops)
|
||
}
|
||
ride(t, r)
|
||
if r.Outcome != Won {
|
||
t.Fatalf("outcome=%v (%s)", r.Outcome, r.LostReason)
|
||
}
|
||
}
|
||
|
||
// TestWrongDirectionLoses: Keihin-Tohoku mot Omiya från Ueno går åt fel håll
|
||
// – resan visar stationerna norrut, resmålet kommer aldrig och banan förloras
|
||
// med orsaken "fel håll".
|
||
func TestWrongDirectionLoses(t *testing.T) {
|
||
l := loadLevel(t, "005-ueno")
|
||
r := NewRun(l, RunOptions{Seed: rng.FromInt(5)})
|
||
tr := boardAt(t, r, level.WrongPlatform)
|
||
g := r.Mini.(*minigame.Ride)
|
||
if tr.Verdict != nav.WrongDirection || g.Dest != -1 || g.Stops[0] != "鶯谷" {
|
||
t.Fatalf("Keihin-Tohoku mot Omiya: verdict=%v dest=%d stops=%v", tr.Verdict, g.Dest, g.Stops)
|
||
}
|
||
ride(t, r)
|
||
if r.Outcome != Lost || r.LostReason != LostWrongDirection {
|
||
t.Fatalf("outcome=%v reason=%q", r.Outcome, r.LostReason)
|
||
}
|
||
}
|
||
|
||
// TestTooFarLoses: Marunouchi från Ikebukuro når Shinjuku först via city –
|
||
// för långt bort.
|
||
func TestTooFarLoses(t *testing.T) {
|
||
l := loadLevel(t, "006-ikebukuro")
|
||
r := NewRun(l, RunOptions{Seed: rng.FromInt(6)})
|
||
if n := r.NextTrains(); len(n) != 2 {
|
||
t.Fatalf("006 ska ha två rätta tåg, har %d", len(n))
|
||
}
|
||
tr := boardAt(t, r, level.Platform3)
|
||
if tr.Verdict != nav.TooFar || tr.LineID != "marunouchi" {
|
||
t.Fatalf("q-perrongen: %v %s", tr.Verdict, tr.LineID)
|
||
}
|
||
ride(t, r)
|
||
if r.Outcome != Lost || r.LostReason != LostTooFar {
|
||
t.Fatalf("outcome=%v reason=%q", r.Outcome, r.LostReason)
|
||
}
|
||
}
|
||
|
||
// TestSignsModeBonus: skyltläget ger 50 % bonus på grundpoängen, listläget inte.
|
||
func TestSignsModeBonus(t *testing.T) {
|
||
l := loadLevel(t, "001-flygplatsen")
|
||
list := NewRun(l, RunOptions{Seed: rng.FromInt(1)})
|
||
signs := NewRun(l, RunOptions{Seed: rng.FromInt(1), Mode: nav.Signs})
|
||
if list.Mode != nav.List || signs.Mode != nav.Signs {
|
||
t.Fatal("läget ska följa RunOptions")
|
||
}
|
||
for _, r := range []*Run{list, signs} {
|
||
r.Time = 30
|
||
r.computeScore()
|
||
}
|
||
base := list.Score.Time + list.Score.Money + list.Score.Meters + list.Score.Explore + list.Score.Car
|
||
if list.Score.Bonus != 0 || signs.Score.Bonus != base*ScoreSignsBonusPct/100 || signs.Score.Total != list.Score.Total+signs.Score.Bonus {
|
||
t.Fatalf("list=%+v signs=%+v", list.Score, signs.Score)
|
||
}
|
||
if n := list.NextTrains(); len(n) != 1 || !n[0].Correct {
|
||
t.Fatalf("NextTrains=%v", n)
|
||
}
|
||
}
|
||
|
||
// TestTerminalLines: terminalen listar linjerna vid stationen med grannstationer.
|
||
func TestTerminalLines(t *testing.T) {
|
||
r := NewRun(loadLevel(t, "005-ueno"), RunOptions{Seed: rng.FromInt(5)})
|
||
lines := r.TerminalLines()
|
||
if len(lines) < 3 {
|
||
t.Fatalf("Ueno har flera linjer, fick %v", lines)
|
||
}
|
||
joined := strings.Join(lines, "\n")
|
||
for _, want := range []string{"山手線: ", "御徒町", "鶯谷", "← 上野 →", "京浜東北線"} {
|
||
if !strings.Contains(joined, want) {
|
||
t.Errorf("terminalen saknar %q:\n%s", want, joined)
|
||
}
|
||
}
|
||
plain := NewRun(loadLevel(t, "002b-kabukicho"), RunOptions{Seed: rng.FromInt(1)})
|
||
if plain.TerminalLines() != nil || plain.Level.Net != nil {
|
||
t.Fatal("okopplad bana har ingen terminal")
|
||
}
|
||
}
|