diff --git a/index.html b/index.html index 75907bb..0b56005 100644 --- a/index.html +++ b/index.html @@ -28,7 +28,10 @@
- +
+ + Share this grid +
diff --git a/js/Mode/Edit.js b/js/Mode/Edit.js index 6a4fb0e..5252130 100644 --- a/js/Mode/Edit.js +++ b/js/Mode/Edit.js @@ -3,12 +3,14 @@ import Grid; import Grid.Color; import Mode; import Toolbox; +import Share; var down = false; Grid.get().element.addEventListener('mouseleave', function() { down = false; }); var save = document.getElementById('save'); +var share = document.getElementById('share') return { events: { @@ -64,5 +66,6 @@ function colorCell(row, column) { function checkCompleteness() { if(Grid.get().missing.isEmpty()) { Mode.setEnabled(true, ['play', 'solve']); + share.href = '?game=' + Share.naiveEncode(Grid.get().data); } } diff --git a/js/Share.js b/js/Share.js index 216d169..ab874e8 100644 --- a/js/Share.js +++ b/js/Share.js @@ -1,78 +1,24 @@ +import * as Decoder from Share.Decoder; +import * as Encoder from Share.Encoder; +import {iter, square} from Grid.Util; + return { compress: compress, naive: naive } function compress(grid) { - var state = { - data: '', - stack: 0, - size: 0 - }; - var color; - var count; - for(var i = 0; i < grid.length; i++) { - for(var j = 0; j < grid.length; j++) { - if(color == undefined) { - color = grid[i][j]; - } else if(grid[i][j] != color) { - } else if(count > 6) { - } else { - count++; - } - } - } - return atob(compressed); } -function appendLength(state, n) { - append(state, 1); - for(var i = 0; i < 3; i++) { - append(state, n % 2); - n >>= 1; - } +function naiveEncode(grid) { + var encoder = Encoder.make(); + iter(grid, function(row, column) { + encoder.int(3)(grid[row][column]); + }); + return encoder.output(); } -function appendColor(state, c) { - append(state, 0); - for(var i = 0; i < 3; i++) { - append(state, c % 2); - c >>= 1; - } -} - -function appendColorNaive(state, c) { - for(var i = 0; i < 3; i++) { - append(state, c % 2); - c >>= 1; - } -} - -function append(state, one) { - if(state.size > 7) { - flush(state); - } - state.stack = 2*state.stack + (one ? 1 : 0); - state.size++; -} - -function flush(state) { - state.data = state.data + String.fromCharCode(state.stack); - state.stack = 0; - state.size = 0; -} - -function naive(grid) { - var state = { - data: '', - stack: 0, - size: 0 - }; - for(var i = 0; i < grid.length; i++) { - for(var j = 0; j < grid.length; j++) { - appendColorNaive(state, grid[i][j]); - } - } - flush(state); - return btoa(state.data); +function naiveDecode(size, input) { + var decoder = Decoder.make(input); + return generate(size, size, function() {return decoder.int(3);}); } diff --git a/js/Share/Decoder.js b/js/Share/Decoder.js new file mode 100644 index 0000000..a9df254 --- /dev/null +++ b/js/Share/Decoder.js @@ -0,0 +1,49 @@ +function Decoder(input) { + this.input = atob(input); + this.cache = 0; + this.size = 0; +} + +Decoder.prototype.pop = function() { + if(this.size < 1) { + if(this.input.length < 1) { + return null; + } else { + this.cache = this.input.charCodeAt(0); + this.size = 8; + this.input = this.input.slice(1); + } + } + this.size--; + var wasFirstBitOne = this.cache > 0x7f; + this.cache = (2*this.cache) & 0xff; + return wasFirstBitOne ? 1 : 0; +}; + +Decoder.prototype.variableLength3 = function() { + if(this.pop() == 1) { + return this.pop() + 1; + } else { + return 0; + } +}; + +Decoder.prototype.variableLength6 = function() { + if(this.pop() == 1) { + return 2 + this.int(2); + } else { + return this.pop(); + } +}; + +Decoder.prototype.int = function(size) { + var result = 0; + for(var i = 0; i < size; i++) { + result = 2*result + this.pop(); + } + return result; +}; + +return { + make: function(input) {return new Decoder(input);} +}; diff --git a/js/Share/Encoder.js b/js/Share/Encoder.js new file mode 100644 index 0000000..43ede74 --- /dev/null +++ b/js/Share/Encoder.js @@ -0,0 +1,56 @@ +function Encoder() { + this.data = ''; + this.stack = 0; + this.size = 0; +} + +Encoder.prototype.push = function(one) { + if(this.size > 7) { + this.flush(); + } + this.stack = 2*this.stack + (one ? 1 : 0); + this.size++; +}; + +Encoder.prototype.flush = function() { + this.data = this.data + String.fromCharCode(this.stack); + this.stack = 0; + this.size = 0; +}; + +Encoder.prototype.output = function() { + while(this.size < 8) { + this.push(0); + } + this.flush(); + return btoa(this.data); +}; + +Encoder.prototype.variableLength3 = function(n) { + if(n > 0) { + this.push(1); + } + this.push(n > 1); +}; + +Encoder.prototype.variableLength6 = function(n) { + if(n > 1) { + this.push(1); + } + this.push(n > 3); + this.push(n % 2); +}; + +Encoder.prototype.int = function(size) { + var encoder = this; + return function(n) { + for(var i = 0; i < size; i++) { + encoder.push(n > 3); + n = (2*n) & 7; + } + } +}; + +return { + make: function() {return new Encoder();} +};