UNPKG

@logic-pad/core

Version:
103 lines (102 loc) 4.38 kB
import { array } from '../../../dataHelper.js'; import { Comparison } from '../../../primitives.js'; import BTModule, { BTTile, IntArray2D, colorToBTTile, } from '../data.js'; export default class SymbolsPerRegionBTModule extends BTModule { instr; symbolMap = []; constructor(instr, width, height, allSymbols) { super(); this.instr = instr; this.symbolMap = array(width, height, () => []); for (const symbol of allSymbols) { if (Math.floor(symbol.x) >= 0 && Math.floor(symbol.y) >= 0) { this.symbolMap[Math.floor(symbol.y)][Math.floor(symbol.x)].push(symbol); } if (Math.ceil(symbol.x) !== Math.floor(symbol.x) && Math.ceil(symbol.x) < width && Math.floor(symbol.y) >= 0) { this.symbolMap[Math.floor(symbol.y)][Math.ceil(symbol.x)].push(symbol); } if (Math.ceil(symbol.y) !== Math.floor(symbol.y) && Math.floor(symbol.x) >= 0 && Math.ceil(symbol.y) < height) { this.symbolMap[Math.ceil(symbol.y)][Math.floor(symbol.x)].push(symbol); } if (Math.ceil(symbol.x) !== Math.floor(symbol.x) && Math.ceil(symbol.y) !== Math.floor(symbol.y) && Math.ceil(symbol.x) < width && Math.ceil(symbol.y) < height) { this.symbolMap[Math.ceil(symbol.y)][Math.ceil(symbol.x)].push(symbol); } } } checkGlobal(grid) { const color = colorToBTTile(this.instr.color); const visited = IntArray2D.create(grid.width, grid.height); let id = 0; for (let y = 0; y < grid.height; y++) { for (let x = 0; x < grid.width; x++) { if (visited.get(x, y) & 0b01111111) continue; if (grid.getTile(x, y) !== color) continue; id += 1; if (id > 127) throw new Error('Too many regions!'); if (!this.visitArea(grid, color, visited, { x, y }, id)) return false; } } return { tilesNeedCheck: null, ratings: null }; } visitArea(grid, tile, visited, pos, id) { const sameTileQueue = [pos]; const usableTileQueue = []; const completed = new Set(); const possible = new Set(); visited.set(pos.x, pos.y, id); // Count same tile while (sameTileQueue.length > 0) { const curPos = sameTileQueue.pop(); this.symbolMap[curPos.y][curPos.x].forEach(symbol => completed.add(symbol)); for (const edge of grid.getEdges(curPos)) { if ((visited.get(edge.x, edge.y) & 0b01111111) === id) continue; const edgeTile = grid.getTile(edge.x, edge.y); if (edgeTile === BTTile.Empty) { usableTileQueue.push(edge); visited.set(edge.x, edge.y, id | 0b10000000); } else if (edgeTile === tile) { sameTileQueue.push(edge); visited.set(edge.x, edge.y, id); } } } if (completed.size > this.instr.count) { return this.instr.comparison === Comparison.AtLeast; } if (this.instr.comparison === Comparison.AtMost) return true; // Count usable tile while (usableTileQueue.length > 0) { const curPos = usableTileQueue.pop(); this.symbolMap[curPos.y][curPos.x].forEach(symbol => { if (!completed.has(symbol)) possible.add(symbol); }); if (completed.size + possible.size >= this.instr.count) return true; for (const edge of grid.getEdges(curPos)) { if ((visited.get(edge.x, edge.y) & 0b01111111) === id) continue; const edgeTile = grid.getTile(edge.x, edge.y); if (edgeTile === BTTile.Empty || edgeTile === tile) { usableTileQueue.push(edge); visited.set(edge.x, edge.y, id | 0b10000000); } } } return completed.size + possible.size >= this.instr.count; } }