Compare commits

..

No commits in common. "improve-editor" and "main" have entirely different histories.

24 changed files with 193 additions and 651 deletions

View file

@ -34,10 +34,10 @@
filter: invert(1); filter: invert(1);
} }
#export > * { #save {
display: none; display: none;
} }
#save.active, #share.active { #save.active {
display: initial; display: initial;
} }

View file

@ -6,7 +6,7 @@
(let (let
((%source-dir (dirname (current-filename))) ((%source-dir (dirname (current-filename)))
(SJW (load "/home/Bureau/sjw/guix.scm")) (SJW (load "/home/Bureau/sjw/SJW.scm"))
(UnitJS (load "/home/Bureau/unitJS/guix.scm")) (UnitJS (load "/home/Bureau/unitJS/guix.scm"))
(WTK (load "/home/Bureau/WTK/guix.scm"))) (WTK (load "/home/Bureau/WTK/guix.scm")))
(package (package

View file

@ -25,14 +25,10 @@
<span>Color</span> <span>Color</span>
<select id="colors" class="color0"></select> <select id="colors" class="color0"></select>
</li> </li>
<button id="scatter">Scatter stars</button>
</ul> </ul>
<button id="load">Load</button> <button id="load">Load</button>
<table id="grid"></table> <table id="grid"></table>
<div id="export">
<button id="save">Save</button> <button id="save">Save</button>
<a id="share">Share this grid</a>
</div>
</div> </div>
</body> </body>
</html> </html>

101
js/CellSet.js Normal file
View file

@ -0,0 +1,101 @@
function CellSet(definition) {
definition = definition || {};
this.cells = {};
if(definition.type == 'rectangle') {
this.fromRectangle(definition);
} else if(definition.type == 'isochrome') {
this.fromIsochrome(definition);
} else if(definition.type == 'union') {
this.fromUnion(definition.sets);
}
}
CellSet.prototype.fromRectangle = function(definition) {
var iMax = definition.row + definition.height;
var jMax = definition.column + definition.width;
for(var i = definition.row; i < iMax; i++) {
for(var j = definition.column; j < jMax; j++) {
this.add(i, j);
}
}
};
CellSet.prototype.fromIsochrome = function(definition) {
var originColor = definition.data[definition.row][definition.column];
var queue = [{i: definition.row, j: definition.column}];
while(queue.length > 0) {
var p = queue[0];
this.add(p.i, p.j);
for(var d = -1; d < 2; d += 2) {
[{i: p.i + d, j: p.j}, {i: p.i, j: p.j + d}].forEach(
gateKeeper(this, definition.data, queue, originColor)
);
}
queue.shift();
}
};
CellSet.prototype.fromUnion = function(sets) {
for(var i = 0; i < sets.length; i++) {
for(var key in sets[i].cells) {
this.cells[key] = true;
}
}
}
CellSet.prototype.add = function(i, j) {
this.cells[id(i, j)] = true;
};
CellSet.prototype.remove = function(i, j) {
delete this.cells[id(i, j)];
};
CellSet.prototype.contains = function(i, j) {
return !!this.cells[id(i, j)];
};
CellSet.prototype.isEmpty = function() {
return Object.keys(this.cells).length < 1;
};
CellSet.prototype.map = function(f) {
var result = [];
for(var key in this.cells) {
result.push(f.apply(null, key.split(':')));
}
return result;
}
CellSet.prototype.iter = function(f) {
this.map(f);
}
CellSet.prototype.difference = function(cellSet) {
var newCellSet = new CellSet();
this.iter(function(i, j) {
if(!cellSet.contains(i, j)) {
newCellSet.add(i, j);
}
});
return newCellSet;
}
return {
make: function(definition) {return new CellSet(definition);},
union: function(sets) {return new CellSet({type: 'union', sets: sets});}
};
function id(i, j) {
return i + ':' + j;
}
function gateKeeper(cellSet, data, queue, originColor) {
return function(p1) {
if(p1.i >= 0 && p1.i < data.length && p1.j >= 0 && p1.j < data.length
&& !cellSet.contains(p1.i, p1.j)
&& data[p1.i][p1.j] == originColor) {
queue.push(p1);
}
}
}

View file

@ -1,65 +0,0 @@
import generate from Grid.Util;
return {
random: random
};
function random(size) {
var indices = Array.from({length: size}).map(function(x, i) {return i;});
var previousColumn;
var columns = []
while(columns.length < 8) {
previousColumn = pickNextColumn(indices, previousColumn)
columns.push(previousColumn);
}
return generate(size, size, function(cell) {
return columns[cell.row] == cell.column;
});
}
function pickNextColumn(columnsLeft, previousColumn) {
var parts = contiguousParts(columnsLeft);
if(parts.length == 1 && columnsLeft.length == 4) {
var candidateColumns = [null, columnsLeft[1], columnsLeft[2], null];
} else if(parts.length == 2 && columnsLeft.length < 5
&& Math.min(parts[0].length, parts[1].length) < 2) {
candidateColumns = parts[0].length == 1 ? [null].concat(parts[1]) : parts[0];
} else {
var candidateColumns = columnsLeft;
}
candidateColumns = candidateColumns.map(maskAround(previousColumn));
return columnsLeft.splice(pickIndex(candidateColumns), 1)[0];
}
function maskAround(c0) {
return function(c1) {
return Math.abs(c1 - c0) < 2 ? null : c1;
};
}
function pickIndex(t) {
var o = {};
var definedCount = 0;
for(var i = 0; i < t.length; i++) {
if(t[i] != undefined) {
o[definedCount] = i;
definedCount++;
}
}
return o[Math.floor(definedCount * Math.random())];
}
function contiguousParts(t) {
var parts = [];
var current = [];
for(var i = 0; i < t.length; i++) {
if(current.length < 1 || t[i] - current[current.length-1] == 1) {
current.push(t[i]);
} else {
parts.push(current);
current = [t[i]];
}
}
parts.push(current);
return parts;
}

View file

@ -1,99 +0,0 @@
import {diagonal, isSmaller, key, plus, ofKey, zero} from Geometry.Vector;
import {at, generate} from Grid.Util;
function CellSet(definition) {
definition = definition || {};
this.cells = {};
if(definition.type == 'rectangle') {
this.fromRectangle(definition.origin, definition.offset);
} else if(definition.type == 'isochrome') {
this.fromIsochrome(definition.grid, definition.origin);
} else if(definition.type == 'union') {
this.fromUnion(definition.sets);
}
}
CellSet.prototype.fromRectangle = function(origin, maxOffset) {
generate(
maxOffset.row,
maxOffset.column,
function(offset) {
this.add(plus(origin, offset));
}.bind(this)
);
};
CellSet.prototype.fromIsochrome = function(grid, origin) {
var originColor = at(grid, origin);
var queue = [origin];
while(queue.length > 0) {
var cell = queue.shift();
this.add(cell);
for(var d = -1; d < 2; d += 2) {
[plus(cell, vertical(d)), plus(cell, horizontal(d))].forEach(
gateKeeper(this, grid, queue, originColor)
);
}
}
};
CellSet.prototype.fromUnion = function(sets) {
for(var i = 0; i < sets.length; i++) {
for(var k in sets[i].cells) {
this.cells[k] = true;
}
}
}
CellSet.prototype.add = function(v) {
this.cells[key(v)] = true;
};
CellSet.prototype.remove = function(v) {
delete this.cells[key(v)];
};
CellSet.prototype.contains = function(v) {
return !!this.cells[key(v)];
};
CellSet.prototype.isEmpty = function() {
return Object.keys(this.cells).length < 1;
};
CellSet.prototype.map = function(f) {
var result = [];
for(var k in this.cells) {
result.push(f(ofKey(k)));
}
return result;
}
CellSet.prototype.iter = function(f) {
this.map(f);
}
CellSet.prototype.difference = function(cellSet) {
var newCellSet = new CellSet();
this.iter(function(v) {
if(!cellSet.contains(v)) {
newCellSet.add(v);
}
});
return newCellSet;
}
return {
make: function(definition) {return new CellSet(definition);},
union: function(sets) {return new CellSet({type: 'union', sets: sets});}
};
function gateKeeper(cellSet, grid, queue, originColor) {
return function(cell) {
if(isSmaller(zero(), cell) && isSmaller(cell, diagonal(grid.length-1))
&& !cellSet.contains(cell)
&& at(grid, cell) == originColor) {
queue.push(cell);
}
}
}

View file

@ -1,52 +0,0 @@
return {
make: make,
vertical: vertical,
horizontal: horizontal,
diagonal: diagonal,
zero: zero,
plus: plus,
opposite: opposite,
isSmaller: isSmaller,
key: key,
ofKey: ofKey
};
function make(row, column) {
return {row: row, column: column};
}
function zero() {
return make(0, 0);
}
function vertical(length) {
return make(length, 0);
}
function horizontal(length) {
return make(0, length);
}
function diagonal(length) {
return make(length, length);
}
function plus(v0, v1) {
return {row: v0.row + v1.row, column: v0.column + v1.column};
}
function opposite(v) {
return {row: -v.row, column: -v.column};
}
function isSmaller(v0, v1) {
return v0.row <= v1.row && v0.column <= v1.column;
}
function key(v) {
return v.row + ':' + v.column;
}
function ofKey(k) {
return make.apply(null, k.split(':'));
}

View file

@ -1,43 +1,53 @@
import * as CellSet from Geometry.CellSet; import CellSet;
import * as Dom from UnitJS.Dom; import * as Dom from UnitJS.Dom;
import {at, generate, iter, square} from Grid.Util; import {iter, square} from Grid.Util;
import {diagonal, zero} from Geometry.Vector;
var grid = { var grid = {
root: document.getElementById('grid'), element: document.getElementById('grid'),
cells: null, data: null,
colors: null,
missing: null, missing: null,
size: null size: null
}; };
return { return {
cell: cell,
clear: clear, clear: clear,
get: get,
init: init, init: init,
get: get,
}; };
function init(size, eventHandlers) { function init(size, eventHandlers) {
grid.size = size; grid.size = size;
grid.cells = generate(size, size, function(cell) {
return Dom.make('td', eventHandlers(cell));
});
for(var row = 0; row < size; row++) { for(var row = 0; row < size; row++) {
grid.root.appendChild(Dom.make('tr', {}, grid.cells[row])); grid.element.appendChild(
makeRow({tag: 'td', attributes: eventHandlers, row: row})
);
} }
clear(); clear();
} }
function makeRow(config) {
var cells = [];
for(var column = 0; column < grid.size; column++) {
cells.push(Dom.make(config.tag, config.attributes(config.row, column)));
}
return Dom.make('tr', {}, cells);
}
function clear() { function clear() {
grid.colors = square(grid.size); grid.data = square(grid.size);
grid.missing = CellSet.make( grid.missing = CellSet.make(
{type: 'rectangle', origin: zero(), offset: diagonal(grid.size)} {type: 'rectangle', row: 0, column: 0, width: 8, height: 8}
); );
iter(grid.colors, function(cell) { iter(grid.data, function(row, column) {
at(grid.cells, cell).className = ''; cell(row, column).className = '';
}); });
} }
function get() { function get() {
return grid; return grid;
} }
function cell(row, column) {
return grid.element.children[row].children[column];
}

View file

@ -1,40 +1,22 @@
import * as CellSet from Geometry.CellSet; import CellSet;
import Grid; import Grid;
import {at, iter, set} from Grid.Util;
import Toolbox; import Toolbox;
import Mode;
return { return {
ize: colorize, ize: colorize,
paint: paint, paint: paint
setColors: setColors
}; };
function colorize(cell, color) { function colorize(row, column, color) {
var grid = Grid.get(); var grid = Grid.get();
set(grid.colors, cell, color || Toolbox.color()); grid.data[row][column] = color || Toolbox.color();
at(Grid.get().cells, cell).className = 'color' + at(grid.colors, cell); Grid.cell(row, column).className = 'color' + grid.data[row][column];
grid.missing.remove(cell); grid.missing.remove(row, column);
} }
function paint(origin) { function paint(row, column) {
var cellSet = CellSet.make( var cellSet = CellSet.make(
{type: 'isochrome', grid: Grid.get().colors, origin: origin} {type: 'isochrome', row: row, column: column, data: Grid.get().data}
); );
cellSet.iter(colorize); cellSet.iter(colorize);
} }
function setColors(grid) {
if(grid != undefined) {
iter(grid, function(cell) {
if(at(grid, cell) != undefined) {
colorize(cell, at(grid, cell));
}
});
if(Grid.get().missing.isEmpty()) {
Mode.setEnabled(true, ['play', 'solve']);
} else {
Mode.set('edit');
}
}
}

View file

@ -2,6 +2,7 @@ import * as File from WTK.File;
import * as Async from UnitJS.Async; import * as Async from UnitJS.Async;
import Grid; import Grid;
import Grid.Color; import Grid.Color;
import iter from Grid.Util;
import Mode; import Mode;
return { return {
@ -23,13 +24,27 @@ function load() {
return File.load(input.files[0]); return File.load(input.files[0]);
}, },
function(data) { function(data) {
Grid.Color.setColors(JSON.parse(data)); return Async.wrap(setGridData(JSON.parse(data)));
return Async.wrap();
} }
) )
); );
} }
function save() { function setGridData(data) {
File.save('data:text/json,' + JSON.stringify(Grid.get().colors), "grid.json"); if(data != undefined) {
iter(data, function(row, column) {
if(data[row][column] != undefined) {
Grid.Color.ize(row, column, data[row][column]);
}
});
if(Grid.get().missing.isEmpty()) {
Mode.setEnabled(true, ['play', 'solve']);
} else {
Mode.set('edit');
}
}
}
function save() {
File.save('data:text/json,' + JSON.stringify(Grid.get().data), "grid.json");
} }

