import { IMPOSSIBLE, VersionInfo } from '@start9labs/start-sdk' export const current = VersionInfo.of({ // `:` — the upstream half tracks the bundled Station Master tag exactly // (`versions.md`'s consistency checklist), so bumping the submodule pin and bumping this are one // action. The downstream half moves only for packaging-only changes, and RESETS to `:0` when the // upstream half moves. // // FOUR COMPONENTS IS FINE. ExVer's upstream half is an arbitrary-length dotted number, not semver // — checked against the SDK's own parser rather than assumed, since every example in `versions.md` // has three: `0.7.9.8:0` parses to upstream `[0,7,9,8]`, which sorts above `[0,7,9]`, so a box on // 0.7.9:0 sees this as an update rather than refusing it as a downgrade. version: '0.8.0.9:0', releaseNotes: { en_US: 'Bundles Station Master v0.8.0.9 — the bots play much better, and the server does its work ' + 'faster. GAMES IN PROGRESS ON THIS SERVER ARE UNAFFECTED and will resume normally: no rule ' + 'changed. A bot filling an empty seat now plans its whole switching turn before its first ' + 'move, so it delivers cars to industries that can work them instead of choosing one move at a ' + 'time, and it brings expedited trains back to the station. It no longer takes face-up cards ' + 'it cannot play only to throw them back, so it builds its district — more track, more ' + 'industries, and run-arounds far more often, because it now lays track where it opens up ' + 'something to do. And it no longer runs a Second Section by accident when it meant to start ' + 'an Extra, which caused many of its collisions. Measured over thousands of simulated games, a ' + 'bot now earns about 4.8 Revenue a game, where it earned about −0.3 before. Behind the ' + 'scenes, working out where a train can move is now done once per position instead of several ' + 'times, which makes the server about three times faster at checking moves — with play proven ' + 'identical.', es_ES: 'Incluye Station Master v0.8.0.9 — los bots juegan mucho mejor y el servidor trabaja más ' + 'rápido. LAS PARTIDAS EN CURSO EN ESTE SERVIDOR NO SE VEN AFECTADAS y se reanudarán con ' + 'normalidad: no ha cambiado ninguna regla. Un bot que ocupa un asiento vacío planifica ahora ' + 'su turno de maniobras completo antes de su primer movimiento, así que entrega vagones a las ' + 'industrias que pueden trabajarlos en lugar de decidir movimiento a movimiento, y devuelve ' + 'los trenes expresos a la estación. Ya no toma cartas descubiertas que no puede jugar solo ' + 'para volver a descartarlas, así que construye su distrito — más vía, más industrias y vías ' + 'de circunvalación mucho más a menudo, porque ahora tiende vía donde abre algo que hacer. Y ' + 'ya no lanza una Segunda Sección por accidente cuando quería poner en marcha un Extra, lo que ' + 'causaba muchas de sus colisiones. Medido en miles de partidas simuladas, un bot gana ahora ' + 'unos 4,8 de Ingresos por partida, frente a unos −0,3 antes. Por dentro, calcular adónde ' + 'puede moverse un tren se hace ahora una vez por posición en lugar de varias, lo que hace al ' + 'servidor unas tres veces más rápido al comprobar movimientos — con el juego demostrado ' + 'idéntico.', de_DE: 'Enthält Station Master v0.8.0.9 — die Bots spielen deutlich besser, und der Server arbeitet ' + 'schneller. LAUFENDE SPIELE AUF DIESEM SERVER SIND NICHT BETROFFEN und werden normal ' + 'fortgesetzt: Keine Regel hat sich geändert. Ein Bot auf einem freien Platz plant jetzt ' + 'seinen ganzen Rangierzug, bevor er sich zum ersten Mal bewegt, und stellt Wagen daher bei ' + 'Industrien zu, die sie bearbeiten können, statt Zug um Zug zu entscheiden; beschleunigte ' + 'Züge bringt er zum Bahnhof zurück. Er nimmt keine offenen Karten mehr, die er nicht spielen ' + 'kann, nur um sie wieder abzuwerfen, und baut deshalb seinen Bezirk aus — mehr Gleis, mehr ' + 'Industrien und viel öfter Umfahrgleise, weil er Gleis jetzt dort legt, wo es etwas zu tun ' + 'eröffnet. Und er setzt keinen zweiten Zugteil (Second Section) mehr aus Versehen ein, wenn ' + 'er einen Sonderzug starten wollte, was viele seiner Zusammenstöße verursachte. Über Tausende ' + 'simulierter Spiele gemessen, erzielt ein Bot jetzt etwa 4,8 Einnahmen pro Spiel, vorher etwa ' + '−0,3. Im Hintergrund wird jetzt einmal pro Stellung statt mehrfach berechnet, wohin ein Zug ' + 'fahren kann, was den Server beim Prüfen von Zügen etwa dreimal schneller macht — bei ' + 'nachweislich identischem Spielverlauf.', pl_PL: 'Zawiera Station Master v0.8.0.9 — boty grają znacznie lepiej, a serwer pracuje szybciej. GRY ' + 'W TOKU NA TYM SERWERZE NIE SĄ ZAGROŻONE i zostaną normalnie wznowione: żadna zasada się nie ' + 'zmieniła. Bot zajmujący wolne miejsce planuje teraz całą swoją turę manewrów przed pierwszym ' + 'ruchem, więc dostarcza wagony do zakładów, które mogą je obsłużyć, zamiast decydować ruch po ' + 'ruchu, i odprowadza pociągi przyspieszone z powrotem na stację. Nie bierze już odkrytych ' + 'kart, których nie może zagrać, tylko po to, by je odrzucić, więc rozbudowuje swój okręg — ' + 'więcej torów, więcej zakładów i znacznie częściej tory objazdowe, bo kładzie teraz tor tam, ' + 'gdzie otwiera to coś do zrobienia. I nie uruchamia już przez przypadek Drugiej Sekcji, gdy ' + 'chciał wypuścić pociąg dodatkowy, co powodowało wiele jego zderzeń. Zmierzone w tysiącach ' + 'symulowanych gier: bot zarabia teraz około 4,8 Przychodu na grę, wcześniej około −0,3. W tle ' + 'to, dokąd pociąg może pojechać, jest teraz liczone raz na pozycję zamiast kilka razy, co ' + 'czyni serwer około trzy razy szybszym przy sprawdzaniu ruchów — przy udowodnionym ' + 'identycznym przebiegu gry.', fr_FR: 'Inclut Station Master v0.8.0.9 — les bots jouent beaucoup mieux, et le serveur travaille ' + 'plus vite. LES PARTIES EN COURS SUR CE SERVEUR NE SONT PAS AFFECTÉES et reprendront ' + 'normalement : aucune règle n’a changé. Un bot qui occupe une place libre planifie désormais ' + 'tout son tour de manœuvres avant son premier mouvement, si bien qu’il livre les wagons aux ' + 'industries capables de les traiter au lieu de décider coup par coup, et il ramène les trains ' + 'accélérés en gare. Il ne prend plus de cartes face visible qu’il ne peut pas jouer pour les ' + 'défausser aussitôt, donc il développe son district — plus de voie, plus d’industries et bien ' + 'plus souvent des voies d’évitement, parce qu’il pose désormais la voie là où elle ouvre ' + 'quelque chose à faire. Et il ne lance plus une Deuxième Section par erreur quand il voulait ' + 'faire partir un train supplémentaire, ce qui causait beaucoup de ses collisions. Mesuré sur ' + 'des milliers de parties simulées, un bot gagne maintenant environ 4,8 de Revenu par partie, ' + 'contre environ −0,3 auparavant. En coulisses, le calcul des endroits où un train peut aller ' + 'se fait désormais une fois par position au lieu de plusieurs, ce qui rend le serveur environ ' + 'trois fois plus rapide pour vérifier les coups — avec un jeu prouvé identique.', }, migrations: { /** * NOTHING TO CARRY, AND CHECKED THE SAME NARROW WAY v0.7.9.8's ENTRY WAS. * * The rule this package lives by is in the game's README: a save is a seed plus the moves * played, replayed through the CURRENT rules, so the only thing that strands an older save is a * change that makes a once-legal move illegal. So the question is never "how big was the * release" — v0.8.0 is a large one — but "did any predicate change its answer". * * Measured with `git diff v0.7.9.8..v0.8.0.1 -- src/engine/`. The WHOLE engine diff is eight * lines: * four `GameEvent` types (`trayMoved`, `carsCoupled`, `carsDropped`, `consistSorted`) gained a * `player` field, and the four places that build them pass it. `check()` is untouched, `legal.ts` * and `advance.ts` are untouched, and no predicate anywhere was edited. Games in progress resume, * and the release notes say so in all five locales rather than leaving it to be discovered. * * EVENTS ARE NOT PERSISTED, so widening four of them cannot invalidate anything on disk: a * `SavedGame` is `{ seed, config, history: Intent[], … }` and the events are derived by replaying * it. The narration TEXT of two lines changed with them ("Moved Train 3 …" where it used to read * "CREW moved …"), which a resumed game simply regenerates — the log is not stored either. * * WHAT IS NOT COVERED BY THAT ARGUMENT, and why it still does not need a migration: the wire * between this server and a browser gained a lot. `Push` now carries ordered presentation steps * and a public-board baseline, and the board deltas changed shape. None of it is on disk, and a * browser reloads onto the new page as part of the update, so there is no version skew to * migrate — the same reasoning v0.7.9.8 used for its own `Frame` changes. * * v0.8.0.1 ADDED NOTHING TO THIS ARGUMENT: `git diff v0.8.0..v0.8.0.1 -- src/engine/` is empty. * It changed `sim/pacing.ts`, `web/step-queue.ts` and `web/main.ts` — how long a step is shown * and when the queue calls itself idle — which is presentation and touches neither the rules nor * anything on disk. * * v0.8.0.2 DOES TOUCH THE ENGINE, and it is worth being exact about why that is still nothing to * migrate. `git diff v0.8.0.1..v0.8.0.2 -- src/engine/` is three added lines: `collisionsPrevDay` * declared on `GameState`, initialised to 0 in `setup.ts`, and assigned at the Day rollover in * `advance.ts`. It is a counter that nothing checks — no predicate reads it, so no once-legal move * became illegal. * * v0.8.0.3 THROUGH v0.8.0.7 ADDED NOTHING: `git diff v0.8.0.2..v0.8.0.7 -- src/engine/` is empty. * One moved the Skip button, changed what the waiting row says, and stopped the speed control * stretching the clock; one took a hostname out of comments; the last drew the Home Office deck * and lit the pile a watched move touched, which is a diff of two frames the client already * holds. None of it is a rule, and none of it is on disk. * * v0.8.0.8 IS DIFFERENT AND IS THE ONE TO READ CAREFULLY: it changes a RULE (Gitea#23). When the * Home Office deck is reshuffled, a timetabled train sitting in the SALVAGE YARD is no longer * recovered — it was played, its number is on the timetable, and it cannot be run twice. The same * card in a DEPARTMENT was discarded rather than played and still comes back, as does any Extra. * A duplicate went with it: `trainScheduled` had been pushing a synthetic `train-` beside the * real card, so four scheduled trains left eight entries in a pile of four. * * GAMES IN PROGRESS STILL RESUME, and the reason is the narrow one this package always asks * (README § Design notes): a save is a seed plus the moves played, replayed through the CURRENT * rules, so what strands one is a change that makes a once-legal move ILLEGAL. Nothing here does. * `check()` is untouched; a draw is a draw whatever lies on top of the deck. What differs is the * Salvage Yard's depth, which was double-counting, and which cards a reshuffle returns — and a * reshuffle is effectively unreachable in ordinary play: eight games driven to 4000 moves across * eight seeds produced ZERO. A game that had somehow reshuffled would replay to a different deck * order rather than refusing to replay, which is worth knowing and is not the same as breaking. * * v0.8.0.9 TOUCHES THE ENGINE FOR SPEED, AND PROVED IT CHANGED NOTHING. `git diff v0.8.0.8..v0.8.0.9 * -- src/engine/` adds a route cache scoped to one unchanged position (`withRouteCache`), splits * `applyIntent` into `prepareIntent` + `commitEvents`, trims allocation in `exploreMoves`, adds * `legalSwitchingActions`, and exports `badlyMadeUp`, `protoCard` and `extendLimitsIfNeeded` for the * bot. No predicate's answer changed: every event and intent of 32 seeded games hashed identical before * and after each step, and the game's `test/route-cache.test.ts` pins the split. Everything else is the * developer bot, whose past moves are already intents in a save. Games in progress resume. * * A NEW STATE FIELD CANNOT STRAND A SAVE HERE, which is the property worth naming rather than * re-deriving: a `SavedGame` holds `{ seed, config, history }` and NOT a serialised `GameState`. * Resuming calls `createGame` — which fills the new field from `setup.ts` — and then replays the * intents through the current rules, so the field is populated on the way past. There is no old * shape on disk for a new field to be missing from. * * THE ONE THING THAT WOULD HAVE NEEDED CARE, had it been built the way the plan first described: * the display-step collector runs inside `submit()`, and the resume path (`fromMultiplayerSave`) * deliberately does not go through `submit()`. So replaying a saved game emits no steps and burns * no sequence numbers. A test in the game pins that, because it is a property rather than an * accident. */ up: async ({ effects }) => {}, down: IMPOSSIBLE, }, })