aboutsummaryrefslogtreecommitdiff
path: root/static/bv/puzzleencoder.js
diff options
context:
space:
mode:
Diffstat (limited to 'static/bv/puzzleencoder.js')
-rw-r--r--static/bv/puzzleencoder.js83
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