View file

@ -1,12 +1,6 @@
import * as Vector from Geometry.Vector;
return { return {
at: at,
column: column,
generate: generate, generate: generate,
iter: iter, iter: iter,
row: row,
set: set,
square: square square: square
}; };
@ -15,7 +9,7 @@ function generate(width, height, f) {
for(var row = 0; row < height; row++) { for(var row = 0; row < height; row++) {
result[row] = [];; result[row] = [];;
for(var column = 0; column < width; column++) { for(var column = 0; column < width; column++) {
result[row].push(f(Vector.make(row, column))); result[row].push(f(row, column));
} }
} }
return result; return result;
@ -25,22 +19,6 @@ function iter(grid, f) {
generate(grid.length > 0 ? grid[0].length : null, grid.length, f); generate(grid.length > 0 ? grid[0].length : null, grid.length, f);
} }
function square(size, value) { function square(size) {
return generate(size, size, function() {return value;}); return generate(size, size, function() {return;});
}
function at(grid, vector) {
return grid[vector.row][vector.column];
}
function set(grid, vector, value) {
return grid[vector.row][vector.column] = value;
}
function row(grid, n) {
return grid[n];
}
function column(grid, n) {
return grid.map(function(row) {return row[n];});
} }

View file

@ -1,7 +1,5 @@
import Grid; import Grid;
import Grid.IO; import Grid.IO;
import Grid.Color;
import Share;
import Toolbox; import Toolbox;
import Mode; import Mode;
import * as Play from Mode.Play; import * as Play from Mode.Play;
@ -17,8 +15,4 @@ Mode.init({
edit: Edit edit: Edit
}); });
Grid.init(size, Mode.dispatch); Grid.init(size, Mode.dispatch);
if(window.location.search.length > 0) {
var urlSearchParameters = new URLSearchParams(window.location.search);
Grid.Color.set(Share.decode(size, urlSearchParameters.get('game')));
}
Grid.IO.init(); Grid.IO.init();

