1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
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;
}
}
};
|