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>
|
||||
<button id="load">Load</button>
|
||||
<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>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
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 {
|
||||
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);});
|
||||
}
|
||||
|
|
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