View file

@ -48,10 +48,10 @@ function set(newMode) {
} }
} }
function dispatch(cell) { function dispatch(row, column) {
var handler = {}; var handler = {};
mouseEvents.forEach(function(eventName) { mouseEvents.forEach(function(eventName) {
handler[eventName] = function(e) {runEvent(eventName, e, cell);}; handler[eventName] = function(e) {runEvent(eventName, e, row, column);};
}); });
return handler; return handler;
} }

View file

@ -3,10 +3,9 @@ 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().root.addEventListener('mouseleave', function() { Grid.get().element.addEventListener('mouseleave', function() {
down = false; down = false;
}); });
var save = document.getElementById('save'); var save = document.getElementById('save');
@ -22,51 +21,48 @@ return {
}; };
function onEnter() { function onEnter() {
GUI.activate(true, [Grid.get().root, Toolbox.get(), save]); GUI.activate(true, [Grid.get().element, Toolbox.get(), save]);
if(!Grid.get().missing.isEmpty()) { if(!Grid.get().missing.isEmpty()) {
Mode.setEnabled(false, ['play', 'solve']); Mode.setEnabled(false, ['play', 'solve']);
} else {
Share.link(Grid.get().colors);
} }
} }
function onLeave() { function onLeave() {
GUI.activate(false, [Grid.get().root, Toolbox.get(), save, Share.get()]); GUI.activate(false, [Grid.get().element, Toolbox.get(), save]);
} }
function onMousedown(e, cell) { function onMousedown(e, row, column) {
if(e.button == GUI.mouse.left) { if(e.button == GUI.mouse.left) {
down = true; down = true;
if(Toolbox.tool() == 'draw') { if(Toolbox.tool() == 'draw') {
colorCell(cell); colorCell(row, column);
} }
} }
} }
function onMouseup(e, cell) { function onMouseup(e, row, column) {
if(e.button == GUI.mouse.left) { if(e.button == GUI.mouse.left) {
down = false; down = false;
if(Toolbox.tool() == 'paint') { if(Toolbox.tool() == 'paint') {
Grid.Color.paint(cell); Grid.Color.paint(row, column);
checkCompleteness(); checkCompleteness();
} }
} }
} }
function onMouseenter(e, cell) { function onMouseenter(e, row, column) {
if(down && Toolbox.tool() == 'draw') { if(down && Toolbox.tool() == 'draw') {
colorCell(cell); colorCell(row, column);
} }
} }
function colorCell(cell) { function colorCell(row, column) {
Grid.Color.ize(cell); Grid.Color.ize(row, column);
checkCompleteness(); checkCompleteness();
} }
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.link(Grid.get().colors);
} }
} }

