@logic-pad/core
Version:
199 lines (198 loc) • 7.76 kB
JavaScript
import { ConfigType } from '../config.js';
import { move } from '../dataHelper.js';
import GridData from '../grid.js';
import { Color, ORIENTATIONS, Orientation, State, orientationToggle, } from '../primitives.js';
import MultiEntrySymbol from './multiEntrySymbol.js';
class MyopiaSymbol extends MultiEntrySymbol {
/**
* **Viewpoint Numbers count visible cells in the four directions**
* @param x - The x-coordinate of the symbol.
* @param y - The y-coordinate of the symbol.
* @param diagonals - Whether the symbol should consider diagonal directions.
* @param directions - The directions in which an arrow is pointing.
*/
constructor(x, y, diagonals, directions) {
super(x, y);
Object.defineProperty(this, "diagonals", {
enumerable: true,
configurable: true,
writable: true,
value: diagonals
});
Object.defineProperty(this, "directions", {
enumerable: true,
configurable: true,
writable: true,
value: directions
});
this.directions = directions;
this.diagonals =
directions[Orientation.DownLeft] ||
directions[Orientation.DownRight] ||
directions[Orientation.UpLeft] ||
directions[Orientation.UpRight]
? true
: diagonals;
}
get id() {
return `myopia`;
}
get placementStep() {
return 1;
}
get explanation() {
return this.diagonals
? '*Framed myopia arrows* point to *all* the closest opposite cells in 8 directions'
: '*Myopia arrows* point to *all* the closest cells of the opposite color';
}
get configs() {
return MyopiaSymbol.CONFIGS;
}
createExampleGrid() {
return this.diagonals
? MyopiaSymbol.EXAMPLE_DIAGONAL_GRID
: MyopiaSymbol.EXAMPLE_GRID;
}
validateSymbol(grid) {
const tile = grid.getTile(this.x, this.y);
if (!tile.exists || tile.color === Color.Gray)
return State.Incomplete;
const allDirections = this.diagonals
? ORIENTATIONS
: [Orientation.Up, Orientation.Down, Orientation.Left, Orientation.Right];
const map = {
up: { min: 0, max: 0, complete: true },
down: { min: 0, max: 0, complete: true },
left: { min: 0, max: 0, complete: true },
right: { min: 0, max: 0, complete: true },
'up-left': { min: 0, max: 0, complete: true },
'up-right': { min: 0, max: 0, complete: true },
'down-left': { min: 0, max: 0, complete: true },
'down-right': { min: 0, max: 0, complete: true },
};
const pos = { x: this.x, y: this.y };
allDirections.forEach(direction => {
let stopped = false;
grid.iterateDirectionAll(move(pos, direction), direction, t => {
if (!t.exists)
return true;
if (t.color === tile.color)
return true;
stopped = true;
return false;
}, () => {
map[direction].min++;
});
if (!stopped && map[direction].min === 0)
map[direction].min = Number.MAX_SAFE_INTEGER;
stopped = false;
grid.iterateDirectionAll(move(pos, direction), direction, t => {
if (!t.exists)
return true;
if (t.color === tile.color || t.color === Color.Gray)
return true;
stopped = true;
return false;
}, t => {
map[direction].max++;
if (t.exists && t.color === Color.Gray)
map[direction].complete = false;
});
if (!stopped)
map[direction].max = Number.MAX_SAFE_INTEGER;
});
const pointedDirections = allDirections.filter(d => this.directions[d]);
const otherDirections = allDirections.filter(d => !this.directions[d]);
for (let i = 0; i < pointedDirections.length; i++) {
const direction1 = pointedDirections[i];
for (let j = i + 1; j < pointedDirections.length; j++) {
const direction2 = pointedDirections[j];
if (map[direction1].min > map[direction2].max)
return State.Error;
if (map[direction2].min > map[direction1].max)
return State.Error;
}
}
if (Math.min(...otherDirections.map(d => map[d].max)) <=
Math.max(...pointedDirections.map(d => map[d].min)))
return State.Error;
if (pointedDirections.length === 0 &&
otherDirections.some(d => map[d].max !== Number.MAX_SAFE_INTEGER))
return State.Error;
if (pointedDirections.some(d => map[d].complete && map[d].max === Number.MAX_SAFE_INTEGER))
return State.Error;
if (pointedDirections.length > 0 &&
otherDirections.length > 0 &&
pointedDirections.every(d => map[d].complete) &&
Math.max(...pointedDirections.map(d => map[d].max)) <
Math.min(...otherDirections.map(d => map[d].min)))
return State.Satisfied;
if (allDirections.every(d => map[d].complete))
return State.Satisfied;
return State.Incomplete;
}
copyWith({ x, y, diagonals, directions, }) {
return new MyopiaSymbol(x ?? this.x, y ?? this.y, diagonals ?? this.diagonals, directions ?? this.directions);
}
withDirections(directions) {
return this.copyWith({ directions });
}
withDiagonals(diagonals) {
return this.copyWith({ diagonals });
}
}
Object.defineProperty(MyopiaSymbol, "CONFIGS", {
enumerable: true,
configurable: true,
writable: true,
value: 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.Boolean,
default: false,
field: 'diagonals',
description: 'Include diagonal directions',
configurable: true,
},
{
type: ConfigType.OrientationToggle,
default: orientationToggle(Orientation.Up, Orientation.Right),
field: 'directions',
description: 'Directions',
configurable: true,
},
])
});
Object.defineProperty(MyopiaSymbol, "EXAMPLE_GRID", {
enumerable: true,
configurable: true,
writable: true,
value: Object.freeze(GridData.create(['wbwww', 'bwwwb', 'wwwww', 'wbwww']).withSymbols([
new MyopiaSymbol(1, 1, false, orientationToggle(Orientation.Up, Orientation.Left)),
new MyopiaSymbol(4, 3, false, orientationToggle(Orientation.Up)),
]))
});
Object.defineProperty(MyopiaSymbol, "EXAMPLE_DIAGONAL_GRID", {
enumerable: true,
configurable: true,
writable: true,
value: Object.freeze(GridData.create(['wbwww', 'bwwwb', 'wwwww', 'wbwww']).withSymbols([
new MyopiaSymbol(1, 2, true, orientationToggle(Orientation.UpLeft, Orientation.Down)),
new MyopiaSymbol(3, 2, true, orientationToggle(Orientation.UpRight)),
]))
});
export default MyopiaSymbol;
export const instance = new MyopiaSymbol(0, 0, false, orientationToggle(Orientation.Up, Orientation.Right));