@logic-pad/core
Version:
147 lines (146 loc) • 5.17 kB
JavaScript
import { ConfigType } from '../config.js';
import GridData from '../grid.js';
import { array } from '../dataHelper.js';
import { Color, State } from '../primitives.js';
import CustomTextSymbol from '../symbols/customTextSymbol.js';
import Rule from './rule.js';
export default class MysteryRule extends Rule {
solution;
visible;
title = 'Alternate Solution';
get configExplanation() {
return 'You may use multiple instances of this rule to provide multiple alternate solutions.';
}
static EXAMPLE_GRID = Object.freeze(GridData.create(['.']).addSymbol(new CustomTextSymbol('', GridData.create([]), 0, 0, '?')));
static CONFIGS = Object.freeze([
{
type: ConfigType.Tile,
default: MysteryRule.EXAMPLE_GRID,
resizable: false,
field: 'solution',
description: 'Solution',
explanation: 'The alternate solution to the puzzle. Does not need to satisfy puzzle rules / symbols.',
configurable: true,
},
{
type: ConfigType.Boolean,
default: true,
field: 'visible',
description: 'Visible',
explanation: 'Display this rule to the player.',
configurable: true,
},
]);
static SEARCH_VARIANTS = [
new MysteryRule(MysteryRule.EXAMPLE_GRID, true).searchVariant(),
];
/**
* **Mystery: alternate solution**
*/
constructor(solution, visible) {
super();
this.solution = solution;
this.visible = visible;
this.solution = MysteryRule.cleanSolution(solution);
this.visible = visible;
}
get id() {
return `mystery`;
}
get explanation() {
return `*Mystery:* Alternate solution`;
}
get visibleWhenSolving() {
return this.visible;
}
get configs() {
return MysteryRule.CONFIGS;
}
createExampleGrid() {
return MysteryRule.EXAMPLE_GRID;
}
get searchVariants() {
return MysteryRule.SEARCH_VARIANTS;
}
validateGrid(grid) {
if (grid.colorEquals(this.solution))
return { state: State.Satisfied };
return { state: State.Incomplete };
}
get necessaryForCompletion() {
return false;
}
onFinalValidation(grid, _solution, state) {
if (State.isSatisfied(state.final))
return state;
if (grid.colorEquals(this.solution))
return {
final: State.Satisfied,
symbols: state.symbols,
rules: state.rules,
};
return state;
}
onGridChange(newGrid) {
if (newGrid.width === this.solution.width &&
newGrid.height === this.solution.height) {
if (!newGrid.tiles.some((row, y) => row.some((tile, x) => {
const solutionTile = this.solution.getTile(x, y);
if (solutionTile.exists !== tile.exists)
return true;
if (solutionTile.fixed !== tile.fixed)
return true;
if (solutionTile.exists &&
solutionTile.fixed &&
solutionTile.color !== tile.color)
return true;
return false;
})))
return this;
}
return this.withSolution(MysteryRule.cleanSolution(this.solution, newGrid));
}
onGridResize(_grid, mode, direction, index) {
if (mode === 'insert') {
if (direction === 'row') {
return this.withSolution(this.solution.insertRow(index));
}
else if (direction === 'column') {
return this.withSolution(this.solution.insertColumn(index));
}
}
else if (mode === 'remove') {
if (direction === 'row') {
return this.withSolution(this.solution.removeRow(index));
}
else if (direction === 'column') {
return this.withSolution(this.solution.removeColumn(index));
}
}
return this;
}
copyWith({ solution, visible, }) {
return new MysteryRule(solution ?? this.solution, visible ?? this.visible);
}
withSolution(solution) {
return this.copyWith({ solution });
}
withVisible(visible) {
return this.copyWith({ visible });
}
static cleanSolution(solution, baseGrid) {
const tiles = baseGrid
? array(baseGrid.width, baseGrid.height, (x, y) => {
const tile = baseGrid.getTile(x, y);
if (!tile.exists || tile.fixed)
return tile;
const solutionTile = solution.getTile(x, y);
if (!solutionTile.exists || solutionTile.color === Color.Gray)
return tile;
return tile.withColor(solutionTile.color);
})
: solution.tiles;
return GridData.create(baseGrid?.width ?? solution.width, baseGrid?.height ?? solution.height, tiles);
}
}
export const instance = new MysteryRule(GridData.create([]), true);