feat(game): add neon isometric relay interface
This commit is contained in:
@@ -0,0 +1,48 @@
|
||||
import test from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
|
||||
import { LEVELS, canReachTarget } from '../levels.js';
|
||||
import { parseLevel } from '../game-engine.js';
|
||||
|
||||
test('every authored relay has reachable signal pads before any echo is anchored', () => {
|
||||
for (const definition of LEVELS) {
|
||||
const level = parseLevel(definition.map);
|
||||
for (const [padId, position] of level.pads) {
|
||||
assert.equal(
|
||||
canReachTarget(level, position, new Set()),
|
||||
true,
|
||||
`${definition.id}: pad ${padId} should be initially reachable`,
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
test('each relay keeps extraction sealed until its full gate sequence is sustained', () => {
|
||||
for (const definition of LEVELS) {
|
||||
const level = parseLevel(definition.map);
|
||||
const allGates = new Set(level.gates.keys());
|
||||
|
||||
assert.equal(
|
||||
canReachTarget(level, level.goal, new Set()),
|
||||
false,
|
||||
`${definition.id}: extraction must not be reachable with all gates closed`,
|
||||
);
|
||||
assert.equal(
|
||||
canReachTarget(level, level.goal, allGates),
|
||||
true,
|
||||
`${definition.id}: extraction should be reachable with all gates active`,
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
test('multi-gate relays preserve their intended staged locks', () => {
|
||||
const double = parseLevel(LEVELS.find((level) => level.id === 'prism-drift').map);
|
||||
const triple = parseLevel(LEVELS.find((level) => level.id === 'cathedral-null').map);
|
||||
|
||||
assert.equal(canReachTarget(double, double.goal, new Set(['A'])), false);
|
||||
assert.equal(canReachTarget(double, double.goal, new Set(['A', 'B'])), true);
|
||||
|
||||
assert.equal(canReachTarget(triple, triple.goal, new Set(['A'])), false);
|
||||
assert.equal(canReachTarget(triple, triple.goal, new Set(['A', 'B'])), false);
|
||||
assert.equal(canReachTarget(triple, triple.goal, new Set(['A', 'B', 'C'])), true);
|
||||
});
|
||||
@@ -0,0 +1,22 @@
|
||||
import test from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
import { readFileSync } from 'node:fs';
|
||||
|
||||
const root = new URL('../', import.meta.url);
|
||||
const readProjectFile = (name) => readFileSync(new URL(name, root), 'utf8');
|
||||
|
||||
test('the playable shell uses a local canvas entry point and no external runtime assets', () => {
|
||||
const html = readProjectFile('index.html');
|
||||
|
||||
assert.match(html, /<canvas[^>]+id="relay-canvas"/);
|
||||
assert.match(html, /<script\s+type="module"\s+src="\.\/app\.js"><\/script>/);
|
||||
assert.match(html, /data-action="anchor"/);
|
||||
assert.doesNotMatch(html, /<(?:script|link|img)\b[^>]+(?:src|href)\s*=\s*["']https?:\/\//i);
|
||||
});
|
||||
|
||||
test('the runtime exposes a narrow smoke-test surface without network calls', () => {
|
||||
const app = readProjectFile('app.js');
|
||||
|
||||
assert.match(app, /window\.__VANTA_TEST__/);
|
||||
assert.doesNotMatch(app, /\bfetch\s*\(|XMLHttpRequest|WebSocket/);
|
||||
});
|
||||
Reference in New Issue
Block a user