Implement hypothesis solver (no recursivity yet); solves all known grids
This commit is contained in:
parent
e8d0db8b1d
commit
42dc3e394c
6 changed files with 81 additions and 56 deletions
|
@ -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
|
||||||
|
|
|
@ -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]);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
|
@ -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
|
|
||||||
}
|
|
||||||
|
|
|
@ -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}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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];
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue