diff --git a/js/Solver/Inclusion.js b/js/Solver/Inclusion.js index 16e46b6..d51bcdb 100644 --- a/js/Solver/Inclusion.js +++ b/js/Solver/Inclusion.js @@ -1,82 +1,83 @@ import * as CellSet from Geometry.CellSet; import * as Strategy from Solver.Strategy; import {getColumn, getRow} from Geometry.Vector; +import Set; 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 find(solvingState) { + var inclusion = findInclusion(cellDimensionsByname(solvingState)); + return Strategy.tryEach([ + inclusion('rows', 'colors'), + inclusion('columns', 'colors'), + inclusion('colors', 'rows'), + inclusion('colors', 'columns') + ]); } -function findInclusion(subsets, supersets, property) { - return Strategy.tryEach( - quotient(subsets.map(getClasses(property)), sameSet) - .map(keepInclusion(subsets, supersets)) - ); +function cellDimensionsByname(solvingState) { + return { + rows: {sets: solvingState.rows, property: getRow}, + columns: {sets: solvingState.columns, property: getColumn}, + colors: {sets: solvingState.colorZones, property: solvingState.getColor} + }; } -function keepInclusion(subsets, supersets) { - return function(set) { +function getAll(property) { + return function(cellSet) {return new Set.Int(cellSet.map(property));}; +} + +function getSet(namedSet) { + return function(i) {return namedSet.sets[i];}; +} + +function findInclusion(cellDimensions) { + return function(subName, superName) { + var subDimension = cellDimensions[subName]; + var superDimension = cellDimensions[superName]; + var diff = difference(getSet(subDimension), getSet(superDimension)); + return Strategy.map( + stepOfInclusion(subName, superName), + Strategy.tryEach( + group(subDimension.sets.map(getAll(superDimension.property))).map(diff) + ) + ); + } +} + +function difference(getSubset, getSuperset) { + return function(group) { 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; + if(group.indices.length == group.value.size()) { + var empty = CellSet.union(group.value.map(getSuperset)) + .difference(CellSet.union(group.indices.map(getSubset))); + return empty.size() > 0 ? {empty: empty, group: group} : null; } }; }; } -function stepOfInclusion(inclusion) { - return { - reason: 'inclusion', - empty: difference(inclusion.superset, inclusion.subset), +function stepOfInclusion(subName, superName) { + return function(diffedGroup) { + var step = {reason: 'inclusion', empty: diffedGroup.empty}; + step[subName] = diffedGroup.group.indices; + step['in_' + superName] = diffedGroup.group.value.toList(); + return step; }; } -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); +function group(sets) { + var groups = []; + sets.forEach(function(set, i) { + for(var g = 0; g < groups.length; g++) { + if(groups[g].value.equals(set)) { + groups[g].indices.push(i); return; } } - classes.push({specimen: element, occurrences: [i]}); + groups.push({value: set, indices: [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)); + return groups; } diff --git a/js/Solver/SingleCell.js b/js/Solver/SingleCell.js index 95e41ab..d00c870 100644 --- a/js/Solver/SingleCell.js +++ b/js/Solver/SingleCell.js @@ -1,14 +1,16 @@ +import * as CellSet from Geometry.CellSet; +import getCellSets from Solver.State; import * as Strategy from Solver.Strategy; -import {diagonal, plus} from Geometry.Vector; +import {diagonal, getColumn, getRow, plus} from Geometry.Vector; return { find: find }; -function find(zones, lines) { - var cellSets = zones.concat(lines.rows).concat(lines.columns); +function find(solvingState) { + var cellSets = getCellSets(solvingState); return Strategy.map( - stepOfCell(cellSets), + stepOfCell, Strategy.tryEach(cellSets.map(getSingleCellIn)) ); } @@ -16,27 +18,25 @@ function find(zones, lines) { function getSingleCellIn(cellSet) { return function() { if(cellSet.size() == 1) { - return cellSet.getAll(function(v) {return v;})[0]; + return cellSet.toList()[0]; } }; } -function stepOfCell(cellSets) { - return function(cell) { - return { - reason: 'singleCell', - empty: toEmpty(cell).intersection(cellSets), - star: CellSet.cells([cell]) - }; +function stepOfCell(cell) { + return { + reason: 'singleCell', + empty: toEmpty(cell), + star: new CellSet.CellSet(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()) + var union = CellSet.union([ + CellSet.rectangle(plus(cell, diagonal(-1)), diagonal(3)), + CellSet.row(getRow(cell)), + CellSet.column(getColumn(cell)) ]); + union.remove(cell); + return union; } diff --git a/js/Solver/State.js b/js/Solver/State.js new file mode 100644 index 0000000..cc65fd5 --- /dev/null +++ b/js/Solver/State.js @@ -0,0 +1,35 @@ +import * as CellSet from Geometry.CellSet; + +return { + getCellSets: getCellSets, + start: start +}; + +function start(coloring) { + var empty = Array.from({length: size}); + return { + constellation: square(size), + getColor: asAFunction(coloring), + missing: CellSet.rectangle(zero(), diagonal(size)), + colorZones: getZones(coloring), + rows: empty.map(function(_, i) {return CellSet.row(i);}), + columns: empty.map(function(_, i) {return CellSet.column(i);}) + }; +} + +function getZones(grid) { + var zones = Array.from({length: size}); + iter(grid, function(color, cell) { + if(zones[color] == undefined) { + zones[color] = new CellSet.CellSet(); + } + zones[color].add(cell); + }); + return zones; +} + +function getCellSets(solvingState) { + return solvingState.colorZones + .concat(solvingState.rows) + .concat(solvingState.columns); +}