diff options
Diffstat (limited to 'static/bv/puzzleencoder.js')
-rw-r--r-- | static/bv/puzzleencoder.js | 83 |
1 files changed, 83 insertions, 0 deletions
diff --git a/static/bv/puzzleencoder.js b/static/bv/puzzleencoder.js new file mode 100644 index 0000000..fcba62c --- /dev/null +++ b/static/bv/puzzleencoder.js @@ -0,0 +1,83 @@ +// Utility functions for compact puzzle encoding/decoding +const PuzzleEncoder = { + // Simple substitution cipher using base64 + cipher: { + encode(str) { + return btoa(encodeURIComponent(str)).replace(/=/g, '').replace(/\+/g, '-').replace(/\//g, '_'); + }, + decode(str) { + str = str.replace(/-/g, '+').replace(/_/g, '/'); + // Add back padding if needed + while (str.length % 4) str += '='; + try { + return decodeURIComponent(atob(str)); + } catch (e) { + console.error('Failed to decode:', e); + return null; + } + } + }, + + // Compress puzzle structure by replacing common patterns + compressPuzzle(puzzle) { + return puzzle + .replace(/\[\[/g, '<<') // Replace double brackets + .replace(/\]\]/g, '>>') // with angle brackets + .replace(/\[/g, '<') // Replace single brackets + .replace(/\]/g, '>') // with single angle brackets + .replace(/\s+/g, ' '); // Normalize spaces + }, + + // Decompress puzzle structure + decompressPuzzle(compressed) { + return compressed + .replace(/<<|〈〈/g, '[[') + .replace(/>>|〉〉/g, ']]') + .replace(/[<〈]/g, '[') + .replace(/[>〉]/g, ']'); + }, + + // Compress solutions map into compact format + compressSolutions(solutions) { + const pairs = Object.entries(solutions) + .map(([expr, sol]) => `${expr}:${sol}`) + .join('|'); + return pairs; + }, + + // Decompress solutions back into object + decompressSolutions(compressed) { + if (!compressed) return {}; + return Object.fromEntries( + compressed.split('|') + .map(pair => pair.split(':')) + .filter(([k, v]) => k && v) // Filter out any invalid pairs + ); + }, + + // Encode entire puzzle into compact URL-safe string + encodePuzzle(puzzleData) { + const compressed = { + p: this.compressPuzzle(puzzleData.initialPuzzle), + s: this.compressSolutions(puzzleData.solutions) + }; + return this.cipher.encode(JSON.stringify(compressed)); + }, + + // Decode puzzle from compact string + decodePuzzle(encoded) { + try { + const decoded = this.cipher.decode(encoded); + if (!decoded) return null; + + const compressed = JSON.parse(decoded); + return { + initialPuzzle: this.decompressPuzzle(compressed.p), + solutions: this.decompressSolutions(compressed.s) + }; + } catch (e) { + console.error('Failed to decode puzzle:', e); + return null; + } + } + };
\ No newline at end of file |