UNPKG

@logic-pad/core

Version:
60 lines (59 loc) 2.14 kB
import Z3Module from './z3Module.js'; import { Point } from 'grilops'; import { instance as cellCountInstance, } from '../../../rules/cellCountRule.js'; import { Color } from '../../../primitives.js'; export default class CellCountModule extends Z3Module { constructor() { super(...arguments); Object.defineProperty(this, "id", { enumerable: true, configurable: true, writable: true, value: cellCountInstance.id }); } encode(grid, ctx) { const rules = grid.rules.filter(rule => rule.id === this.id); // optimizations if (rules.length === 0) { return; } const colorMap = new Map(); for (const rule of rules) { if (colorMap.has(rule.color)) { if (colorMap.get(rule.color) !== rule.count) { ctx.solver.add(ctx.ctx.Bool.val(false)); return; } } else { colorMap.set(rule.color, rule.count); } } for (const [color, count] of colorMap.entries()) { const { min, max } = grid.getColorCount(color); if (min > count || max < count) { ctx.solver.add(ctx.ctx.Bool.val(false)); return; } } if (colorMap.has(Color.Light) && colorMap.has(Color.Dark)) { if (colorMap.get(Color.Light) + colorMap.get(Color.Dark) !== grid.getTileCount(true)) { ctx.solver.add(ctx.ctx.Bool.val(false)); return; } } // encode for real for (const [color, count] of colorMap.entries()) { const sumTerms = []; grid.forEach((tile, x, y) => { if (tile.exists) { sumTerms.push(ctx.ctx.If(ctx.grid.cellAt(new Point(y, x)).eq(ctx.symbolSet.indices[color]), 1, 0)); } }); ctx.solver.add(ctx.ctx.Sum(sumTerms[0], ...sumTerms.slice(1)).eq(count)); } } } export const instance = new CellCountModule();