View file

@ -1,6 +1,5 @@
import Grid; import Grid;
import GUI; import GUI;
import at from Grid.Util;
return { return {
events: { events: {
@ -8,9 +7,9 @@ return {
} }
}; };
function onClick(e, cell) { function onClick(e, row, column) {
if(Grid.get().missing.isEmpty()) { if(Grid.get().missing.isEmpty()) {
rotateState(at(Grid.get().cells, cell)); rotateState(Grid.cell(row, column));
} }
} }

View file

@ -8,5 +8,5 @@ return {
}; };
function onEnter() { function onEnter() {
console.log(Solver.step(Grid.get().colors)); console.log(Solver.step(Grid.get().data));
} }

View file

@ -1,38 +0,0 @@
import {at, generate, iter, square} from Grid.Util;
import * as Decode from Share.Decoder.Protocol;
import * as Encode from Share.Encoder.Protocol;
import GUI;
import Grid;
var share = document.getElementById('share')
return {
get: get,
decode: Decode.grid,
link: link
}
function get() {
return share;
}
function naiveEncode(grid) {
var encoder = Encoder.make();
iter(grid, function(cell) {
encoder.int(3)(at(grid, cell));
});
return encoder.output();
}
function naiveDecode(size, input) {
if(input != undefined) {
var decoder = Decoder.make(input);
return generate(size, size, function() {return decoder.int(3);});
}
}
function link(grid) {
//share.href = '?game=' + naiveEncode(Grid.get().colors);
share.href = '?game=' + Encode.grid(Grid.get().colors);
GUI.activate(true, share);
}

