Implement naive en/decoder + add link to share game

This commit is contained in:
Tissevert 2022-08-06 18:33:10 +02:00
parent 259d1fc175
commit 5c0ef70220
5 changed files with 125 additions and 68 deletions

View file

@ -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>

View file

@ -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);
}
}

View file

@ -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
View 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
View 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();}
};