make turnout description more clear. fix curves from breaking running track.
This commit is contained in:
@@ -23,6 +23,7 @@ import {
|
||||
allReachable,
|
||||
canDropCarsAt,
|
||||
canPlaceAt,
|
||||
carriesThroughTrack,
|
||||
exitsFrom,
|
||||
hasPort,
|
||||
neighbour,
|
||||
@@ -803,3 +804,100 @@ describe('Operational Rail — where a train may stop and leave cars (Appendix A
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
describe('the Running Track must stay a through route', () => {
|
||||
const runningArea = (): OfficeArea =>
|
||||
areaFrom(
|
||||
{
|
||||
[coordKey(at(0, -1))]: straight(),
|
||||
[coordKey(at(0, 0))]: officeCard(),
|
||||
[coordKey(at(0, 1))]: straight(),
|
||||
},
|
||||
at(0, 0),
|
||||
);
|
||||
|
||||
it('refuses a curve in the running row, which would dead-end the main', () => {
|
||||
// A curve has ONE road — from an east or west edge round to a 45° leg — so a card of it standing
|
||||
// in the Running Track stops the main dead at that square, cutting the Office off from its own
|
||||
// Limits. Every other card that may stand there carries an east-west road across it.
|
||||
const area = runningArea();
|
||||
for (const arc of ['ne', 'nw', 'se', 'sw'] as TrackArc[]) {
|
||||
assert.ok(!carriesThroughTrack(curve(arc)), `a ${arc} curve has no through road`);
|
||||
assert.ok(!canPlaceAt(area, at(0, 2), curve(arc)), `a ${arc} curve must not go in the Running Track`);
|
||||
}
|
||||
});
|
||||
|
||||
it('still accepts everything that does carry the road through', () => {
|
||||
const area = runningArea();
|
||||
assert.ok(carriesThroughTrack(straight()));
|
||||
assert.ok(carriesThroughTrack(turnout({ stem: 'w', through: 'e', diverge: 's' })));
|
||||
assert.ok(carriesThroughTrack(officeCard()));
|
||||
assert.ok(canPlaceAt(area, at(0, 2), straight()), 'a straight extends the main');
|
||||
assert.ok(
|
||||
canPlaceAt(area, at(0, 2), turnout({ stem: 'w', through: 'e', diverge: 's' })),
|
||||
'a turnout keeps the road AND opens a leg — which is why a district hangs off one',
|
||||
);
|
||||
});
|
||||
|
||||
it('leaves a curve free to go anywhere off the main', () => {
|
||||
const area = areaFrom(
|
||||
{
|
||||
[coordKey(at(0, 0))]: officeCard(),
|
||||
[coordKey(at(0, 1))]: turnout({ stem: 'w', through: 'e', diverge: 's' }),
|
||||
},
|
||||
at(0, 0),
|
||||
);
|
||||
assert.ok(canPlaceAt(area, at(-1, 1), curve('ne')), 'the siding is exactly where a curve belongs');
|
||||
});
|
||||
});
|
||||
|
||||
describe('a turnout may be laid to face another, making a crossover', () => {
|
||||
/** A turnout stated the way the cards read: who may come in, and where they may go. */
|
||||
const facing = (stem: Port, through: Port, diverge: Port, hand: 'left' | 'right'): TrackCard => ({
|
||||
geometry: { kind: 'track', geometry: 'turnout', turnout: { stem, through, diverge }, hand },
|
||||
baseOperationalRail: false, standing: [], facility: null, modifiers: [], enhancements: [],
|
||||
});
|
||||
|
||||
it('joins a south-diverging turnout to the north-diverging one beneath it', () => {
|
||||
// "Traffic from the east to travel west or turn to the south", with directly beneath it "traffic
|
||||
// from the west to travel east or turn to the north". The two 45° legs are one continuous rail
|
||||
// across the card edge — a crossover, and the way a siding gets a track parallel to the main.
|
||||
const above = facing('e', 'w', 's', 'right');
|
||||
const below = facing('w', 'e', 'n', 'right');
|
||||
assert.ok(joins(above, 's', below), 'the crossover does not join');
|
||||
|
||||
// And its mirror, which is the same move built from the other hand.
|
||||
const aboveL = facing('w', 'e', 's', 'left');
|
||||
const belowL = facing('e', 'w', 'n', 'left');
|
||||
assert.ok(joins(aboveL, 's', belowL), 'the mirrored crossover does not join');
|
||||
});
|
||||
|
||||
it('refuses the pair whose legs lie on opposite diagonals', () => {
|
||||
// Both cards have the port and both legs meet the same point on the shared edge. They still form
|
||||
// a V: one descends to the right and the other to the left.
|
||||
assert.ok(!joins(facing('e', 'w', 's', 'right'), 's', facing('e', 'w', 'n', 'left')));
|
||||
assert.ok(!joins(facing('w', 'e', 's', 'left'), 's', facing('w', 'e', 'n', 'right')));
|
||||
});
|
||||
|
||||
it('lets a crew run down the crossover onto the parallel track', () => {
|
||||
// The point of building one: the lower turnout carries its own east-west road, so the siding
|
||||
// runs alongside the main rather than dead-ending under it.
|
||||
const area = areaFrom(
|
||||
{
|
||||
[coordKey(at(0, -1))]: straight(),
|
||||
[coordKey(at(0, 0))]: facing('w', 'e', 's', 'left'),
|
||||
[coordKey(at(0, 1))]: straight(),
|
||||
// Coming down the leg, the lower turnout is entered through its diverging north end, so the
|
||||
// only way on is its stem — east, along the parallel track.
|
||||
[coordKey(at(-1, 0))]: facing('e', 'w', 'n', 'left'),
|
||||
[coordKey(at(-1, 1))]: straight(),
|
||||
},
|
||||
at(0, 5),
|
||||
);
|
||||
const dests = reachableDestinations(ctxFor(area), at(0, -1), 'e');
|
||||
assert.ok(has(dests, -1, 1), 'a crew cannot reach the parallel track through the crossover');
|
||||
assert.ok(!has(dests, -1, 0), 'and may not stop on the turnout itself');
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user