Sort of reached an acceptable state where two first solver rules work
This commit is contained in:
parent
0a61d9a389
commit
213eec19fe
18 changed files with 213 additions and 279 deletions
|
@ -1,99 +1,58 @@
|
|||
import {diagonal, isSmaller, key, plus, ofKey, zero} from Geometry.Vector;
|
||||
import {at, generate} from Grid.Util;
|
||||
import size from Config;
|
||||
import {isSmaller, plus, zero} from Geometry.Vector;
|
||||
import * as Vector from Geometry.Vector;
|
||||
import {at, iter} from Grid.Util;
|
||||
import * as Matrix from Grid.Util;
|
||||
import Set;
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
var CellSet = Set.make(Vector);
|
||||
|
||||
CellSet.prototype.fromRectangle = function(origin, maxOffset) {
|
||||
generate(
|
||||
maxOffset.row,
|
||||
maxOffset.column,
|
||||
function(offset) {
|
||||
this.add(plus(origin, offset));
|
||||
}.bind(this)
|
||||
);
|
||||
return {
|
||||
CellSet: CellSet,
|
||||
union: CellSet.union,
|
||||
rectangle: rectangle,
|
||||
isochrome: isochrome,
|
||||
row: row,
|
||||
column: column
|
||||
};
|
||||
|
||||
CellSet.prototype.fromIsochrome = function(grid, origin) {
|
||||
var originColor = at(grid, origin);
|
||||
function rectangle(origin, delta) {
|
||||
var cellSet = new CellSet();
|
||||
iter(Matrix.make(delta), function(_, cell) {cellSet.add(plus(origin, cell));});
|
||||
return cellSet;
|
||||
}
|
||||
|
||||
function isochrome(coloring, origin) {
|
||||
var cellSet = new CellSet();
|
||||
var color = at(coloring, origin);
|
||||
var queue = [origin];
|
||||
while(queue.length > 0) {
|
||||
var cell = queue.shift();
|
||||
this.add(cell);
|
||||
cellSet.add(cell);
|
||||
for(var d = -1; d < 2; d += 2) {
|
||||
[plus(cell, vertical(d)), plus(cell, horizontal(d))].forEach(
|
||||
gateKeeper(this, grid, queue, originColor)
|
||||
[plus(cell, Vector.vertical(d)), plus(cell, Vector.horizontal(d))].forEach(
|
||||
gateKeeper(cellSet, coloring, queue, color)
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
CellSet.prototype.fromUnion = function(sets) {
|
||||
for(var i = 0; i < sets.length; i++) {
|
||||
for(var k in sets[i].cells) {
|
||||
this.cells[k] = true;
|
||||
}
|
||||
}
|
||||
return cellSet;
|
||||
}
|
||||
|
||||
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) {
|
||||
function gateKeeper(cellSet, coloring, queue, color) {
|
||||
return function(cell) {
|
||||
if(isSmaller(zero(), cell) && isSmaller(cell, diagonal(grid.length-1))
|
||||
if(isSmaller(zero(), cell)
|
||||
&& isSmaller(cell, Vector.diagonal(size-1))
|
||||
&& !cellSet.contains(cell)
|
||||
&& at(grid, cell) == originColor) {
|
||||
&& at(coloring, cell) == color) {
|
||||
queue.push(cell);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function row(n) {
|
||||
return rectangle(Vector.vertical(n), Vector.make(1, size));
|
||||
}
|
||||
|
||||
function column(n) {
|
||||
return rectangle(Vector.horizontal(n), Vector.make(size, 1));
|
||||
}
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
return {
|
||||
make: make,
|
||||
getRow: getRow,
|
||||
getColumn: getColumn,
|
||||
vertical: vertical,
|
||||
horizontal: horizontal,
|
||||
diagonal: diagonal,
|
||||
|
@ -7,12 +9,20 @@ return {
|
|||
plus: plus,
|
||||
opposite: opposite,
|
||||
isSmaller: isSmaller,
|
||||
key: key,
|
||||
ofKey: ofKey
|
||||
toKey: toKey,
|
||||
ofKey: ofKey,
|
||||
};
|
||||
|
||||
function make(row, column) {
|
||||
return {row: row, column: column};
|
||||
return {row: parseInt(row), column: parseInt(column)};
|
||||
}
|
||||
|
||||
function getRow(v) {
|
||||
return v.row;
|
||||
}
|
||||
|
||||
function getColumn(v) {
|
||||
return v.column;
|
||||
}
|
||||
|
||||
function zero() {
|
||||
|
@ -32,21 +42,23 @@ function diagonal(length) {
|
|||
}
|
||||
|
||||
function plus(v0, v1) {
|
||||
return {row: v0.row + v1.row, column: v0.column + v1.column};
|
||||
return make(v0.row + v1.row, v0.column + v1.column);
|
||||
}
|
||||
|
||||
function opposite(v) {
|
||||
return {row: -v.row, column: -v.column};
|
||||
return make(-v.row, -v.column);
|
||||
}
|
||||
|
||||
function isSmaller(v0, v1) {
|
||||
return v0.row <= v1.row && v0.column <= v1.column;
|
||||
}
|
||||
|
||||
function key(v) {
|
||||
function toKey(v) {
|
||||
return v.row + ':' + v.column;
|
||||
//return 8*v.row + v.column;
|
||||
}
|
||||
|
||||
function ofKey(k) {
|
||||
return make.apply(null, k.split(':'));
|
||||
//return make.call(null, Math.floor(k / 8), k % 8);
|
||||
}
|
||||
|
|
17
js/Grid.js
17
js/Grid.js
|
@ -1,3 +1,4 @@
|
|||
import size from Config;
|
||||
import * as CellSet from Geometry.CellSet;
|
||||
import * as Dom from UnitJS.Dom;
|
||||
import {at, generate, iter, square} from Grid.Util;
|
||||
|
@ -8,7 +9,6 @@ var grid = {
|
|||
cells: null,
|
||||
colors: null,
|
||||
missing: null,
|
||||
size: null
|
||||
};
|
||||
|
||||
return {
|
||||
|
@ -17,9 +17,8 @@ return {
|
|||
init: init,
|
||||
};
|
||||
|
||||
function init(size, eventHandlers) {
|
||||
grid.size = size;
|
||||
grid.cells = generate(size, size, function(cell) {
|
||||
function init(eventHandlers) {
|
||||
grid.cells = square(size, function(cell) {
|
||||
return Dom.make('td', eventHandlers(cell));
|
||||
});
|
||||
for(var row = 0; row < size; row++) {
|
||||
|
@ -29,13 +28,9 @@ function init(size, eventHandlers) {
|
|||
}
|
||||
|
||||
function clear() {
|
||||
grid.colors = square(grid.size);
|
||||
grid.missing = CellSet.make(
|
||||
{type: 'rectangle', origin: zero(), offset: diagonal(grid.size)}
|
||||
);
|
||||
iter(grid.colors, function(cell) {
|
||||
at(grid.cells, cell).className = '';
|
||||
});
|
||||
grid.colors = square(size);
|
||||
grid.missing = CellSet.rectangle(zero(), diagonal(size));
|
||||
iter(grid.cells, function(td) {td.className = '';});
|
||||
}
|
||||
|
||||
function get() {
|
||||
|
|
|
@ -12,29 +12,27 @@ return {
|
|||
|
||||
function colorize(cell, color) {
|
||||
var grid = Grid.get();
|
||||
set(grid.colors, cell, color || Toolbox.color());
|
||||
set(grid.colors, cell, color ?? Toolbox.color());
|
||||
at(Grid.get().cells, cell).className = 'color' + at(grid.colors, cell);
|
||||
grid.missing.remove(cell);
|
||||
}
|
||||
|
||||
function paint(origin) {
|
||||
var cellSet = CellSet.make(
|
||||
{type: 'isochrome', grid: Grid.get().colors, origin: origin}
|
||||
);
|
||||
cellSet.iter(colorize);
|
||||
CellSet.isochrome(Grid.get().colors, origin)
|
||||
.iter(function(cell) {colorize(cell);});
|
||||
}
|
||||
|
||||
function setColors(grid) {
|
||||
if(grid != undefined) {
|
||||
iter(grid, function(cell) {
|
||||
if(at(grid, cell) != undefined) {
|
||||
colorize(cell, at(grid, cell));
|
||||
function setColors(coloring) {
|
||||
if(coloring != undefined) {
|
||||
iter(coloring, function(color, cell) {
|
||||
if(color != undefined) {
|
||||
colorize(cell, color);
|
||||
}
|
||||
});
|
||||
if(Grid.get().missing.isEmpty()) {
|
||||
Mode.setEnabled(true, ['play', 'solve']);
|
||||
} else {
|
||||
if(Grid.get().missing.size() > 0) {
|
||||
Mode.set('edit');
|
||||
} else {
|
||||
Mode.setEnabled(true, ['play', 'solve']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
import * as Vector from Geometry.Vector;
|
||||
|
||||
return {
|
||||
make: make,
|
||||
at: at,
|
||||
asAFunction: asAFunction,
|
||||
column: column,
|
||||
generate: generate,
|
||||
iter: iter,
|
||||
|
@ -21,18 +23,39 @@ function generate(width, height, f) {
|
|||
return result;
|
||||
}
|
||||
|
||||
function make(width, height) {
|
||||
if(width instanceof Object && width.row != undefined) {
|
||||
height = width.row;
|
||||
width = width.column;
|
||||
}
|
||||
return Array.from({length: height}).map(
|
||||
function() {return Array.from({length: width});}
|
||||
);
|
||||
}
|
||||
|
||||
function iter(grid, f) {
|
||||
generate(grid.length > 0 ? grid[0].length : null, grid.length, f);
|
||||
map(grid, f);
|
||||
}
|
||||
|
||||
function map(grid, f) {
|
||||
return grid.map(function(rowArray, row) {return rowArray.map(
|
||||
function(value, column) {return f(value, Vector.make(row, column), grid);}
|
||||
)});
|
||||
}
|
||||
|
||||
function square(size, value) {
|
||||
return generate(size, size, function() {return value;});
|
||||
var generator = value instanceof Function ? value : function() {return value;};
|
||||
return map(make(size, size), function(_, cell) {return generator(cell);});
|
||||
}
|
||||
|
||||
function at(grid, vector) {
|
||||
return grid[vector.row][vector.column];
|
||||
}
|
||||
|
||||
function asAFunction(grid) {
|
||||
return function (vector) {return at(grid, vector);};
|
||||
}
|
||||
|
||||
function set(grid, vector, value) {
|
||||
return grid[vector.row][vector.column] = value;
|
||||
}
|
||||
|
|
|
@ -8,17 +8,15 @@ import * as Play from Mode.Play;
|
|||
import * as Solve from Mode.Solve;
|
||||
import * as Edit from Mode.Edit;
|
||||
|
||||
var size = 8;
|
||||
|
||||
Toolbox.init(size);
|
||||
Toolbox.init();
|
||||
Mode.init({
|
||||
play: Play,
|
||||
solve: Solve,
|
||||
edit: Edit
|
||||
});
|
||||
Grid.init(size, Mode.dispatch);
|
||||
Grid.init(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.Color.set(Share.decode(urlSearchParameters.get('game')));
|
||||
}
|
||||
Grid.IO.init();
|
||||
|
|
|
@ -23,7 +23,7 @@ return {
|
|||
|
||||
function onEnter() {
|
||||
GUI.activate(true, [Grid.get().root, Toolbox.get(), save]);
|
||||
if(!Grid.get().missing.isEmpty()) {
|
||||
if(Grid.get().missing.size() > 0) {
|
||||
Mode.setEnabled(false, ['play', 'solve']);
|
||||
} else {
|
||||
Share.link(Grid.get().colors);
|
||||
|
@ -65,7 +65,7 @@ function colorCell(cell) {
|
|||
}
|
||||
|
||||
function checkCompleteness() {
|
||||
if(Grid.get().missing.isEmpty()) {
|
||||
if(Grid.get().missing.size() < 1) {
|
||||
Mode.setEnabled(true, ['play', 'solve']);
|
||||
Share.link(Grid.get().colors);
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@ return {
|
|||
};
|
||||
|
||||
function onClick(e, cell) {
|
||||
if(Grid.get().missing.isEmpty()) {
|
||||
if(Grid.get().missing.size() < 1) {
|
||||
rotateState(at(Grid.get().cells, cell));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,5 +8,5 @@ return {
|
|||
};
|
||||
|
||||
function onEnter() {
|
||||
console.log(Solver.step(Grid.get().colors));
|
||||
console.log(Solver.solve(Grid.get().colors));
|
||||
}
|
||||
|
|
16
js/Set.js
16
js/Set.js
|
@ -1,12 +1,14 @@
|
|||
return {
|
||||
make: make
|
||||
make: make,
|
||||
Int: make({toKey: id, ofKey: parseInt})
|
||||
};
|
||||
|
||||
function id(x) {
|
||||
return x;
|
||||
}
|
||||
|
||||
function make(type) {
|
||||
if(type == undefined) {
|
||||
var id = function(x) {return x;};
|
||||
type = {toKey: id, ofKey: id};
|
||||
}
|
||||
type = type ?? {toKey: id, ofKey: id};
|
||||
|
||||
function Set(s) {
|
||||
this.elements = {};
|
||||
|
@ -65,5 +67,9 @@ function make(type) {
|
|||
return newSet;
|
||||
}
|
||||
|
||||
Set.uniq = function(t) {
|
||||
return (new Set(t)).toList();
|
||||
}
|
||||
|
||||
return Set;
|
||||
}
|
||||
|
|
13
js/Share.js
13
js/Share.js
|
@ -1,6 +1,8 @@
|
|||
import size from Config;
|
||||
import {at, generate, iter, square} from Grid.Util;
|
||||
import * as Decode from Share.Decoder.Protocol;
|
||||
import * as Encode from Share.Encoder.Protocol;
|
||||
import * as Encoder from Share.Encoder.Class;
|
||||
import GUI;
|
||||
import Grid;
|
||||
|
||||
|
@ -16,23 +18,24 @@ function get() {
|
|||
return share;
|
||||
}
|
||||
|
||||
function naiveEncode(grid) {
|
||||
function naiveEncode(coloring) {
|
||||
var encoder = Encoder.make();
|
||||
iter(grid, function(cell) {
|
||||
encoder.int(3)(at(grid, cell));
|
||||
iter(coloring, function(color) {
|
||||
encoder.int(3)(color);
|
||||
});
|
||||
return encoder.output();
|
||||
}
|
||||
|
||||
function naiveDecode(size, input) {
|
||||
function naiveDecode(input) {
|
||||
if(input != undefined) {
|
||||
var decoder = Decoder.make(input);
|
||||
return generate(size, size, function() {return decoder.int(3);});
|
||||
}
|
||||
}
|
||||
|
||||
function link(grid) {
|
||||
function link() {
|
||||
//share.href = '?game=' + naiveEncode(Grid.get().colors);
|
||||
console.log(naiveEncode(Grid.get().colors));
|
||||
share.href = '?game=' + Encode.grid(Grid.get().colors);
|
||||
GUI.activate(true, share);
|
||||
}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import size from Config;
|
||||
import * as CellSet from Geometry.CellSet;
|
||||
import * as Decoder from Share.Decoder.Class;
|
||||
import {diagonal, plus, zero} from Geometry.Vector;
|
||||
|
@ -8,12 +9,12 @@ return {
|
|||
grid: decodeGrid
|
||||
};
|
||||
|
||||
function decodeGrid(size, input) {
|
||||
function decodeGrid(input) {
|
||||
if(input != undefined) {
|
||||
return decoderLoop(
|
||||
Decoder.make(input),
|
||||
square(size),
|
||||
CellSet.make({type: 'rectangle', origin: zero(), offset: diagonal(size)})
|
||||
CellSet.rectangle(zero(), diagonal(size))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -44,7 +44,7 @@ Encoder.prototype.variableLength6 = function(n) {
|
|||
Encoder.prototype.int = function(size) {
|
||||
return function(n) {
|
||||
for(var i = 0; i < size; i++) {
|
||||
encoder.push(n > 3);
|
||||
this.push(n > 3);
|
||||
n = (2*n) & 7;
|
||||
}
|
||||
}.bind(this);
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
import {diagonal, isSmaller, plus} from Geometry.Vector;
|
||||
import * as Vector from Geometry.Vector;
|
||||
import * as Encoder from Share.Encoder.Class;
|
||||
import {at, iter, square} from Grid.Util;
|
||||
import * as Grid from Grid.Util;
|
||||
import * as Protocol from Share.Protocol;
|
||||
|
||||
return {
|
||||
|
@ -10,65 +13,55 @@ function encodeGrid(grid) {
|
|||
var encoder = Encoder.make();
|
||||
var done = square(grid.length, false);
|
||||
var gradients = square(grid.length);
|
||||
iter(grid, function(cell) {
|
||||
iter(grid, function(_, cell) {
|
||||
if(!at(done, cell)) {
|
||||
let block = getLongestBlock(grid, cell);
|
||||
if(block != undefined) {
|
||||
encodeBlock(encoder, block);
|
||||
if(block.size >= Protocol.MIN_BLOCK_SIZE) {
|
||||
encodeBlock(encoder, done, block);
|
||||
} else {
|
||||
encodeSingleCell(
|
||||
encoder,
|
||||
getColorGradient(gradients, grid, cell)
|
||||
getColorGradient(gradients, grid, done, cell)
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
return encoder.output();
|
||||
}
|
||||
|
||||
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
|
||||
};
|
||||
}
|
||||
var hSize = getStreak(Grid.row(grid, origin.row), origin.column, color);
|
||||
var vSize = getStreak(Grid.column(grid, origin.column), origin.row, color);
|
||||
return {
|
||||
isVertical: vSize > hSize,
|
||||
size: Math.max(hSize, vSize),
|
||||
color: color,
|
||||
origin: origin
|
||||
};
|
||||
}
|
||||
|
||||
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 getStreak(t, firstIndex, color) {
|
||||
var fromFirst = t.slice(firstIndex);
|
||||
var index = fromFirst.findIndex(
|
||||
function(x) {return x != color;}
|
||||
);
|
||||
return index >= 0 ? index : fromFirst.length;
|
||||
}
|
||||
|
||||
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) {
|
||||
function encodeBlock(encoder, done, block) {
|
||||
encoder.push(1);
|
||||
encoder.push(block.direction == 'vertical');
|
||||
encoder.push(block.isVertical);
|
||||
encoder.variableLength6(block.size - Protocol.MIN_BLOCK_SIZE);
|
||||
encoder.int(3)(block.color);
|
||||
var cell = Vector.make(block.origin.row, block.origin.column);
|
||||
for(var i = 0; i < block.size; i++) {
|
||||
Grid.set(done, cell, true);
|
||||
cell[block.isVertical ? 'row' : 'column']++;
|
||||
}
|
||||
}
|
||||
|
||||
function getColorGradient(gradients, grid, cell) {
|
||||
function getColorGradient(gradients, grid, done, cell) {
|
||||
if(at(gradients, cell) == undefined) {
|
||||
|
||||
}
|
||||
|
|
142
js/Solver.js
142
js/Solver.js
|
@ -1,114 +1,54 @@
|
|||
import * as CellSet from Geometry.CellSet;
|
||||
import set from Grid.Util;
|
||||
import * as Inclusion from Solver.Inclusion;
|
||||
import * as SingleCell from Solver.SingleCell;
|
||||
import * as State from Solver.State;
|
||||
import * as Strategy from Solver.Strategy;
|
||||
|
||||
return {
|
||||
step: step
|
||||
rate: rate,
|
||||
solve: solve,
|
||||
findNextStep: findNextStep
|
||||
};
|
||||
|
||||
function step(grid) {
|
||||
var zones = getZones(grid);
|
||||
var lines = getLines(grid.length);
|
||||
var rowClusters = checkRowsInclusions(grid);
|
||||
if(rowClusters.length > 0) {
|
||||
rowClusters.forEach(function(rowCluster) {
|
||||
rowCluster.toClear = difference(
|
||||
rowCluster.colors.map(function(color) {return zones[color];}),
|
||||
rowCluster.rows.map(function(row) {return lines.rows[row];})
|
||||
);
|
||||
});
|
||||
function solve(coloring) {
|
||||
var solvingState = State.start(coloring);
|
||||
var stuck = false;
|
||||
while(!stuck && solvingState.missing.size() > 0) {
|
||||
Strategy.execute(
|
||||
findNextStep(solvingState),
|
||||
applyStep(solvingState),
|
||||
function() {console.log('Solver is stuck'); stuck = true;}
|
||||
);
|
||||
}
|
||||
return rowClusters;
|
||||
return solvingState.constellation;
|
||||
}
|
||||
|
||||
function getZones(grid) {
|
||||
var zones = {};
|
||||
for(var row = 0; row < grid.length; row++) {
|
||||
for(var column = 0; column < grid[row].length; column++) {
|
||||
var color = grid[row][column];
|
||||
if(zones[color] == undefined) {
|
||||
zones[color] = CellSet.make(
|
||||
{type: 'isochrome', row: row, column: column, grid: grid}
|
||||
);
|
||||
function rate(coloring) {
|
||||
}
|
||||
|
||||
function findNextStep(solvingState) {
|
||||
return Strategy.tryEach([
|
||||
Inclusion.find(solvingState),
|
||||
SingleCell.find(solvingState)
|
||||
]);
|
||||
}
|
||||
|
||||
function applyStep(solvingState) {
|
||||
return function(step) {
|
||||
console.log(step);
|
||||
['empty', 'star'].forEach(function(attribute) {
|
||||
if(step[attribute] != undefined) {
|
||||
step[attribute].iter(function(cell) {
|
||||
set(solvingState.constellation, cell, attribute == 'star');
|
||||
forget(solvingState, cell);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
return zones;
|
||||
}
|
||||
|
||||
function line(type, size, i) {
|
||||
if(type == 'row') {
|
||||
return CellSet.make(
|
||||
{type: 'rectangle', row: i, column: 0, width: size, height: 1}
|
||||
);
|
||||
} else if(type == 'column') {
|
||||
return CellSet.make(
|
||||
{type: 'rectangle', row: 0, column: i, width: 1, height: size}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function getLines(size) {
|
||||
var empty = Array.from({length: size});
|
||||
return {
|
||||
rows: empty.map(function(x, i) {return line('row', size, i);}),
|
||||
columns: empty.map(function(x, i) {return line('column', size, i);}),
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
function getColorsByRow(grid) {
|
||||
var colorsByRow = [];
|
||||
for(var row = 0; row < grid.length; row++) {
|
||||
colorsByRow.push(
|
||||
quotient(grid[row], function(c0, c1) {return c0 == c1;}).map(
|
||||
function(colorClass) {return colorClass.specimen;}
|
||||
)
|
||||
);
|
||||
}
|
||||
return colorsByRow;
|
||||
}
|
||||
|
||||
function checkRowsInclusions(grid) {
|
||||
var colorsByRow = getColorsByRow(grid);
|
||||
var colorSets = quotient(colorsByRow, sameColorsSet);
|
||||
return colorSets.reduce(function(commands, colorSet) {
|
||||
if(colorSet.occurrences.length == colorSet.specimen.length) {
|
||||
commands.push({
|
||||
reason: 'rowsInColors',
|
||||
rows: colorSet.occurrences,
|
||||
colors: colorSet.specimen
|
||||
});
|
||||
}
|
||||
return commands;
|
||||
}, []);
|
||||
}
|
||||
|
||||
function quotient(elements, equivalence) {
|
||||
var classes = [];
|
||||
elements.forEach(function(element, i) {
|
||||
for(var c = 0; c < classes.length; c++) {
|
||||
if(equivalence(element, classes[c].specimen)) {
|
||||
classes[c].occurrences.push(i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
classes.push({specimen: element, occurrences: [i]});
|
||||
});
|
||||
return classes;
|
||||
}
|
||||
|
||||
function sameColorsSet(s0, s1) {
|
||||
if(s0.length != s1.length) {
|
||||
return false;
|
||||
}
|
||||
var o0 = {};
|
||||
s0.forEach(function(x) {o0[x] = true;});
|
||||
for(var i = 0; i < s1.length; i++) {
|
||||
if(!o0[s1[i]]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function difference(setsFrom, setsSubstracted) {
|
||||
return CellSet.union(setsFrom).difference(CellSet.union(setsSubstracted));
|
||||
function forget(solvingState, cell) {
|
||||
State.getCellSets(solvingState).concat(solvingState.missing)
|
||||
.forEach(function(cellSet) {cellSet.remove(cell);});
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@ return {
|
|||
function find(solvingState) {
|
||||
var cellSets = getCellSets(solvingState);
|
||||
return Strategy.map(
|
||||
stepOfCell,
|
||||
stepOfCell(solvingState.missing),
|
||||
Strategy.tryEach(cellSets.map(getSingleCellIn))
|
||||
);
|
||||
}
|
||||
|
@ -23,11 +23,13 @@ function getSingleCellIn(cellSet) {
|
|||
};
|
||||
}
|
||||
|
||||
function stepOfCell(cell) {
|
||||
return {
|
||||
reason: 'singleCell',
|
||||
empty: toEmpty(cell),
|
||||
star: new CellSet.CellSet(cell)
|
||||
function stepOfCell(missing) {
|
||||
return function(cell) {
|
||||
return {
|
||||
reason: 'singleCell',
|
||||
empty: toEmpty(cell).intersection(missing),
|
||||
star: new CellSet.CellSet(cell)
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
import size from Config;
|
||||
import {asAFunction, iter, square} from Grid.Util;
|
||||
import {diagonal, zero} from Geometry.Vector;
|
||||
import * as CellSet from Geometry.CellSet;
|
||||
|
||||
return {
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import size from Config;
|
||||
import * as Dom from UnitJS.Dom;
|
||||
|
||||
var toolbox;
|
||||
|
@ -11,7 +12,7 @@ return {
|
|||
tool: tool
|
||||
};
|
||||
|
||||
function init(size, elementId) {
|
||||
function init(elementId) {
|
||||
toolbox = document.getElementById(elementId || 'toolbox');
|
||||
colors = toolbox.querySelector('#colors');
|
||||
for(var i = 0; i < size; i++) {
|
||||
|
|
Loading…
Reference in a new issue