From 42dc3e394c7a2c8e62c91eb5fcaace745999c312 Mon Sep 17 00:00:00 2001 From: Tissevert Date: Sun, 23 Oct 2022 23:13:49 +0200 Subject: [PATCH] Implement hypothesis solver (no recursivity yet); solves all known grids --- js/Grid/Util.js | 3 ++- js/Solver.js | 4 +++- js/Solver/Hypothesis.js | 43 +++++++++++++++++++++++++++--------- js/Solver/Inclusion.js | 10 ++++----- js/Solver/SingleCell.js | 28 ++++++++++++++--------- js/Solver/State.js | 49 +++++++++++++++++------------------------ 6 files changed, 81 insertions(+), 56 deletions(-) diff --git a/js/Grid/Util.js b/js/Grid/Util.js index 6e9bad5..e4dd274 100644 --- a/js/Grid/Util.js +++ b/js/Grid/Util.js @@ -1,12 +1,13 @@ import * as Vector from Geometry.Vector; return { - make: make, at: at, asAFunction: asAFunction, column: column, generate: generate, iter: iter, + make: make, + map: map, row: row, set: set, square: square diff --git a/js/Solver.js b/js/Solver.js index d17bd44..8ad09c2 100644 --- a/js/Solver.js +++ b/js/Solver.js @@ -40,7 +40,9 @@ function applyStep(solvingState) { console.log(step); ['empty', 'star'].forEach(function(attribute) { if(step[attribute] != undefined) { - step[attribute].iter(State.setCell(solvingState, attribute == 'star')); + //step[attribute].iter(State.setCells(solvingState, attribute == 'star')); + State.setCells(solvingState, attribute == 'star', step[attribute]); + // ?? why is curryfication needed above ? State.setCells(solvingState, attribute == 'star', step[attribute]); } }); }; diff --git a/js/Solver/Hypothesis.js b/js/Solver/Hypothesis.js index 3b696ae..36c3c35 100644 --- a/js/Solver/Hypothesis.js +++ b/js/Solver/Hypothesis.js @@ -1,21 +1,44 @@ -import perimeter from Solver.SingleCell; +import getRange from Solver.SingleCell; +import CellSet from Geometry.CellSet; import * as State from Solver.State; +import * as Strategy from Solver.Strategy; return { find: find }; function find(solvingState) { - solvingState.missing.map(f(solvingState)) -}; + return Strategy.tryEach( + solvingState.missing.map(findContradiction(solvingState)) + ); +} -function f(solvingState) { +function findContradiction(solvingState) { return function(cell) { - var forked = State.fork(solvingState); - State.set(forked, cell, true); + return function() { + var forked = State.fork(solvingState); + State.setCells(forked, false, getRange(forked, cell)); + return getContradiction(solvingState, forked, cell); + }; + }; +} + +function stepOfContradiction(cell, name, i) { + var step = { + reason: 'noStarLeft', + empty: new CellSet(cell), + }; + step['in_' + name] = i; + return step; +} + +function getContradiction(beforeState, afterState, cell) { + for(var name in beforeState.zones) { + var zones = beforeState.zones[name]; + for(var i = 0; i < zones.length; i++) { + if(zones[i].size() > 0 && afterState.zones[name][i].size() < 1) { + return stepOfContradiction(cell, name, i); + } + } } } - -function checkContradiction(beforeState, afterState, cell) { - //TODO has one cellSet (color, row, column) become empty ? if it doesn't contain cell, it's a contradiction -} diff --git a/js/Solver/Inclusion.js b/js/Solver/Inclusion.js index d51bcdb..a137050 100644 --- a/js/Solver/Inclusion.js +++ b/js/Solver/Inclusion.js @@ -8,7 +8,7 @@ return { }; function find(solvingState) { - var inclusion = findInclusion(cellDimensionsByname(solvingState)); + var inclusion = findInclusion(cellDimensionsByName(solvingState)); return Strategy.tryEach([ inclusion('rows', 'colors'), inclusion('columns', 'colors'), @@ -17,11 +17,11 @@ function find(solvingState) { ]); } -function cellDimensionsByname(solvingState) { +function cellDimensionsByName(solvingState) { return { - rows: {sets: solvingState.rows, property: getRow}, - columns: {sets: solvingState.columns, property: getColumn}, - colors: {sets: solvingState.colorZones, property: solvingState.getColor} + rows: {sets: solvingState.zones.rows, property: getRow}, + columns: {sets: solvingState.zones.columns, property: getColumn}, + colors: {sets: solvingState.zones.colors, property: solvingState.getColor} }; } diff --git a/js/Solver/SingleCell.js b/js/Solver/SingleCell.js index ddb4e4c..20779a8 100644 --- a/js/Solver/SingleCell.js +++ b/js/Solver/SingleCell.js @@ -1,16 +1,21 @@ import * as CellSet from Geometry.CellSet; import * as Strategy from Solver.Strategy; +import * as State from Solver.State; import {diagonal, getColumn, getRow, plus} from Geometry.Vector; return { find: find, - perimeter: perimeter + getRange: getRange }; function find(solvingState) { - return Strategy.map( - stepOfCell(solvingState.missing), - Strategy.tryEach(solvingState.colorZones.map(getSingleCellIn)) + return Strategy.tryEach( + State.zoneNames(solvingState).map(function(name) { + return Strategy.map( + stepOfCell(solvingState, name), + Strategy.tryEach(solvingState.zones[name].map(getSingleCellIn)) + ); + }) ); } @@ -22,21 +27,24 @@ function getSingleCellIn(cellSet) { }; } -function stepOfCell(missing) { +function stepOfCell(solvingState, name) { return function(cell) { return { reason: 'singleCell', - empty: perimeter(cell).intersection(missing), + set: name, + empty: getRange(solvingState, cell), star: new CellSet.CellSet(cell) }; }; } -function perimeter(cell) { +function getRange(solvingState, cell) { var union = CellSet.union([ - CellSet.rectangle(plus(cell, diagonal(-1)), diagonal(3)), - CellSet.row(getRow(cell)), - CellSet.column(getColumn(cell)) + solvingState.zones.colors[solvingState.getColor(cell)], + solvingState.zones.rows[getRow(cell)], + solvingState.zones.columns[getColumn(cell)], + CellSet.rectangle(plus(cell, diagonal(-1)), diagonal(3)) + .intersection(solvingState.missing) ]); union.remove(cell); return union; diff --git a/js/Solver/State.js b/js/Solver/State.js index 67f1515..a3fe7fb 100644 --- a/js/Solver/State.js +++ b/js/Solver/State.js @@ -4,12 +4,11 @@ import {asAFunction, iter, map, set, square} from Grid.Util; import {diagonal, zero} from Geometry.Vector; import * as CellSet from Geometry.CellSet; -var zoneNames = ['colors', 'rows', 'columns']; - return { - setCell: setCell, + fork: fork, + setCells: setCells, start: start, - fork: fork + zoneNames: zoneNames }; function start(coloring) { @@ -39,9 +38,9 @@ function getColors(grid) { function fork(state) { var zones = {}; - zoneNames.forEach(function(name) { + for(var name in state.zones) { zones[name] = state.zones[name].map(function(s) {return s.copy();}); - }); + } return { constellation: map(state.constellation, id), getColor: state.getColor, @@ -50,30 +49,22 @@ function fork(state) { }; } -function setCells(solvingState, value) { - return function(cellSet) { - for(var i = 0; i < zoneNames.length; i++) { - for(var j = 0; j < size; j++) { - f(solvingState.zones[field][j], cellSet) - } - } - var field = zoneNames[i]; - var zone = solvingState.zones[field][j]; - if(zone.size() > 0) { - var diff = - }); - solvingState.colorZones - .concat(solvingState.rows) - .concat(solvingState.columns) - .concat(solvingState.missing) - .forEach(function(cellSet) {cellSet.remove(cell);}); - solvingState.missing +function setCells(solvingState, value, cellSet) { + var forgetList = allZones(solvingState).concat(solvingState.missing); + cellSet.iter(function(cell) { set(solvingState.constellation, cell, value); + forgetList.forEach(function(solverSet) { + solverSet.remove(cell); + }); + }); } -function f(zone, cellSet) { - if(zone.size() > 0) { - var diff = zone.difference(cellSet); - if(diff. - } +function zoneNames(solvingState) { + return Object.keys(solvingState.zones); +} + +function allZones(solvingState) { + return zoneNames(solvingState).flatMap(function(name) { + return solvingState.zones[name]; + }); }