Implement naive en/decoder + add link to share game
This commit is contained in:
parent
259d1fc175
commit
5c0ef70220
5 changed files with 125 additions and 68 deletions
|
@ -28,7 +28,10 @@
|
||||||
</ul>
|
</ul>
|
||||||
<button id="load">Load</button>
|
<button id="load">Load</button>
|
||||||
<table id="grid"></table>
|
<table id="grid"></table>
|
||||||
<button id="save">Save</button>
|
<div id="export">
|
||||||
|
<button id="save">Save</button>
|
||||||
|
<a id="share">Share this grid</a>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -3,12 +3,14 @@ import Grid;
|
||||||
import Grid.Color;
|
import Grid.Color;
|
||||||
import Mode;
|
import Mode;
|
||||||
import Toolbox;
|
import Toolbox;
|
||||||
|
import Share;
|
||||||
|
|
||||||
var down = false;
|
var down = false;
|
||||||
Grid.get().element.addEventListener('mouseleave', function() {
|
Grid.get().element.addEventListener('mouseleave', function() {
|
||||||
down = false;
|
down = false;
|
||||||
});
|
});
|
||||||
var save = document.getElementById('save');
|
var save = document.getElementById('save');
|
||||||
|
var share = document.getElementById('share')
|
||||||
|
|
||||||
return {
|
return {
|
||||||
events: {
|
events: {
|
||||||
|
@ -64,5 +66,6 @@ function colorCell(row, column) {
|
||||||
function checkCompleteness() {
|
function checkCompleteness() {
|
||||||
if(Grid.get().missing.isEmpty()) {
|
if(Grid.get().missing.isEmpty()) {
|
||||||
Mode.setEnabled(true, ['play', 'solve']);
|
Mode.setEnabled(true, ['play', 'solve']);
|
||||||
|
share.href = '?game=' + Share.naiveEncode(Grid.get().data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
80
js/Share.js
80
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 {
|
return {
|
||||||
compress: compress,
|
compress: compress,
|
||||||
naive: naive
|
naive: naive
|
||||||
}
|
}
|
||||||
|
|
||||||
function compress(grid) {
|
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) {
|
function naiveEncode(grid) {
|
||||||
append(state, 1);
|
var encoder = Encoder.make();
|
||||||
for(var i = 0; i < 3; i++) {
|
iter(grid, function(row, column) {
|
||||||
append(state, n % 2);
|
encoder.int(3)(grid[row][column]);
|
||||||
n >>= 1;
|
});
|
||||||
}
|
return encoder.output();
|
||||||
}
|
}
|
||||||
|
|
||||||
function appendColor(state, c) {
|
function naiveDecode(size, input) {
|
||||||
append(state, 0);
|
var decoder = Decoder.make(input);
|
||||||
for(var i = 0; i < 3; i++) {
|
return generate(size, size, function() {return decoder.int(3);});
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
49
js/Share/Decoder.js
Normal file
49
js/Share/Decoder.js
Normal file
|
@ -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);}
|
||||||
|
};
|
56
js/Share/Encoder.js
Normal file
56
js/Share/Encoder.js
Normal file
|
@ -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();}
|
||||||
|
};
|
Loading…
Reference in a new issue