M10d: toaletter innanför och utanför spärrarna
All checks were successful
release / build-release (push) Successful in 1m38s

Björns tillägg 2026-10-24. Generatorn har nu ett betalt område per perrong
(paidDepth) och toilets inside/outside/both: 005 Ueno och 008b Nippori har
toalett bara innanför, 007b Ueno på båda sidor. Perrongceller görs till
återvändsgränder (bara passagen mot starten behålls, labyrinten repareras)
och det betalda området krymper om det skulle bli genomfart; regeln att
varje perrong nås utan att passera ett annat betalt område testas i
level och levelcheck. level.PathOutside används av testbotar och shots.
Alla genererade banor utom 003 omgjorda, skärmdumpar omtagna.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
2026-10-24 23:09:27 +02:00
parent f04d6a88f9
commit 46bd330dfc
33 changed files with 419 additions and 209 deletions

View File

@@ -11,7 +11,7 @@ import (
// pathTo är testbotens väg till goal: som PathCanEnter, men andra perronger
// används inte som genvägar (på spärrar utan återvändo skulle man fastna).
func pathTo(r *Run, goal level.Point) []level.Point {
return r.Level.Path(r.Player.Tile, goal, func(p level.Point) bool {
return r.Level.PathOutside(r.Player.Tile, goal, func(p level.Point) bool {
return r.PathCanEnter(p) && (!r.Level.At(p).IsPlatform() || p == goal)
})
}
@@ -100,12 +100,22 @@ func TestOneWayGatesNeedStaff(t *testing.T) {
t.Fatalf("på perrongen ska man vara incheckad och ha betalat en gång: checkedIn=%v passes=%d card=%d", r.CheckedIn(), r.GatePasses, r.Wallet.Card)
}
card := r.Wallet.Card
stepUntilStill(r, Left) // tillbaka på spärren: kostar inget
// Tillbaka mot utgången: vägen till starten, kapad vid första spärren.
back := l.PathOutside(plat, l.SpawnPoint(), r.PathCanEnter)
gi := 0
for gi < len(back) && l.At(back[gi]) != level.Gate {
gi++
}
if gi >= len(back)-1 {
t.Fatal("ingen spärr på vägen ut")
}
walk(t, r, back[:gi+1]) // inifrån och ut på spärren: kostar inget
if !r.inGate() || r.GatePasses != 1 || r.Wallet.Card != card {
t.Fatalf("spärren igen: inGate=%v passes=%d card=%d", r.inGate(), r.GatePasses, r.Wallet.Card)
}
gate := r.Player.Tile
stepUntilStill(r, Left) // ut? nej
gate, outside := r.Player.Tile, back[gi+1]
out := dirTo(gate, outside)
stepUntilStill(r, out) // ut? nej
if r.Player.Tile != gate || r.NoExitAt < 0 {
t.Fatalf("spärren ska inte släppa ut: tile=%v noExitAt=%.1f", r.Player.Tile, r.NoExitAt)
}
@@ -119,15 +129,15 @@ func TestOneWayGatesNeedStaff(t *testing.T) {
if r.Staff.Active || !r.StaffUnlocked || r.StaffCalls != 1 || r.FlashKey != FlashStaff {
t.Fatalf("personalen ska ha låst upp: active=%v unlocked=%v calls=%d", r.Staff.Active, r.StaffUnlocked, r.StaffCalls)
}
stepUntilStill(r, Left)
if r.Player.Tile == gate || r.CheckedIn() || r.StaffUnlocked {
stepUntilStill(r, out)
if r.Player.Tile != outside || r.CheckedIn() || r.StaffUnlocked {
t.Fatalf("ute igen: tile=%v checkedIn=%v unlocked=%v", r.Player.Tile, r.CheckedIn(), r.StaffUnlocked)
}
stepUntilStill(r, Right) // på spärren utifrån: inget dras än
stepUntilStill(r, dirTo(outside, gate)) // på spärren utifrån: inget dras än
if !r.inGate() || r.CheckedIn() || r.GatePasses != 1 {
t.Fatalf("spärren utifrån: inGate=%v checkedIn=%v passes=%d", r.inGate(), r.CheckedIn(), r.GatePasses)
}
stepUntilStill(r, Right) // in igen: kostar igen
walk(t, r, pathTo(r, plat)) // in igen: kostar igen
if r.Player.Tile != plat || !r.CheckedIn() || r.GatePasses != 2 || r.Wallet.Card != card-l.FareYen {
t.Fatalf("ny inpassering: tile=%v checkedIn=%v passes=%d card=%d (var %d)", r.Player.Tile, r.CheckedIn(), r.GatePasses, r.Wallet.Card, card)
}