View file

@ -1,49 +0,0 @@
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);}
};

View file

@ -1,79 +0,0 @@
import * as CellSet from Geometry.CellSet;
import * as Decoder from Share.Decoder.Class;
import {diagonal, plus, zero} from Geometry.Vector;
import * as Vector from Geometry.Vector;
import * as Protocol from Share.Protocol;
return {
grid: decodeGrid
};
function decodeGrid(size, input) {
if(input != undefined) {
return decoderLoop(
Decoder.make(input),
square(size),
CellSet.make({type: 'rectangle', origin: zero(), offset: diagonal(size)})
);
}
}
function decoderLoop(decoder, grid, missing) {
var queue = [];
var nextBit = decoder.pop();
var cell = zero();
var danglingCells = [];
while(nextBit != null) {
if(nextBit == 1) {
fillBlock(grid, decodeBlock(decoder), missing);
} else {
handleCell(grid, cell, decodeDirection(decoder), danglingCells);
}
moveToNext(cell, grid, missing);
nextBit = decoder.pop();
}
resolve(grid, danglingCells);
return grid;
}
function moveToNext(cell, grid, missing) {
cell.column++;
while(!missing.contains(cell)) {
if(cell.column >= grid[cell.row].length) {
cell.row++;
cell.column = 0;
} else {
cell.column++;
}
}
}
function fillBlock(grid, block, missing, cell) {
var offset = Vector[block.direction](1);
var newCell = Vector.make(cell.row, cell.column);
for(var delta = 0; delta < block.size; delta++) {
set(grid, newCell, block.color);
missing.remove(newCell);
newCell = plus(newCell, offset);
}
}
function decodeBlock(decoder) {
return {
direction: decoder.pop() == 1 ? 'vertical' : 'horizontal',
size: decoder.variableLength6() + Protocol.MIN_BLOCK_SIZE,
color: decoder.int(3)
};
}
function handleCell(grid, cell, direction, danglingCells) {
}
function resolve(grid, danglingCells) {
}
function decodeDirection(decoder) {
return Protocol.directions[decoder.int(2)];
}

