Constellations/js/Solver/Inclusion.js

83 lines
2.0 KiB
JavaScript

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