Expand solver and structure its design
This commit is contained in:
parent
671bfdcb5f
commit
ac7cd6333b
4 changed files with 158 additions and 0 deletions
3
js/Config.js
Normal file
3
js/Config.js
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
return {
|
||||||
|
size: 8
|
||||||
|
}
|
82
js/Solver/Inclusion.js
Normal file
82
js/Solver/Inclusion.js
Normal file
|
@ -0,0 +1,82 @@
|
||||||
|
import * as CellSet from Geometry.CellSet;
|
||||||
|
import * as Strategy from Solver.Strategy;
|
||||||
|
import {getColumn, getRow} from Geometry.Vector;
|
||||||
|
|
||||||
|
return {
|
||||||
|
find: find
|
||||||
|
};
|
||||||
|
|
||||||
|
function find(getColor, zones, lines) {
|
||||||
|
return Strategy.map(
|
||||||
|
stepOfInclusion,
|
||||||
|
Strategy.tryEach([
|
||||||
|
findInclusion(lines.rows, zones, getColor),
|
||||||
|
findInclusion(lines.columns, zones, getColor),
|
||||||
|
findInclusion(zones, lines.rows, getRow),
|
||||||
|
findInclusion(zones, lines.columns, getColumn)
|
||||||
|
])
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function findInclusion(subsets, supersets, property) {
|
||||||
|
return Strategy.tryEach(
|
||||||
|
quotient(subsets.map(getClasses(property)), sameSet)
|
||||||
|
.map(keepInclusion(subsets, supersets))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function keepInclusion(subsets, supersets) {
|
||||||
|
return function(set) {
|
||||||
|
return function() {
|
||||||
|
if(set.occurrences.length == set.specimen.length) {
|
||||||
|
var superset = set.specimen.map(function(i) {return supersets[i];});
|
||||||
|
var subset = set.specimen.map(function(i) {return subsets[i];});
|
||||||
|
empty = difference(superset, subset);
|
||||||
|
return empty.isEmpty() ? null : empty;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function stepOfInclusion(inclusion) {
|
||||||
|
return {
|
||||||
|
reason: 'inclusion',
|
||||||
|
empty: difference(inclusion.superset, inclusion.subset),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
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 getClasses(property) {
|
||||||
|
return function(cellSet) {
|
||||||
|
return Array.from(quotient(
|
||||||
|
cellSet.getAll(property), function(a, b) {return a == b;})
|
||||||
|
.map(function(equivClass) {return equivClass.specimen;})
|
||||||
|
).sort();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function sameSet(s0, s1) {
|
||||||
|
for(var i = 0; i < s0.length; i++) {
|
||||||
|
if(i >= s1.length || s0[i] != s1[i]) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function difference(supersets, subsets) {
|
||||||
|
return CellSet.union(supersets).difference(CellSet.union(subsets));
|
||||||
|
}
|
42
js/Solver/SingleCell.js
Normal file
42
js/Solver/SingleCell.js
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
import * as Strategy from Solver.Strategy;
|
||||||
|
import {diagonal, plus} from Geometry.Vector;
|
||||||
|
|
||||||
|
return {
|
||||||
|
find: find
|
||||||
|
};
|
||||||
|
|
||||||
|
function find(zones, lines) {
|
||||||
|
var cellSets = zones.concat(lines.rows).concat(lines.columns);
|
||||||
|
return Strategy.map(
|
||||||
|
stepOfCell(cellSets),
|
||||||
|
Strategy.tryEach(cellSets.map(getSingleCellIn))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getSingleCellIn(cellSet) {
|
||||||
|
return function() {
|
||||||
|
if(cellSet.size() == 1) {
|
||||||
|
return cellSet.getAll(function(v) {return v;})[0];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function stepOfCell(cellSets) {
|
||||||
|
return function(cell) {
|
||||||
|
return {
|
||||||
|
reason: 'singleCell',
|
||||||
|
empty: toEmpty(cell).intersection(cellSets),
|
||||||
|
star: CellSet.cells([cell])
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function toEmpty(cell) {
|
||||||
|
var around = CellSet.rectangle(plus(cell, diagonal(-1)), diagonal(2));
|
||||||
|
around.remove(v);
|
||||||
|
return CellSet.union([
|
||||||
|
around,
|
||||||
|
CellSet.row(v.getRow()),
|
||||||
|
CellSet.column(v.getColumn())
|
||||||
|
]);
|
||||||
|
}
|
31
js/Solver/Strategy.js
Normal file
31
js/Solver/Strategy.js
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
return {
|
||||||
|
execute: execute,
|
||||||
|
tryEach: tryEach,
|
||||||
|
map: map
|
||||||
|
}
|
||||||
|
|
||||||
|
function tryEach(strategies) {
|
||||||
|
return function() {
|
||||||
|
for(var i = 0; i < strategies.length; i++) {
|
||||||
|
var result = strategies[i]();
|
||||||
|
if(result != undefined) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function execute(strategy, onSuccess, onError) {
|
||||||
|
var result = strategy();
|
||||||
|
if(result != undefined) {
|
||||||
|
return onSuccess(result);
|
||||||
|
} else {
|
||||||
|
return onError(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function map(f, strategy) {
|
||||||
|
return function() {
|
||||||
|
return execute(strategy, f, function() {return;});
|
||||||
|
};
|
||||||
|
}
|
Loading…
Reference in a new issue