View file

@ -1,55 +0,0 @@
function Encoder() {
this.buffer = '';
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.buffer = this.buffer + 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.buffer);
};
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) {
return function(n) {
for(var i = 0; i < size; i++) {
encoder.push(n > 3);
n = (2*n) & 7;
}
}.bind(this);
};
return {
make: function() {return new Encoder();}
};

View file

@ -1,81 +0,0 @@
import * as Encoder from Share.Encoder.Class;
import {at, iter, square} from Grid.Util;
import * as Protocol from Share.Protocol;
return {
grid: encodeGrid
};
function encodeGrid(grid) {
var encoder = Encoder.make();
var done = square(grid.length, false);
var gradients = square(grid.length);
iter(grid, function(cell) {
if(!at(done, cell)) {
let block = getLongestBlock(grid, cell);
if(block != undefined) {
encodeBlock(encoder, block);
} else {
encodeSingleCell(
encoder,
getColorGradient(gradients, grid, cell)
);
}
}
});
}
function getLongestBlock(grid, origin) {
var color = at(grid, origin);
var longestDirection = findLongestDirection(grid, origin, color);
var size = extend(grid, origin, color, longestDirection);
if(size >= Protocol.MIN_BLOCK_SIZE) {
return {
direction: longestDirection.coordinate == 'row' ? 'vertical' : 'horizontal',
size: size,
color: color
};
}
}
function findLongestDirection(grid, p, originColor) {
var delta = 1;
while(true) {
var newRow = p.row + delta;
var newColumn = p.column + delta;
if(newRow >= grid.length || grid[newRow][p.column] != originColor) {
return {coordinate: 'column', delta: delta};
} else if(newColumn >= grid[p.row].length || grid[p.row][newColumn] != originColor) {
return {coordinate: 'row', delta: delta+1};
}
delta++;
}
}
function extend(grid, p, originColor, direction) {
var origin = p[direction.coordinate];
p[direction.coordinate] += direction.delta;
while(isSmaller(p, diagonal(grid.length)) && at(grid, p) == originColor) {
p[direction.coordinate]++;
}
return p[direction.coordinate] - origin;
}
function encodeBlock(encoder, block) {
encoder.push(1);
encoder.push(block.direction == 'vertical');
encoder.variableLength6(block.size - Protocol.MIN_BLOCK_SIZE);
encoder.int(3)(block.color);
}
function getColorGradient(gradients, grid, cell) {
if(at(gradients, cell) == undefined) {
}
return at(gradients, cell);
}
function encodeSingleCell(encoder, direction) {
encoder.push(0);
encoder.int(2)(Protocol.directions.indexOf(direction));
}

