UNPKG

@logic-pad/core

Version:
272 lines (271 loc) 10 kB
import { ConfigType } from '../config.js'; import { array } from '../dataHelper.js'; import GridData from '../grid.js'; import { Color, MajorRule, Orientation, State, Wrapping, orientationToggle, } from '../primitives.js'; import LetterSymbol from '../symbols/letterSymbol.js'; import MyopiaSymbol from '../symbols/myopiaSymbol.js'; import Rule from './rule.js'; class WrapAroundRule extends Rule { /** * **The left and right edges are connected (in reverse)** * * @param horizontal - The horizontal wrapping. * @param vertical - The vertical wrapping. */ constructor(horizontal, vertical) { super(); Object.defineProperty(this, "horizontal", { enumerable: true, configurable: true, writable: true, value: horizontal }); Object.defineProperty(this, "vertical", { enumerable: true, configurable: true, writable: true, value: vertical }); this.horizontal = horizontal; this.vertical = vertical; } onGetTile(x, y, grid) { if (grid.width === 0 || grid.height === 0) { return { x, y }; } if (this.horizontal !== Wrapping.None) { const idx = Math.abs(Math.floor(x / grid.width)); x = ((x % grid.width) + grid.width) % grid.width; if ((this.horizontal === Wrapping.WrapReverse || this.horizontal === Wrapping.ReflectReverse) && idx % 2 === 1) { y = grid.height - 1 - y; } if (this.horizontal === Wrapping.ReflectReverse && idx % 2 === 1) { x = grid.width - 1 - x; } } if (this.vertical !== Wrapping.None) { const idx = Math.abs(Math.floor(y / grid.height)); y = ((y % grid.height) + grid.height) % grid.height; if ((this.vertical === Wrapping.WrapReverse || this.vertical === Wrapping.ReflectReverse) && idx % 2 === 1) { x = grid.width - 1 - x; } if (this.vertical === Wrapping.ReflectReverse && idx % 2 === 1) { y = grid.height - 1 - y; } } return { x, y }; } get id() { return MajorRule.WrapAround; } get explanation() { if (this.horizontal === Wrapping.None && this.vertical === Wrapping.None) { return `No edges are connected.`; } const horizontal = this.horizontal === Wrapping.None ? null : this.horizontal === Wrapping.Wrap || this.horizontal === Wrapping.WrapReverse ? 'connected' : 'reflective'; const vertical = this.vertical === Wrapping.None ? null : this.vertical === Wrapping.Wrap || this.vertical === Wrapping.WrapReverse ? 'connected' : 'reflective'; const horizontalReverse = this.horizontal === Wrapping.WrapReverse || this.horizontal === Wrapping.ReflectReverse ? ' in reverse' : ''; const verticalReverse = this.vertical === Wrapping.WrapReverse || this.vertical === Wrapping.ReflectReverse ? ' in reverse' : ''; if (this.horizontal === this.vertical) { return `All four edges are ${horizontal}${horizontalReverse}.`; } if (this.horizontal === Wrapping.None) { return `The top and bottom edges are ${vertical}${verticalReverse}.`; } if (this.vertical === Wrapping.None) { return `The left and right edges are ${horizontal}${horizontalReverse}.`; } if (horizontal === vertical) { if (horizontalReverse !== '') { return `All four edges are ${horizontal}, with the left and right edges${horizontalReverse}.`; } else { return `All four edges are ${horizontal}, with the top and bottom edges${verticalReverse}.`; } } return `The left and right edges are ${horizontal}${horizontalReverse}. The top and bottom edges are ${vertical}${verticalReverse}.`; } createExampleGrid() { const horizontal = WrapAroundRule.EXAMPLE_GRID_HORIZONTAL[this.horizontal]; const vertical = WrapAroundRule.EXAMPLE_GRID_VERTICAL[this.vertical]; if (horizontal === WrapAroundRule.EXAMPLE_GRID_NONE) { return vertical; } else if (vertical === WrapAroundRule.EXAMPLE_GRID_NONE) { return horizontal; } else { const tiles = array(5, 5, (x, y) => { const hTile = horizontal.getTile(x, y); const vTile = vertical.getTile(x, y); return hTile.withColor(hTile.color === Color.Dark || vTile.color === Color.Dark ? Color.Dark : Color.Light); }); const symbols = []; horizontal.symbols.forEach(list => symbols.push(...list)); vertical.symbols.forEach(list => symbols.push(...list)); return horizontal.withTiles(tiles).withSymbols(symbols); } } get configs() { return WrapAroundRule.CONFIGS; } get searchVariants() { return WrapAroundRule.SEARCH_VARIANTS; } validateGrid(grid) { if (grid.getTileCount(true, false, Color.Gray) > 0) { return { state: State.Incomplete }; } else { return { state: State.Satisfied }; } } copyWith({ horizontal, vertical, }) { return new WrapAroundRule(horizontal ?? this.horizontal, vertical ?? this.vertical); } get isSingleton() { return true; } } Object.defineProperty(WrapAroundRule, "EXAMPLE_GRID_NONE", { enumerable: true, configurable: true, writable: true, value: Object.freeze(GridData.create(['wwwww', 'wwwww', 'wwwww', 'wwwww', 'wwwww'])) }); Object.defineProperty(WrapAroundRule, "EXAMPLE_GRID_HORIZONTAL", { enumerable: true, configurable: true, writable: true, value: Object.freeze({ [Wrapping.None]: WrapAroundRule.EXAMPLE_GRID_NONE, [Wrapping.Wrap]: GridData.create([ 'wwwww', 'bwwwb', 'wwwww', 'bwwwb', 'wwwww', ]) .addSymbol(new LetterSymbol(0, 1, 'A')) .addSymbol(new LetterSymbol(4, 1, 'A')) .addSymbol(new LetterSymbol(0, 3, 'B')) .addSymbol(new LetterSymbol(4, 3, 'B')), [Wrapping.WrapReverse]: GridData.create([ 'wwwww', 'bwwwb', 'wwwww', 'bwwwb', 'wwwww', ]) .addSymbol(new LetterSymbol(0, 1, 'A')) .addSymbol(new LetterSymbol(4, 1, 'B')) .addSymbol(new LetterSymbol(0, 3, 'B')) .addSymbol(new LetterSymbol(4, 3, 'A')), [Wrapping.ReflectReverse]: GridData.create([ 'wwwww', 'bwwww', 'wwwww', 'wwwwb', 'wwwww', ]) .addSymbol(new MyopiaSymbol(0, 3, false, orientationToggle(Orientation.Left))) .addSymbol(new MyopiaSymbol(4, 1, false, orientationToggle(Orientation.Right))), }) }); Object.defineProperty(WrapAroundRule, "EXAMPLE_GRID_VERTICAL", { enumerable: true, configurable: true, writable: true, value: Object.freeze({ [Wrapping.None]: WrapAroundRule.EXAMPLE_GRID_NONE, [Wrapping.Wrap]: GridData.create([ 'wbwbw', 'wwwww', 'wwwww', 'wwwww', 'wbwbw', ]) .addSymbol(new LetterSymbol(1, 0, 'C')) .addSymbol(new LetterSymbol(3, 0, 'D')) .addSymbol(new LetterSymbol(1, 4, 'C')) .addSymbol(new LetterSymbol(3, 4, 'D')), [Wrapping.WrapReverse]: GridData.create([ 'wbwbw', 'wwwww', 'wwwww', 'wwwww', 'wbwbw', ]) .addSymbol(new LetterSymbol(1, 0, 'C')) .addSymbol(new LetterSymbol(3, 0, 'D')) .addSymbol(new LetterSymbol(1, 4, 'D')) .addSymbol(new LetterSymbol(3, 4, 'C')), [Wrapping.ReflectReverse]: GridData.create([ 'wbwww', 'wwwww', 'wwwww', 'wwwww', 'wwwbw', ]) .addSymbol(new MyopiaSymbol(3, 0, false, orientationToggle(Orientation.Up))) .addSymbol(new MyopiaSymbol(1, 4, false, orientationToggle(Orientation.Down))), }) }); Object.defineProperty(WrapAroundRule, "SEARCH_VARIANTS", { enumerable: true, configurable: true, writable: true, value: [ new WrapAroundRule(Wrapping.Wrap, Wrapping.None).searchVariant(), new WrapAroundRule(Wrapping.None, Wrapping.Wrap).searchVariant(), new WrapAroundRule(Wrapping.Wrap, Wrapping.Wrap).searchVariant(), new WrapAroundRule(Wrapping.ReflectReverse, Wrapping.None).searchVariant(), new WrapAroundRule(Wrapping.None, Wrapping.ReflectReverse).searchVariant(), new WrapAroundRule(Wrapping.ReflectReverse, Wrapping.ReflectReverse).searchVariant(), ] }); Object.defineProperty(WrapAroundRule, "CONFIGS", { enumerable: true, configurable: true, writable: true, value: Object.freeze([ { type: ConfigType.Wrapping, default: Wrapping.Wrap, field: 'horizontal', description: 'Horizontal wrap', configurable: true, }, { type: ConfigType.Wrapping, default: Wrapping.Wrap, field: 'vertical', description: 'Vertical wrap', configurable: true, }, ]) }); export default WrapAroundRule; export const instance = new WrapAroundRule(Wrapping.Wrap, Wrapping.Wrap);