85 lines
2.2 KiB
JavaScript
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;
|
|
}
|