From 43900cfb64b52ee53040ea7c2fe9b8a894a8cce7 Mon Sep 17 00:00:00 2001 From: Tissevert Date: Sun, 31 Jul 2022 16:32:24 +0200 Subject: [PATCH] Start implementing the solver --- js/CellSet.js | 44 ++++++++++++++---- js/Grid.js | 2 +- js/Grid/Color.js | 4 +- js/Mode/Solve.js | 4 ++ js/Solver.js | 114 +++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 156 insertions(+), 12 deletions(-) create mode 100644 js/Solver.js diff --git a/js/CellSet.js b/js/CellSet.js index e7d7439..8f24886 100644 --- a/js/CellSet.js +++ b/js/CellSet.js @@ -5,22 +5,24 @@ function CellSet(definition) { this.fromRectangle(definition); } else if(definition.type == 'isochrome') { this.fromIsochrome(definition); + } else if(definition.type == 'union') { + this.fromUnion(definition.sets); } } CellSet.prototype.fromRectangle = function(definition) { - var xMax = definition.x + definition.width; - var yMax = definition.y + definition.height; - for(var i = definition.x; i < xMax; i++) { - for(var j = definition.y; j < yMax; j++) { + var iMax = definition.row + definition.height; + var jMax = definition.column + definition.width; + for(var i = definition.row; i < iMax; i++) { + for(var j = definition.column; j < jMax; j++) { this.add(i, j); } } }; CellSet.prototype.fromIsochrome = function(definition) { - var originColor = definition.data[definition.x][definition.y]; - var queue = [{i: definition.x, j: definition.y}]; + var originColor = definition.data[definition.row][definition.column]; + var queue = [{i: definition.row, j: definition.column}]; while(queue.length > 0) { var p = queue[0]; this.add(p.i, p.j); @@ -33,6 +35,14 @@ CellSet.prototype.fromIsochrome = function(definition) { } }; +CellSet.prototype.fromUnion = function(sets) { + for(var i = 0; i < sets.length; i++) { + for(var key in sets[i].cells) { + this.cells[key] = true; + } + } +} + CellSet.prototype.add = function(i, j) { this.cells[id(i, j)] = true; }; @@ -49,15 +59,31 @@ CellSet.prototype.isEmpty = function() { return Object.keys(this.cells).length < 1; }; -CellSet.prototype.iter = function(f) { +CellSet.prototype.map = function(f) { + var result = []; for(var key in this.cells) { - var coordinates = key.split(':'); - f(coordinates[0], coordinates[1]); + result.push(f.apply(null, key.split(':'))); } + return result; +} + +CellSet.prototype.iter = function(f) { + this.map(f); +} + +CellSet.prototype.difference = function(cellSet) { + var newCellSet = new CellSet(); + this.iter(function(i, j) { + if(!cellSet.contains(i, j)) { + newCellSet.add(i, j); + } + }); + return newCellSet; } return { make: function(definition) {return new CellSet(definition);}, + union: function(sets) {return new CellSet({type: 'union', sets: sets});} }; function id(i, j) { diff --git a/js/Grid.js b/js/Grid.js index 29599af..69bd1bc 100644 --- a/js/Grid.js +++ b/js/Grid.js @@ -39,7 +39,7 @@ function makeRow(config) { function clear() { grid.data = generate(function() {return; }); grid.missing = CellSet.make( - {type: 'rectangle', x: 0, y: 0, width: 8, height: 8} + {type: 'rectangle', row: 0, column: 0, width: 8, height: 8} ); iter(function(row, column) { cell(row, column).className = ''; diff --git a/js/Grid/Color.js b/js/Grid/Color.js index 041c557..17a3ee7 100644 --- a/js/Grid/Color.js +++ b/js/Grid/Color.js @@ -14,9 +14,9 @@ function colorize(row, column, color) { grid.missing.remove(row, column); } -function paint(i0, j0) { +function paint(row, column) { var cellSet = CellSet.make( - {type: 'isochrome', x: i0, y: j0, data: Grid.get().data} + {type: 'isochrome', row: row, column: column, data: Grid.get().data} ); cellSet.iter(colorize); } diff --git a/js/Mode/Solve.js b/js/Mode/Solve.js index f80ae81..d8f959e 100644 --- a/js/Mode/Solve.js +++ b/js/Mode/Solve.js @@ -1,3 +1,6 @@ +import Grid; +import Solver; + return { events: { onEnter: onEnter, @@ -5,4 +8,5 @@ return { }; function onEnter() { + console.log(Solver.step(Grid.get().data)); } diff --git a/js/Solver.js b/js/Solver.js new file mode 100644 index 0000000..15c14b6 --- /dev/null +++ b/js/Solver.js @@ -0,0 +1,114 @@ +import CellSet; + +return { + step: step +}; + +function step(matrix) { + var zones = getZones(matrix); + var grid = getGrid(matrix.length); + var rowClusters = checkRowsInclusions(matrix); + if(rowClusters.length > 0) { + rowClusters.forEach(function(rowCluster) { + rowCluster.toClear = difference( + rowCluster.colors.map(function(color) {return zones[color];}), + rowCluster.rows.map(function(row) {return grid.rows[row];}) + ); + }); + } + return rowClusters; +} + +function getZones(matrix) { + var zones = {}; + for(var row = 0; row < matrix.length; row++) { + for(var column = 0; column < matrix[row].length; column++) { + var color = matrix[row][column]; + if(zones[color] == undefined) { + zones[color] = CellSet.make( + {type: 'isochrome', row: row, column: column, data: matrix} + ); + } + } + } + return zones; +} + +function line(type, size, i) { + if(type == 'row') { + return CellSet.make( + {type: 'rectangle', row: i, column: 0, width: size, height: 1} + ); + } else if(type == 'column') { + return CellSet.make( + {type: 'rectangle', row: 0, column: i, width: 1, height: size} + ); + } +} + +function getGrid(size) { + var empty = Array.from({length: size}); + return { + rows: empty.map(function(x, i) {return line('row', size, i);}), + columns: empty.map(function(x, i) {return line('column', size, i);}), + }; +} + +function getColorsByRow(matrix) { + var colorsByRow = []; + for(var row = 0; row < matrix.length; row++) { + colorsByRow.push( + quotient(matrix[row], function(c0, c1) {return c0 == c1;}).map( + function(colorClass) {return colorClass.specimen;} + ) + ); + } + return colorsByRow; +} + +function checkRowsInclusions(matrix) { + var colorsByRow = getColorsByRow(matrix); + var colorSets = quotient(colorsByRow, sameColorsSet); + return colorSets.reduce(function(commands, colorSet) { + if(colorSet.occurrences.length == colorSet.specimen.length) { + commands.push({ + reason: 'rowsInColors', + rows: colorSet.occurrences, + colors: colorSet.specimen + }); + } + return commands; + }, []); +} + +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 sameColorsSet(s0, s1) { + if(s0.length != s1.length) { + return false; + } + var o0 = {}; + s0.forEach(function(x) {o0[x] = true;}); + for(var i = 0; i < s1.length; i++) { + if(!o0[s1[i]]) { + return false; + } + } + return true; +} + +function difference(setsFrom, setsSubstracted) { + return CellSet.union(setsFrom).difference(CellSet.union(setsSubstracted)); +}