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