View file

@ -1,4 +0,0 @@
return {
directions: ['up', 'right', 'down', 'left'],
MIN_BLOCK_SIZE: 3
};

View file

@ -1,32 +1,32 @@
import * as CellSet from Geometry.CellSet; import CellSet;
return { return {
step: step step: step
}; };
function step(grid) { function step(matrix) {
var zones = getZones(grid); var zones = getZones(matrix);
var lines = getLines(grid.length); var grid = getGrid(matrix.length);
var rowClusters = checkRowsInclusions(grid); var rowClusters = checkRowsInclusions(matrix);
if(rowClusters.length > 0) { if(rowClusters.length > 0) {
rowClusters.forEach(function(rowCluster) { rowClusters.forEach(function(rowCluster) {
rowCluster.toClear = difference( rowCluster.toClear = difference(
rowCluster.colors.map(function(color) {return zones[color];}), rowCluster.colors.map(function(color) {return zones[color];}),
rowCluster.rows.map(function(row) {return lines.rows[row];}) rowCluster.rows.map(function(row) {return grid.rows[row];})
); );
}); });
} }
return rowClusters; return rowClusters;
} }
function getZones(grid) { function getZones(matrix) {
var zones = {}; var zones = {};
for(var row = 0; row < grid.length; row++) { for(var row = 0; row < matrix.length; row++) {
for(var column = 0; column < grid[row].length; column++) { for(var column = 0; column < matrix[row].length; column++) {
var color = grid[row][column]; var color = matrix[row][column];
if(zones[color] == undefined) { if(zones[color] == undefined) {
zones[color] = CellSet.make( zones[color] = CellSet.make(
{type: 'isochrome', row: row, column: column, grid: grid} {type: 'isochrome', row: row, column: column, data: matrix}
); );
} }
} }
@ -46,7 +46,7 @@ function line(type, size, i) {
} }
} }
function getLines(size) { function getGrid(size) {
var empty = Array.from({length: size}); var empty = Array.from({length: size});
return { return {
rows: empty.map(function(x, i) {return line('row', size, i);}), rows: empty.map(function(x, i) {return line('row', size, i);}),
@ -54,11 +54,11 @@ function getLines(size) {
}; };
} }
function getColorsByRow(grid) { function getColorsByRow(matrix) {
var colorsByRow = []; var colorsByRow = [];
for(var row = 0; row < grid.length; row++) { for(var row = 0; row < matrix.length; row++) {
colorsByRow.push( colorsByRow.push(
quotient(grid[row], function(c0, c1) {return c0 == c1;}).map( quotient(matrix[row], function(c0, c1) {return c0 == c1;}).map(
function(colorClass) {return colorClass.specimen;} function(colorClass) {return colorClass.specimen;}
) )
); );
@ -66,8 +66,8 @@ function getColorsByRow(grid) {
return colorsByRow; return colorsByRow;
} }
function checkRowsInclusions(grid) { function checkRowsInclusions(matrix) {
var colorsByRow = getColorsByRow(grid); var colorsByRow = getColorsByRow(matrix);
var colorSets = quotient(colorsByRow, sameColorsSet); var colorSets = quotient(colorsByRow, sameColorsSet);
return colorSets.reduce(function(commands, colorSet) { return colorSets.reduce(function(commands, colorSet) {
if(colorSet.occurrences.length == colorSet.specimen.length) { if(colorSet.occurrences.length == colorSet.specimen.length) {

View file

@ -1,5 +1,4 @@
import * as Dom from UnitJS.Dom; import * as Dom from UnitJS.Dom;
import Constellation;
var toolbox; var toolbox;
var tool; var tool;
@ -22,12 +21,6 @@ function init(size, elementId) {
colors.className = color(); colors.className = color();
}); });
tool = toolbox.querySelector('#tool'); tool = toolbox.querySelector('#tool');
toolbox.querySelector('#scatter').addEventListener('click', function() {
var constellation = Constellation.random(size);
for(var i = 0; i < size; i++) {
console.log(constellation[i].map(function(x) {return x ? '*' : ' ';}).join('|'));
}
});
} }
function get() { function get() {