UNPKG

@logic-pad/core

Version:
240 lines (239 loc) 7.11 kB
import { ConfigType } from '../config.js'; import GridData from '../grid.js'; import { Color, Orientation, State, } from '../primitives.js'; import Rule from './rule.js'; import validateGrid from '../validate.js'; import Symbol from '../symbols/symbol.js'; import LetterSymbol from '../symbols/letterSymbol.js'; import GalaxySymbol from '../symbols/galaxySymbol.js'; import LotusSymbol from '../symbols/lotusSymbol.js'; import AreaNumberSymbol from '../symbols/areaNumberSymbol.js'; class IgnoredSymbol extends Symbol { constructor(symbol, state) { super(symbol.x, symbol.y); Object.defineProperty(this, "symbol", { enumerable: true, configurable: true, writable: true, value: symbol }); Object.defineProperty(this, "state", { enumerable: true, configurable: true, writable: true, value: state }); this.symbol = symbol; this.state = state; } get id() { return `ignored_${this.symbol.id}`; } get explanation() { return this.symbol.explanation; } get configs() { return []; } createExampleGrid() { return this.symbol.createExampleGrid(); } get necessaryForCompletion() { return this.symbol.necessaryForCompletion; } get visibleWhenSolving() { return this.symbol.visibleWhenSolving; } get sortOrder() { return this.symbol.sortOrder; } validateSymbol(_grid, _solution) { return this.state; } copyWith({ symbol, state }) { return new IgnoredSymbol(symbol ?? this.symbol, state ?? this.state); } withSymbol(symbol) { return this.copyWith({ symbol }); } equals(other) { return other === this; } } class IgnoredRule extends Rule { constructor(rule, state) { super(); Object.defineProperty(this, "rule", { enumerable: true, configurable: true, writable: true, value: rule }); Object.defineProperty(this, "state", { enumerable: true, configurable: true, writable: true, value: state }); this.rule = rule; this.state = state; } get searchVariants() { return []; } get id() { return `ignored_${this.rule.id}`; } get explanation() { return this.rule.explanation; } get configs() { return []; } createExampleGrid() { return this.rule.createExampleGrid(); } get necessaryForCompletion() { return this.rule.necessaryForCompletion; } get visibleWhenSolving() { return this.rule.visibleWhenSolving; } get isSingleton() { return this.rule.isSingleton; } validateGrid(_grid) { if (this.state === State.Error) return { state: State.Error, positions: [] }; else return { state: this.state }; } copyWith({ rule, state }) { return new IgnoredRule(rule ?? this.rule, state ?? this.state); } equals(other) { return other === this; } } class LyingSymbolRule extends Rule { /** * **&lt;count&gt; symbols are lying and are incorrect** * * @param count Number of lying symbols */ constructor(count) { super(); Object.defineProperty(this, "count", { enumerable: true, configurable: true, writable: true, value: count }); this.count = count; } get id() { return `lying_symbols`; } get explanation() { return `${this.count} symbol${this.count <= 1 ? ' is' : 's are'} *lying* and ${this.count <= 1 ? 'is' : 'are'} incorrect`; } get configs() { return LyingSymbolRule.CONFIGS; } createExampleGrid() { return LyingSymbolRule.EXAMPLE_GRID; } get searchVariants() { return LyingSymbolRule.SEARCH_VARIANTS; } validateGrid(_) { return { state: State.Incomplete }; } get isSingleton() { return true; } onFinalValidation(grid, solution, state) { const ignoredSymbols = []; state.symbols.forEach((values, key) => { values.forEach((state, idx) => { if (state === State.Error) ignoredSymbols.push([key, idx]); }); }); if (ignoredSymbols.length > this.count) { const thisIdx = grid.rules.findIndex(rule => rule.id === this.id); return { final: State.Error, rules: state.rules.map((rule, idx) => idx === thisIdx ? { state: State.Error, positions: [] } : rule), symbols: state.symbols, }; } const newSymbols = new Map(); grid.symbols.forEach((values, key) => { values.forEach((symbol, idx) => { if (!newSymbols.has(key)) { newSymbols.set(key, []); } if (ignoredSymbols.some(([k, i]) => k === key && i === idx)) { newSymbols.get(key).push(new IgnoredSymbol(symbol, State.Ignored)); } else { newSymbols.get(key).push(symbol); } }); }); const newRules = grid.rules.map(rule => rule.id === this.id ? new IgnoredRule(this, ignoredSymbols.length === this.count ? State.Satisfied : grid.getTileCount(true, false, Color.Gray) === 0 ? State.Error : State.Incomplete) : rule); return validateGrid(grid.copyWith({ rules: newRules, symbols: newSymbols }), solution); } copyWith({ count }) { return new LyingSymbolRule(count ?? this.count); } withCount(count) { return this.copyWith({ count }); } } Object.defineProperty(LyingSymbolRule, "EXAMPLE_GRID", { enumerable: true, configurable: true, writable: true, value: Object.freeze(GridData.create(['bbbbw', 'wwbbb', 'bbbbw', 'wbbww']).withSymbols([ new LetterSymbol(4, 0, 'A'), new GalaxySymbol(1, 1), new LotusSymbol(2, 2, Orientation.Up), new LetterSymbol(0, 3, 'A'), new AreaNumberSymbol(4, 3, 1), ])) }); Object.defineProperty(LyingSymbolRule, "CONFIGS", { enumerable: true, configurable: true, writable: true, value: Object.freeze([ { type: ConfigType.Number, default: 1, min: 1, max: 100, step: 1, field: 'count', description: 'Number of liars', configurable: true, }, ]) }); Object.defineProperty(LyingSymbolRule, "SEARCH_VARIANTS", { enumerable: true, configurable: true, writable: true, value: [ new LyingSymbolRule(1).searchVariant(), ] }); export default LyingSymbolRule; export const instance = new LyingSymbolRule(1);