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 := pathTo(r, l.Find(tile)[0]) 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") } }