@logic-pad/core
Version:
147 lines (146 loc) • 5.16 kB
JavaScript
import { ConfigType } from '../config.js';
import GridData from '../grid.js';
import { array } from '../dataHelper.js';
import { Color, State } from '../primitives.js';
import { getShapeVariants, sanitizePatternGrid, tilesToShape, } from '../shapes.js';
import Rule from './rule.js';
class BanPatternRule extends Rule {
/**
* **Don't make this pattern**
*
* @param pattern - GridData representing the banned pattern. Only non-gray tiles are considered.
*/
constructor(pattern) {
super();
Object.defineProperty(this, "pattern", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
Object.defineProperty(this, "cache", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
this.pattern = sanitizePatternGrid(pattern);
this.cache = getShapeVariants(tilesToShape(this.pattern.tiles));
}
get id() {
return `ban_pattern`;
}
get explanation() {
return `Don't make this pattern`;
}
get configs() {
return BanPatternRule.CONFIGS;
}
createExampleGrid() {
let minX = Number.POSITIVE_INFINITY;
let minY = Number.POSITIVE_INFINITY;
let maxX = Number.NEGATIVE_INFINITY;
let maxY = Number.NEGATIVE_INFINITY;
this.pattern.forEach((tile, x, y) => {
if (tile.color !== Color.Gray && tile.exists) {
minX = Math.min(minX, x);
minY = Math.min(minY, y);
maxX = Math.max(maxX, x);
maxY = Math.max(maxY, y);
}
});
const width = maxX - minX + 1;
const height = maxY - minY + 1;
const tiles = array(width, height, (x, y) => {
const tile = this.pattern.getTile(x + minX, y + minY);
if (!tile.exists || tile.color !== Color.Gray)
return tile;
return tile.withExists(false);
});
return GridData.create(width, height, tiles);
}
get searchVariants() {
return BanPatternRule.SEARCH_VARIANTS;
}
validateGrid(grid) {
for (const pattern of this.cache) {
let startX, startY, endX, endY;
if (grid.wrapAround.value) {
startX = -pattern.width;
startY = -pattern.height;
endX = grid.width - 1;
endY = grid.height - 1;
}
else {
startX = 0;
startY = 0;
endX = grid.width - pattern.width;
endY = grid.height - pattern.height;
}
for (let y = startY; y <= endY; y++) {
for (let x = startX; x <= endX; x++) {
let match = true;
const visited = [];
for (const tile of pattern.elements) {
const pos = grid.toArrayCoordinates(x + tile.x, y + tile.y);
if (grid.wrapAround.value && // optimization: no need to check visited if wrapAround is disabled
visited.some(p => p.x === pos.x && p.y === pos.y)) {
match = false;
break;
}
visited.push(pos);
const t = grid.getTile(x + tile.x, y + tile.y);
if (!t.exists || t.color !== tile.color) {
match = false;
break;
}
}
if (match) {
return {
state: State.Error,
positions: pattern.elements.map(tile => grid.toArrayCoordinates(x + tile.x, y + tile.y)),
};
}
}
}
}
return { state: grid.isComplete() ? State.Satisfied : State.Incomplete };
}
copyWith({ pattern }) {
return new BanPatternRule(pattern ?? this.pattern);
}
withPattern(pattern) {
return this.copyWith({ pattern });
}
}
Object.defineProperty(BanPatternRule, "EXAMPLE_GRID", {
enumerable: true,
configurable: true,
writable: true,
value: Object.freeze(GridData.create(['nnnnn', 'nnnnn', 'wwwwn', 'nnnnn', 'nnnnn']))
});
Object.defineProperty(BanPatternRule, "CONFIGS", {
enumerable: true,
configurable: true,
writable: true,
value: Object.freeze([
{
type: ConfigType.Tile,
default: BanPatternRule.EXAMPLE_GRID,
resizable: true,
field: 'pattern',
description: 'Pattern',
configurable: true,
},
])
});
Object.defineProperty(BanPatternRule, "SEARCH_VARIANTS", {
enumerable: true,
configurable: true,
writable: true,
value: [
new BanPatternRule(BanPatternRule.EXAMPLE_GRID).searchVariant(),
]
});
export default BanPatternRule;
export const instance = new BanPatternRule(GridData.create([]));