Expand game engine, replay, tests, and documentation
This commit is contained in:
+30
-29
@@ -128,53 +128,54 @@ describe('ports and geometry', () => {
|
||||
it('joins a turnout stem to both legs but never the legs to each other', () => {
|
||||
// §A.1 — the whole point. Entering from the stem reaches either leg; entering from a leg
|
||||
// reaches only the stem. This is an ABSENT edge, not a one-way edge.
|
||||
const t = turnout({ stem: 'e', through: 'w', diverge: 'n' });
|
||||
assert.deepEqual(exitsFrom(t, 'e').sort(), ['n', 'w']);
|
||||
const t = turnout({ stem: 'e', through: 'w', diverge: 's' });
|
||||
assert.deepEqual(exitsFrom(t, 'e').sort(), ['s', 'w']);
|
||||
assert.deepEqual(exitsFrom(t, 'w'), ['e']);
|
||||
assert.deepEqual(exitsFrom(t, 'n'), ['e']);
|
||||
assert.deepEqual(exitsFrom(t, 's'), ['e']);
|
||||
});
|
||||
|
||||
it('lets a train traverse a turnout in both directions', () => {
|
||||
// A→B and B→A are both legal; only B↔C is missing.
|
||||
const t = turnout({ stem: 'e', through: 'w', diverge: 'n' });
|
||||
assert.ok(exitsFrom(t, 'e').includes('n'), 'stem to diverging leg');
|
||||
assert.ok(exitsFrom(t, 'n').includes('e'), 'diverging leg back to stem');
|
||||
const t = turnout({ stem: 'e', through: 'w', diverge: 's' });
|
||||
assert.ok(exitsFrom(t, 'e').includes('s'), 'stem to diverging leg');
|
||||
assert.ok(exitsFrom(t, 's').includes('e'), 'diverging leg back to stem');
|
||||
});
|
||||
|
||||
it('gives the Office card junction stubs above and below', () => {
|
||||
// Gap 8 — plain junctions, so unlike a turnout no pair is missing between track and stub.
|
||||
it('gives the Office card a junction stub BELOW only', () => {
|
||||
// Q7 — the card art draws the through-track along the top edge with everything diverging
|
||||
// downward, so a district grows beneath the Running Track. Supersedes Gap 8.
|
||||
const o = officeCard();
|
||||
for (const p of ['n', 's', 'e', 'w'] as Port[]) assert.ok(hasPort(o, p), `office port ${p}`);
|
||||
assert.ok(exitsFrom(o, 'n').includes('e'));
|
||||
assert.ok(exitsFrom(o, 'n').includes('w'));
|
||||
assert.ok(!exitsFrom(o, 'n').includes('s'), 'north must not cross to south');
|
||||
for (const p of ['s', 'e', 'w'] as Port[]) assert.ok(hasPort(o, p), `office port ${p}`);
|
||||
assert.ok(!hasPort(o, 'n'), 'nothing may attach above the Running Track');
|
||||
assert.ok(exitsFrom(o, 's').includes('e'));
|
||||
assert.ok(exitsFrom(o, 's').includes('w'));
|
||||
});
|
||||
|
||||
it('gives a run-around both ends of the loop', () => {
|
||||
// §A.5's facing-point move is impossible without one.
|
||||
it('joins a curve from one end of the through track downward', () => {
|
||||
// Curves come in left and right hands as distinct cards; the leg always goes DOWN (Q7), and
|
||||
// handedness decides which end of the through track it leaves from.
|
||||
const r: TrackCard = {
|
||||
geometry: { kind: 'track', geometry: 'runAround' },
|
||||
geometry: { kind: 'track', geometry: 'curved', hand: 'left' },
|
||||
baseOperationalRail: true,
|
||||
standing: [],
|
||||
facility: null,
|
||||
modifiers: [],
|
||||
};
|
||||
assert.deepEqual(exitsFrom(r, 'n').sort(), ['e', 'w']);
|
||||
assert.deepEqual(exitsFrom(r, 's'), ['w']);
|
||||
});
|
||||
});
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
describe('Move legality', () => {
|
||||
// row 1: [B n-s straight] <- must have a SOUTH port to meet the Office stub
|
||||
// row 0: [D] [E office ] [F]
|
||||
// row 0: [D] [E office ] [F] <- Running Track
|
||||
// row -1: [B n-s straight] <- Secondary Track hangs BELOW (Q7)
|
||||
const basicArea = (): OfficeArea =>
|
||||
areaFrom(
|
||||
{
|
||||
[coordKey(at(0, -1))]: straight(),
|
||||
[coordKey(at(0, 0))]: officeCard(),
|
||||
[coordKey(at(0, 1))]: straight(),
|
||||
[coordKey(at(1, 0))]: nsStraight(),
|
||||
[coordKey(at(-1, 0))]: nsStraight(),
|
||||
},
|
||||
at(0, 0),
|
||||
);
|
||||
@@ -190,7 +191,7 @@ describe('Move legality', () => {
|
||||
it('branches onto Secondary Track through the Office stub', () => {
|
||||
const area = basicArea();
|
||||
const dests = reachableDestinations(ctxFor(area), at(0, 1), 'w');
|
||||
assert.ok(has(dests, 1, 0), 'reaches the card north of the office');
|
||||
assert.ok(has(dests, -1, 0), 'reaches the card below the office');
|
||||
});
|
||||
|
||||
it('never reverses within a single Move', () => {
|
||||
@@ -209,19 +210,19 @@ describe('Move legality', () => {
|
||||
});
|
||||
|
||||
it('will not stop on a turnout', () => {
|
||||
// row 1: [C n-s straight]
|
||||
// row 0: [start] [turnout ]
|
||||
// row 0: [start] [turnout ]
|
||||
// row -1: [C n-s straight]
|
||||
const area = areaFrom(
|
||||
{
|
||||
[coordKey(at(0, 0))]: straight(),
|
||||
[coordKey(at(0, 1))]: turnout({ stem: 'w', through: 'e', diverge: 'n' }),
|
||||
[coordKey(at(1, 1))]: nsStraight(),
|
||||
[coordKey(at(0, 1))]: turnout({ stem: 'w', through: 'e', diverge: 's' }),
|
||||
[coordKey(at(-1, 1))]: nsStraight(),
|
||||
},
|
||||
at(0, 0),
|
||||
);
|
||||
const dests = reachableDestinations(ctxFor(area), at(0, 0), 'e');
|
||||
assert.ok(!has(dests, 0, 1), 'a turnout carries no wheel icon (§A.1)');
|
||||
assert.ok(has(dests, 1, 1), 'but a train may pass through it');
|
||||
assert.ok(has(dests, -1, 1), 'but a train may pass through it');
|
||||
});
|
||||
|
||||
it('will not stop on a facility whose track is locked by a load', () => {
|
||||
@@ -346,8 +347,8 @@ describe('placement and drop-off', () => {
|
||||
},
|
||||
at(0, 0),
|
||||
);
|
||||
assert.ok(canPlaceAt(area, at(1, 0), nsStraight()), 'north of the Office');
|
||||
assert.ok(canPlaceAt(area, at(-1, 0), nsStraight()), 'south of the Office');
|
||||
assert.ok(canPlaceAt(area, at(-1, 0), nsStraight()), 'below the Office');
|
||||
assert.ok(!canPlaceAt(area, at(1, 0), nsStraight()), 'nothing attaches above the Running Track');
|
||||
});
|
||||
|
||||
it('refuses a card whose ports do not meet the neighbour it touches', () => {
|
||||
@@ -361,7 +362,7 @@ describe('placement and drop-off', () => {
|
||||
},
|
||||
at(0, 0),
|
||||
);
|
||||
assert.ok(!canPlaceAt(area, at(1, 0), straight()), 'e-w straight cannot meet a n-s stub');
|
||||
assert.ok(!canPlaceAt(area, at(-1, 0), straight()), 'e-w straight cannot meet a n-s stub');
|
||||
});
|
||||
|
||||
it('refuses a card that connects to nothing', () => {
|
||||
|
||||
Reference in New Issue
Block a user