@logic-pad/core
Version:
120 lines (119 loc) • 4.1 kB
JavaScript
import { ConfigType } from '../config.js';
import GridData from '../grid.js';
import { array } from '../dataHelper.js';
import { Color, State } from '../primitives.js';
import Symbol from './symbol.js';
export default class EveryLetterSymbol extends Symbol {
x;
y;
letter;
title = 'Hollow Letter';
static CONFIGS = Object.freeze([
{
type: ConfigType.Number,
default: 0,
field: 'x',
description: 'X',
configurable: false,
},
{
type: ConfigType.Number,
default: 0,
field: 'y',
description: 'Y',
configurable: false,
},
{
type: ConfigType.String,
default: 'a',
field: 'letter',
description: 'Letter',
explanation: 'Use single lowercase letters by convention.',
configurable: true,
},
]);
static EXAMPLE_GRID = Object.freeze(GridData.create(['bwwbw', 'bwbbw', 'wwbww', 'bbbwb'])
.addSymbol(new EveryLetterSymbol(2, 0, 'b'))
.addSymbol(new EveryLetterSymbol(4, 1, 'a'))
.addSymbol(new EveryLetterSymbol(0, 2, 'a'))
.addSymbol(new EveryLetterSymbol(3, 2, 'b')));
/**
* **Include each Hollow Letter once per region**
*
* @param x - The x-coordinate of the symbol.
* @param y - The y-coordinate of the symbol.
* @param letter - The letter of the symbol.
*/
constructor(x, y, letter) {
super(x, y);
this.x = x;
this.y = y;
this.letter = letter;
this.letter = letter;
}
get id() {
return `every_letter`;
}
get explanation() {
return 'Include each *Hollow Letter* once per region';
}
get configs() {
return EveryLetterSymbol.CONFIGS;
}
createExampleGrid() {
return EveryLetterSymbol.EXAMPLE_GRID;
}
validateSymbol(grid) {
if (!this.validateSubtilePlacement(grid))
return State.Error;
const uniqueLetters = new Set(grid.symbols.get(this.id)?.map(s => s.letter));
if (uniqueLetters.size === 0) {
return State.Satisfied;
}
const possibleLetters = new Set(uniqueLetters);
const thisX = Math.floor(this.x);
const thisY = Math.floor(this.y);
let complete = true;
const visited = array(grid.width, grid.height, () => false);
const connected = array(grid.width, grid.height, () => false);
const color = grid.getTile(thisX, thisY).color;
if (color !== Color.Gray) {
grid.iterateArea({ x: thisX, y: thisY }, tile => tile.color === Color.Gray || tile.color === color, (tile, x, y) => {
visited[y][x] = true;
if (tile.color === Color.Gray)
complete = false;
});
grid.iterateArea({ x: thisX, y: thisY }, tile => tile.color === color, (_, x, y) => {
connected[y][x] = true;
});
}
else {
return State.Incomplete;
}
for (const symbol of grid.symbols.get(this.id) ?? []) {
if (symbol instanceof EveryLetterSymbol) {
const symbolX = Math.floor(symbol.x);
const symbolY = Math.floor(symbol.y);
if (visited[symbolY][symbolX]) {
possibleLetters.delete(symbol.letter);
}
if (connected[symbolY][symbolX]) {
if (!uniqueLetters.delete(symbol.letter)) {
return State.Error;
}
}
}
}
if (possibleLetters.size > 0) {
return State.Error;
}
return complete ? State.Satisfied : State.Incomplete;
}
copyWith({ x, y, letter, }) {
return new EveryLetterSymbol(x ?? this.x, y ?? this.y, letter ?? this.letter);
}
withLetter(letter) {
return this.copyWith({ letter });
}
}
export const instance = new EveryLetterSymbol(0, 0, 'a');