Implement hypothesis solver (no recursivity yet); solves all known grids

This commit is contained in:
Tissevert 2022-10-23 23:13:49 +02:00
parent e8d0db8b1d
commit 42dc3e394c
6 changed files with 81 additions and 56 deletions

View file

@ -1,12 +1,13 @@
import * as Vector from Geometry.Vector; import * as Vector from Geometry.Vector;
return { return {
make: make,
at: at, at: at,
asAFunction: asAFunction, asAFunction: asAFunction,
column: column, column: column,
generate: generate, generate: generate,
iter: iter, iter: iter,
make: make,
map: map,
row: row, row: row,
set: set, set: set,
square: square square: square

View file

@ -40,7 +40,9 @@ function applyStep(solvingState) {
console.log(step); console.log(step);
['empty', 'star'].forEach(function(attribute) { ['empty', 'star'].forEach(function(attribute) {
if(step[attribute] != undefined) { 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]);
} }
}); });
}; };

View file

@ -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 State from Solver.State;
import * as Strategy from Solver.Strategy;
return { return {
find: find find: find
}; };
function find(solvingState) { 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) { return function(cell) {
var forked = State.fork(solvingState); return function() {
State.set(forked, cell, true); 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
}

View file

@ -8,7 +8,7 @@ return {
}; };
function find(solvingState) { function find(solvingState) {
var inclusion = findInclusion(cellDimensionsByname(solvingState)); var inclusion = findInclusion(cellDimensionsByName(solvingState));
return Strategy.tryEach([ return Strategy.tryEach([
inclusion('rows', 'colors'), inclusion('rows', 'colors'),
inclusion('columns', 'colors'), inclusion('columns', 'colors'),
@ -17,11 +17,11 @@ function find(solvingState) {
]); ]);
} }
function cellDimensionsByname(solvingState) { function cellDimensionsByName(solvingState) {
return { return {
rows: {sets: solvingState.rows, property: getRow}, rows: {sets: solvingState.zones.rows, property: getRow},
columns: {sets: solvingState.columns, property: getColumn}, columns: {sets: solvingState.zones.columns, property: getColumn},
colors: {sets: solvingState.colorZones, property: solvingState.getColor} colors: {sets: solvingState.zones.colors, property: solvingState.getColor}
}; };
} }

View file

@ -1,16 +1,21 @@
import * as CellSet from Geometry.CellSet; import * as CellSet from Geometry.CellSet;
import * as Strategy from Solver.Strategy; import * as Strategy from Solver.Strategy;
import * as State from Solver.State;
import {diagonal, getColumn, getRow, plus} from Geometry.Vector; import {diagonal, getColumn, getRow, plus} from Geometry.Vector;
return { return {
find: find, find: find,
perimeter: perimeter getRange: getRange
}; };
function find(solvingState) { function find(solvingState) {
return Strategy.map( return Strategy.tryEach(
stepOfCell(solvingState.missing), State.zoneNames(solvingState).map(function(name) {
Strategy.tryEach(solvingState.colorZones.map(getSingleCellIn)) 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 function(cell) {
return { return {
reason: 'singleCell', reason: 'singleCell',
empty: perimeter(cell).intersection(missing), set: name,
empty: getRange(solvingState, cell),
star: new CellSet.CellSet(cell) star: new CellSet.CellSet(cell)
}; };
}; };
} }
function perimeter(cell) { function getRange(solvingState, cell) {
var union = CellSet.union([ var union = CellSet.union([
CellSet.rectangle(plus(cell, diagonal(-1)), diagonal(3)), solvingState.zones.colors[solvingState.getColor(cell)],
CellSet.row(getRow(cell)), solvingState.zones.rows[getRow(cell)],
CellSet.column(getColumn(cell)) solvingState.zones.columns[getColumn(cell)],
CellSet.rectangle(plus(cell, diagonal(-1)), diagonal(3))
.intersection(solvingState.missing)
]); ]);
union.remove(cell); union.remove(cell);
return union; return union;

View file

@ -4,12 +4,11 @@ import {asAFunction, iter, map, set, square} from Grid.Util;
import {diagonal, zero} from Geometry.Vector; import {diagonal, zero} from Geometry.Vector;
import * as CellSet from Geometry.CellSet; import * as CellSet from Geometry.CellSet;
var zoneNames = ['colors', 'rows', 'columns'];
return { return {
setCell: setCell, fork: fork,
setCells: setCells,
start: start, start: start,
fork: fork zoneNames: zoneNames
}; };
function start(coloring) { function start(coloring) {
@ -39,9 +38,9 @@ function getColors(grid) {
function fork(state) { function fork(state) {
var zones = {}; var zones = {};
zoneNames.forEach(function(name) { for(var name in state.zones) {
zones[name] = state.zones[name].map(function(s) {return s.copy();}); zones[name] = state.zones[name].map(function(s) {return s.copy();});
}); }
return { return {
constellation: map(state.constellation, id), constellation: map(state.constellation, id),
getColor: state.getColor, getColor: state.getColor,
@ -50,30 +49,22 @@ function fork(state) {
}; };
} }
function setCells(solvingState, value) { function setCells(solvingState, value, cellSet) {
return function(cellSet) { var forgetList = allZones(solvingState).concat(solvingState.missing);
for(var i = 0; i < zoneNames.length; i++) { cellSet.iter(function(cell) {
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
set(solvingState.constellation, cell, value); set(solvingState.constellation, cell, value);
forgetList.forEach(function(solverSet) {
solverSet.remove(cell);
});
});
} }
function f(zone, cellSet) { function zoneNames(solvingState) {
if(zone.size() > 0) { return Object.keys(solvingState.zones);
var diff = zone.difference(cellSet); }
if(diff.
} function allZones(solvingState) {
return zoneNames(solvingState).flatMap(function(name) {
return solvingState.zones[name];
});
} }