Files
vanta-relay-20260727-095415/levels.js
T

85 lines
2.2 KiB
JavaScript

export const LEVELS = [
{
id: 'cold-boot',
code: '01 / COLD BOOT',
title: 'Wake the first witness',
briefing: 'The exit only remembers a body that is no longer there. Leave one echo on the amber node.',
accent: '#3df2ff',
map: [
'#########',
'#@..aA.X#',
'#.#######',
'#.#######',
'#########',
],
},
{
id: 'prism-drift',
code: '02 / PRISM DRIFT',
title: 'Hold two impossible places',
briefing: 'One self is a memory. Two selves are an alibi. Sustain both locks at once.',
accent: '#ff62d1',
map: [
'#############',
'#@..aA...B.X#',
'#.###########',
'#.....b######',
'#############',
],
},
{
id: 'cathedral-null',
code: '03 / CATHEDRAL NULL',
title: 'Outnumber the silence',
briefing: 'The vault was built for one mind. Fill three vacant memories and walk through its contradiction.',
accent: '#b48cff',
map: [
'###############',
'#@..aA..B..C.X#',
'#.#############',
'#.....b########',
'#.#############',
'#.....c########',
'###############',
],
},
];
function key(position) {
return `${position.x},${position.y}`;
}
function isWalkable(level, position, openGates) {
if (position.x < 0 || position.y < 0 || position.x >= level.width || position.y >= level.height) {
return false;
}
const tile = level.grid[position.y][position.x];
if (tile === '#') return false;
return !level.gates.has(tile) || openGates.has(tile);
}
export function canReachTarget(level, target, openGates = new Set()) {
const queue = [{ ...level.start }];
const visited = new Set([key(level.start)]);
const vectors = [
{ x: 0, y: -1 },
{ x: 1, y: 0 },
{ x: 0, y: 1 },
{ x: -1, y: 0 },
];
while (queue.length > 0) {
const current = queue.shift();
if (current.x === target.x && current.y === target.y) return true;
for (const vector of vectors) {
const next = { x: current.x + vector.x, y: current.y + vector.y };
if (!isWalkable(level, next, openGates) || visited.has(key(next))) continue;
visited.add(key(next));
queue.push(next);
}
}
return false;
}