From 02f85ef115af8077f1ae6c5ffeb9178771a5fc4b Mon Sep 17 00:00:00 2001 From: tiennm99 Date: Tue, 21 Apr 2026 21:31:14 +0700 Subject: [PATCH] feat(levels): redesign L12 Princess Chamber and add console easter egg MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit L12 widened to 13x13 with 10 guards including 2 chasers and a mirror. Remains unsolvable by normal play (BFS-verified). window.__nntvDev.teleport exposed as an intentional escape hatch — console-savvy users who invoke it win the game. Hidden from README and in-game UI. --- src/lib/levels/levels.js | 72 +++++++++++++++++++++++++++++----------- src/scenes/Game.svelte | 27 ++++++++++++++- 2 files changed, 79 insertions(+), 20 deletions(-) diff --git a/src/lib/levels/levels.js b/src/lib/levels/levels.js index dd7c9b8..4e545df 100644 --- a/src/lib/levels/levels.js +++ b/src/lib/levels/levels.js @@ -722,31 +722,40 @@ export const LEVELS = [ parMoves: 24, }, { - // THE PRINCESS CHAMBER — unbeatable: expanding light wave from goal - // When player reaches distance 4, one ring per turn lights up. + // L12 THE PRINCESS CHAMBER — 13x13, 10 guards + expanding light wave. + // INVARIANT: must be unsolvable by normal play. Only the console + // easter egg (window.__nntvDev.teleport) wins this level. + // See memory: project_level12_unsolvable.md. id: 12, name: "The Princess Chamber", storyKey: "level12Story", - grid: { rows: 10, cols: 10 }, + grid: { rows: 13, cols: 13 }, player: { row: 0, col: 0 }, - goal: { row: 9, col: 9 }, + goal: { row: 12, col: 12 }, walls: [ + // Barrier walls forming concentric barriers around the princess { row: 2, col: 0 }, { row: 2, col: 1 }, { row: 2, col: 2 }, { row: 2, col: 3 }, { row: 2, col: 4 }, { row: 2, col: 5 }, - { row: 2, col: 6 }, { row: 2, col: 7 }, - { row: 4, col: 2 }, { row: 4, col: 3 }, { row: 4, col: 4 }, - { row: 4, col: 5 }, { row: 4, col: 6 }, { row: 4, col: 7 }, - { row: 4, col: 8 }, { row: 4, col: 9 }, + { row: 2, col: 6 }, { row: 2, col: 7 }, { row: 2, col: 8 }, { row: 2, col: 9 }, + { row: 4, col: 3 }, { row: 4, col: 4 }, { row: 4, col: 5 }, + { row: 4, col: 6 }, { row: 4, col: 7 }, { row: 4, col: 8 }, + { row: 4, col: 9 }, { row: 4, col: 10 }, { row: 4, col: 11 }, { row: 4, col: 12 }, { row: 6, col: 0 }, { row: 6, col: 1 }, { row: 6, col: 2 }, { row: 6, col: 3 }, { row: 6, col: 4 }, { row: 6, col: 5 }, - { row: 6, col: 6 }, { row: 6, col: 7 }, + { row: 6, col: 6 }, { row: 6, col: 7 }, { row: 6, col: 8 }, + { row: 8, col: 3 }, { row: 8, col: 4 }, { row: 8, col: 5 }, + { row: 8, col: 6 }, { row: 8, col: 7 }, { row: 8, col: 8 }, + { row: 8, col: 9 }, { row: 8, col: 10 }, { row: 8, col: 11 }, + { row: 10, col: 1 }, { row: 10, col: 2 }, { row: 10, col: 3 }, + { row: 10, col: 4 }, { row: 10, col: 5 }, { row: 10, col: 6 }, + { row: 10, col: 7 }, { row: 10, col: 8 }, { row: 10, col: 9 }, ], guards: [ { type: "static", - position: { row: 1, col: 8 }, + position: { row: 1, col: 10 }, litCells: [ - { row: 0, col: 8 }, { row: 1, col: 7 }, { row: 1, col: 9 }, + { row: 0, col: 10 }, { row: 1, col: 9 }, { row: 1, col: 11 }, ], }, { @@ -756,35 +765,60 @@ export const LEVELS = [ }, { type: "blinking", - position: { row: 5, col: 8 }, + position: { row: 5, col: 1 }, startState: true, litCells: [ - { row: 5, col: 7 }, { row: 5, col: 9 }, + { row: 5, col: 0 }, { row: 5, col: 2 }, ], }, + { + type: "mirror", + position: { row: 3, col: 11 }, + reflectDirection: "cw", + }, { type: "patrolling", startPosition: { row: 7, col: 1 }, path: [ { row: 7, col: 1 }, { row: 7, col: 2 }, { row: 7, col: 3 }, { row: 7, col: 4 }, + { row: 7, col: 5 }, { row: 7, col: 6 }, { row: 7, col: 5 }, { row: 7, col: 4 }, { row: 7, col: 3 }, { row: 7, col: 2 }, ], }, { type: "patrolling", - startPosition: { row: 8, col: 8 }, + startPosition: { row: 9, col: 10 }, path: [ - { row: 8, col: 8 }, { row: 8, col: 7 }, - { row: 8, col: 6 }, { row: 8, col: 5 }, - { row: 8, col: 6 }, { row: 8, col: 7 }, + { row: 9, col: 10 }, { row: 9, col: 9 }, + { row: 9, col: 8 }, { row: 9, col: 7 }, + { row: 9, col: 8 }, { row: 9, col: 9 }, + ], + }, + { + type: "static", + position: { row: 11, col: 11 }, + litCells: [ + { row: 10, col: 11 }, { row: 11, col: 10 }, + { row: 11, col: 12 }, { row: 12, col: 11 }, + ], + }, + { + type: "static", + position: { row: 12, col: 10 }, + litCells: [ + { row: 12, col: 9 }, { row: 12, col: 11 }, ], }, { - // Extra chaser to make it even more hopeless type: "chaser", - position: { row: 8, col: 2 }, + position: { row: 11, col: 2 }, + detectionRadius: 4, + }, + { + type: "chaser", + position: { row: 9, col: 11 }, detectionRadius: 4, }, ], diff --git a/src/scenes/Game.svelte b/src/scenes/Game.svelte index c52a6c1..1960765 100644 --- a/src/scenes/Game.svelte +++ b/src/scenes/Game.svelte @@ -117,9 +117,34 @@ completionMoves = 0; } - onMount(() => { initLevel(); }); + onMount(() => { + initLevel(); + // Dev easter egg — intentional escape hatch for L12 "Princess Chamber", + // which is unsolvable by normal play. Console-savvy users who discover + // this teleport win the game. Not documented in UI/README. + // See memory: project_level12_unsolvable.md. + if (typeof window !== 'undefined') { + window.__nntvDev = { + teleport: (row, col) => { + if (!player || !grid) return false; + if (!grid.isValidPosition(row, col)) return false; + player.row = row; + player.col = col; + renderVersion++; + if (player.isAtGoal()) handleLevelComplete(); + return true; + }, + reveal: () => ({ + player: player ? { row: player.row, col: player.col } : null, + goal: { row: goalRow, col: goalCol }, + level: currentLevel, + }), + }; + } + }); onDestroy(() => { if (detectionTimeout) clearTimeout(detectionTimeout); + if (typeof window !== 'undefined') delete window.__nntvDev; }); // Capture current state as a snapshot object (does not push to history)