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>
120 lines
3.7 KiB
Go
120 lines
3.7 KiB
Go
package minigame
|
||
|
||
import "gitea.brasse-pc.eu/brasse/metro-puzzle-jp/internal/rng"
|
||
|
||
// Ride är tågresan: stationerna passerar en i taget med "次は …"-utrop;
|
||
// tryck Enter vid ditt resmål. Fel station eller att åka förbi är misslyckat.
|
||
type Ride struct {
|
||
base
|
||
Stops []string // stationsnamn på japanska i ordning
|
||
Dest int // index för resmålet, -1 om det inte finns på linjen (fel tåg)
|
||
Index int // aktuell station
|
||
Timer float64 // sekunder kvar vid aktuell station
|
||
StopSec float64
|
||
GotOff int // index där spelaren klev av, -1 = inte än
|
||
|
||
// Trängsel: vid stationer där man inte ska av vill andra passagerare ut.
|
||
Crowd int // vagnens trängselnivå 0–2
|
||
WantsOut []bool // per station: någon vill förbi
|
||
LetPass bool // spelaren har släppt förbi vid aktuell station
|
||
Blocked int // stationer där ingen släpptes förbi (avdrag)
|
||
}
|
||
|
||
// Tid per station efter trängsel: 2,5 / 2,0 / 1,5 s.
|
||
const rideStopSec = 2.5
|
||
|
||
// RideStopSec är tiden per station för en trängselnivå.
|
||
func RideStopSec(crowd int) float64 { return rideStopSec - 0.5*float64(max(0, min(2, crowd))) }
|
||
|
||
// NewRide bygger linjen: fillers är andra stationsnamn (blandas), dest läggs
|
||
// på en seedad plats (aldrig först) om det är rätt tåg, annars utelämnas det.
|
||
// crowd (0–2) ger kortare tid per station och passagerare som vill förbi.
|
||
func NewRide(seed rng.Seed, dest string, fillers []string, stops int, correctTrain bool, crowd int) *Ride {
|
||
r := newRand(seed, "ride")
|
||
f := append([]string(nil), fillers...)
|
||
r.shuffle(len(f), func(i, j int) { f[i], f[j] = f[j], f[i] })
|
||
stops = max(2, stops)
|
||
di := -1
|
||
if correctTrain {
|
||
di = 1 + r.intn(stops-1)
|
||
}
|
||
var names []string
|
||
for i := 0; i < stops; i++ {
|
||
switch {
|
||
case i == di:
|
||
names = append(names, dest)
|
||
case len(f) > 0:
|
||
names = append(names, f[0])
|
||
f = f[1:]
|
||
default:
|
||
names = append(names, UnknownStop) // slut på namn: en namnlös station
|
||
}
|
||
}
|
||
return newRide(r, names, di, crowd)
|
||
}
|
||
|
||
// NewRideStops bygger resan av givna stationer i ordning (linjenätets
|
||
// riktiga stationer); dest är resmålets index, -1 om det inte kommer.
|
||
func NewRideStops(seed rng.Seed, stops []string, dest int, crowd int) *Ride {
|
||
r := newRand(seed, "ride")
|
||
if len(stops) < 2 {
|
||
stops = append(append([]string(nil), stops...), UnknownStop, UnknownStop)[:2]
|
||
}
|
||
if dest >= len(stops) {
|
||
dest = -1
|
||
}
|
||
return newRide(r, append([]string(nil), stops...), dest, crowd)
|
||
}
|
||
|
||
func newRide(r *randSrc, stops []string, dest int, crowd int) *Ride {
|
||
crowd = max(0, min(2, crowd))
|
||
sec := RideStopSec(crowd)
|
||
g := &Ride{StopSec: sec, Timer: sec, GotOff: -1, Dest: dest, Crowd: crowd, Stops: stops}
|
||
g.WantsOut = make([]bool, len(g.Stops))
|
||
chance := [...]float64{0, 0.4, 0.7}[crowd]
|
||
for i := range g.Stops {
|
||
if i != g.Dest && r.float() < chance {
|
||
g.WantsOut[i] = true
|
||
}
|
||
}
|
||
return g
|
||
}
|
||
|
||
// NeedsLetPass rapporterar om någon vill förbi vid aktuell station just nu.
|
||
func (g *Ride) NeedsLetPass() bool { return g.WantsOut[g.Index] && !g.LetPass }
|
||
|
||
// UnknownStop används när det inte finns fler stationsnamn att ta av.
|
||
const UnknownStop = "・・・"
|
||
|
||
// Current är stationen tåget står vid.
|
||
func (g *Ride) Current() string { return g.Stops[g.Index] }
|
||
|
||
// Update låter stationerna passera och tar emot "kliv av".
|
||
func (g *Ride) Update(in Input, dt float64) {
|
||
if g.done {
|
||
return
|
||
}
|
||
if in.Confirm {
|
||
g.GotOff = g.Index
|
||
g.done = true
|
||
g.success = g.Index == g.Dest
|
||
return
|
||
}
|
||
if in.MoveX < 0 && g.NeedsLetPass() {
|
||
g.LetPass = true // kliv åt sidan
|
||
}
|
||
g.Timer -= dt
|
||
if g.Timer <= 0 {
|
||
if g.NeedsLetPass() {
|
||
g.Blocked++
|
||
}
|
||
g.Index++
|
||
g.Timer = g.StopSec
|
||
g.LetPass = false
|
||
if g.Index >= len(g.Stops) {
|
||
g.Index = len(g.Stops) - 1
|
||
g.done = true // åkte till slutstationen utan att kliva av
|
||
}
|
||
}
|
||
}
|