clone

a browser grid puzzle game where you push words around to rewrite the rules of each level

Cache authored lookups across solver restores

Dami committed 4c34901
commit
4c34901d3a450781fe30b47c0c27c9645e7c2e44
parent
8040dfb62a65011da09040865a6ba5630c1324d1
author
Dami <dami.etoile@gmail.com>
2 files changed, +29 -3
Msrc/engine.js13++++++++++---
Mtests/engine-fast.test.js19+++++++++++++++++++
M src/engine.js +10 -3
@@ -85,6 +85,14 @@ export function createGame(level) {
8585 return { ...action };8686 }),8787 }));88+ // Restore runs once per solver transition. Keep the authored identity and89+ // automaton lookup tables immutable so each restore only validates the90+ // supplied snapshot rather than rebuilding level metadata.91+ const authoredById = new Map(original.objects.map((object, index) => [92+ object.id || `o${index}`,93+ { ...object, kind: object.kind || (object.text != null ? 'word' : 'object') },94+ ]));95+ const automataById = new Map(automataDefs.map(system => [system.id, system]));8896 const dynamicProperties = new Set(automataDefs.map(system => system.property));8997 const semanticProperties = new Set([...CORE_PROPERTIES, ...dynamicProperties]);9098 let state;
@@ -322,13 +330,12 @@ export function createGame(level) {
322330 if (snapshot.width !== original.width || snapshot.height !== original.height) throw new RangeError('snapshot board shape does not match this level');323331 if (snapshot.levelId !== undefined && snapshot.levelId !== original.id) throw new RangeError('snapshot level does not match this level');324332 if (!Array.isArray(snapshot.objects)) throw new TypeError('snapshot.objects must be an array');325- const authored = new Map(original.objects.map((object, index) => [object.id || `o${index}`, { ...object, kind: object.kind || (object.text != null ? 'word' : 'object') }]));326333 const ids = new Set();327334 const objects = snapshot.objects.map((object, index) => {328335 if (!object || typeof object !== 'object' || typeof object.id !== 'string') throw new TypeError(`snapshot.objects[${index}] needs an id`);329336 if (ids.has(object.id)) throw new Error(`snapshot has duplicate object id: ${object.id}`);330337 ids.add(object.id);331- const source = authored.get(object.id);338+ const source = authoredById.get(object.id);332339 if (!source) throw new Error(`snapshot object id is not authored by this level: ${object.id}`);333340 const kind = object.kind || (object.text != null ? 'word' : 'object');334341 if (kind !== source.kind) throw new TypeError(`snapshot object kind changed for ${object.id}`);
@@ -344,7 +351,7 @@ export function createGame(level) {
344351 if (snapshot.automata !== undefined) {345352 if (!Array.isArray(snapshot.automata)) throw new TypeError('snapshot.automata must be an array');346353 for (const runtime of snapshot.automata) {347- const system = automataDefs.find(candidate => candidate.id === runtime?.id);354+ const system = automataById.get(runtime?.id);348355 if (!system || phaseById.has(runtime.id) || !Number.isInteger(runtime.phase) || runtime.phase < 0 || runtime.phase >= system.pattern.length) throw new TypeError(`snapshot has an invalid automaton phase: ${runtime?.id || '?'}`);349356 phaseById.set(runtime.id, runtime.phase);350357 }
M tests/engine-fast.test.js +19 -0