Expand game engine, replay, tests, and documentation
This commit is contained in:
+26
-13
@@ -16,6 +16,7 @@
|
||||
*/
|
||||
|
||||
import { MAX_CONSIST } from './content.ts';
|
||||
import type { TrackGeometry } from './content.ts';
|
||||
import type {
|
||||
GridCoord,
|
||||
OfficeArea,
|
||||
@@ -78,15 +79,19 @@ type PortPair = readonly [Port, Port];
|
||||
*/
|
||||
function connectionsFor(card: TrackCard): readonly PortPair[] {
|
||||
switch (card.geometry.kind) {
|
||||
// A Modifier is not track: nothing connects to it and no train may enter (§9).
|
||||
case 'modifier':
|
||||
return [];
|
||||
case 'limits':
|
||||
return [['e', 'w']];
|
||||
case 'facility':
|
||||
return card.geometry.axis === 'ns' ? [['n', 's']] : [['e', 'w']];
|
||||
// Q7 — the card art draws the through-track along the TOP edge with everything diverging
|
||||
// downward, so a district is a Running Track with all Secondary Track hanging beneath it.
|
||||
// This supersedes Gap 8's north-and-south stubs.
|
||||
case 'office':
|
||||
return [
|
||||
['e', 'w'],
|
||||
['e', 'n'],
|
||||
['w', 'n'],
|
||||
['e', 's'],
|
||||
['w', 's'],
|
||||
];
|
||||
@@ -102,12 +107,17 @@ function connectionsFor(card: TrackCard): readonly PortPair[] {
|
||||
[o.stem, o.diverge],
|
||||
];
|
||||
}
|
||||
case 'runAround': {
|
||||
const b = card.geometry.bypass ?? 'n';
|
||||
// A CURVE joins the through track to one diverging side — handedness is printed on the
|
||||
// card, not chosen (the design supplies both hands). A SHARP curve is geometrically the
|
||||
// same but costs two Moves to cross.
|
||||
// Curves and turnouts diverge DOWNWARD from the through track (Q7); handedness decides
|
||||
// which end of the through track the leg leaves from, not whether it goes up or down.
|
||||
case 'curved':
|
||||
case 'sharpCurved': {
|
||||
const stem = card.geometry.hand === 'left' ? 'w' : 'e';
|
||||
return [
|
||||
['e', 'w'],
|
||||
['e', b],
|
||||
['w', b],
|
||||
[stem, 's'],
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -139,23 +149,26 @@ export type TrackVariant = {
|
||||
bypass?: Port;
|
||||
};
|
||||
|
||||
/**
|
||||
* Q7 — everything diverges downward, so a turnout's leg is always south. Handedness (printed on
|
||||
* the card) decides which end of the through track it leaves from.
|
||||
*/
|
||||
const TURNOUT_VARIANTS: readonly TurnoutOrientation[] = [
|
||||
{ stem: 'e', through: 'w', diverge: 'n' },
|
||||
{ stem: 'e', through: 'w', diverge: 's' },
|
||||
{ stem: 'w', through: 'e', diverge: 'n' },
|
||||
{ stem: 'w', through: 'e', diverge: 's' },
|
||||
{ stem: 'n', through: 's', diverge: 'e' },
|
||||
{ stem: 's', through: 'n', diverge: 'w' },
|
||||
];
|
||||
|
||||
export function variantsFor(geometry: 'straight' | 'turnout' | 'runAround'): TrackVariant[] {
|
||||
export function variantsFor(geometry: TrackGeometry): TrackVariant[] {
|
||||
switch (geometry) {
|
||||
case 'straight':
|
||||
return [{ axis: 'ew' }, { axis: 'ns' }];
|
||||
case 'turnout':
|
||||
return TURNOUT_VARIANTS.map((t) => ({ turnout: t }));
|
||||
case 'runAround':
|
||||
return [{ bypass: 'n' }, { bypass: 's' }];
|
||||
case 'curved':
|
||||
case 'sharpCurved':
|
||||
// Handedness is printed on the card, and the leg always goes down (Q7), so nothing is left
|
||||
// to choose — one variant.
|
||||
return [{ axis: 'ew' }];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user