UNPKG

@logic-pad/core

Version:
417 lines (416 loc) 20.3 kB
import GridConnections from './gridConnections.js'; import { CachedAccess } from './dataHelper.js'; import { Color, Direction, Orientation, Position } from './primitives.js'; import Rule from './rules/rule.js'; import Symbol from './symbols/symbol.js'; import TileData from './tile.js'; import MusicGridRule from './rules/musicGridRule.js'; import CompletePatternRule from './rules/completePatternRule.js'; import UndercluedRule from './rules/undercluedRule.js'; import GridZones from './gridZones.js'; import WrapAroundRule from './rules/wrapAroundRule.js'; export declare const NEIGHBOR_OFFSETS: Position[]; export default class GridData { readonly width: number; readonly height: number; readonly tiles: readonly (readonly TileData[])[]; readonly connections: GridConnections; readonly zones: GridZones; readonly symbols: ReadonlyMap<string, readonly Symbol[]>; readonly rules: readonly Rule[]; readonly musicGrid: CachedAccess<MusicGridRule | undefined>; readonly completePattern: CachedAccess<CompletePatternRule | undefined>; readonly underclued: CachedAccess<UndercluedRule | undefined>; readonly wrapAround: CachedAccess<WrapAroundRule | undefined>; /** * Create a new grid with tiles, connections, symbols and rules. * * @param width The width of the grid. * @param height The height of the grid. * @param tiles The tiles of the grid. * @param connections The connections of the grid, which determines which tiles are merged. * @param zones The zones of the grid. * @param symbols The symbols in the grid. * @param rules The rules of the grid. */ constructor(width: number, height: number, tiles?: readonly (readonly TileData[])[], connections?: GridConnections, zones?: GridZones, symbols?: ReadonlyMap<string, readonly Symbol[]>, rules?: readonly Rule[]); /** * Create a new GridData object from a string array. * * - Use `b` for dark cells, `w` for light cells, and `n` for gray cells. * - Capitalize the letter to make the tile fixed. * - Use `.` to represent empty space. * * @param array - The string array to create the grid from. * @returns The created grid. */ static create(array: string[]): GridData; /** * Create a new grid with tiles, connections, symbols and rules. Sanitize the provided list of symbols and rules, * and trigger grid change events. * * @param width The width of the grid. * @param height The height of the grid. * @param tiles The tiles of the grid. * @param connections The connections of the grid, which determines which tiles are merged. * @param zones The zones of the grid. * @param symbols The symbols in the grid. * @param rules The rules of the grid. */ static create(width: number, height: number, tiles?: readonly (readonly TileData[])[], connections?: GridConnections, zones?: GridZones, symbols?: ReadonlyMap<string, readonly Symbol[]>, rules?: readonly Rule[]): GridData; /** * Copy the current grid while modifying the provided properties. * @param param0 The properties to modify. * @returns The new grid with the modified properties. */ copyWith({ width, height, tiles, connections, zones, symbols, rules, }: { width?: number; height?: number; tiles?: readonly (readonly TileData[])[]; connections?: GridConnections; zones?: GridZones; symbols?: ReadonlyMap<string, readonly Symbol[]>; rules?: readonly Rule[]; }): GridData; /** * Copy the current grid while modifying the provided properties. * Skip sanitization and event triggering for performance. * * @param param0 The properties to modify. * @returns The new grid with the modified properties. */ fastCopyWith({ width, height, tiles, connections, zones, symbols, rules, }: { width?: number; height?: number; tiles?: readonly (readonly TileData[])[]; connections?: GridConnections; zones?: GridZones; symbols?: ReadonlyMap<string, readonly Symbol[]>; rules?: readonly Rule[]; }): GridData; toArrayCoordinates(x: number, y: number): Position; isPositionValid(x: number, y: number): boolean; /** * Safely get the tile at the given position. * @param x The x-coordinate of the tile. * @param y The y-coordinate of the tile. * @returns The tile at the given position, or a non-existent tile if the position is invalid. */ getTile(x: number, y: number): TileData; /** * Safely set the tile at the given position. * If the position is invalid, the tile array is returned unchanged. * If the tile is merged with other tiles, the colors of all connected tiles are changed. * * @param x The x-coordinate of the tile. * @param y The y-coordinate of the tile. * @param tile The new tile to set. * @returns The new tile array with updated tiles. */ setTile(x: number, y: number, tile: TileData | ((tile: TileData) => TileData)): readonly (readonly TileData[])[]; /** * Replace or modify all tiles in the grid. * * @param tiles The new tile array or a function to mutate the existing tile array. * @returns The new grid with the new tiles. */ withTiles(tiles: readonly (readonly TileData[])[] | ((value: TileData[][]) => readonly (readonly TileData[])[])): GridData; /** * Add or modify the connections in the grid. * @param connections The new connections to add or modify. * @returns The new grid with the new connections. */ withConnections(connections: GridConnections | ((value: GridConnections) => GridConnections)): GridData; /** * Add or modify the zones in the grid. * @param zones The new zones to add or modify. * @returns The new grid with the new zones. */ withZones(zones: GridZones | ((value: GridZones) => GridZones)): GridData; /** * Add or modify the symbols in the grid. * @param symbols The new symbols to add or modify. * @returns The new grid with the new symbols. */ withSymbols(symbols: readonly Symbol[] | ReadonlyMap<string, readonly Symbol[]> | ((value: Map<string, readonly Symbol[]>) => ReadonlyMap<string, readonly Symbol[]>)): GridData; /** * Add a new symbol to the grid. * @param symbol The symbol to add. * @returns The new grid with the new symbol. */ addSymbol(symbol: Symbol): GridData; /** * Remove an instance of the symbol from the grid. * @param symbol The symbol to remove. * @returns The new grid with the symbol removed. */ removeSymbol(symbol: Symbol): GridData; /** * Remove all symbols that satisfy the predicate. * @param predicate The predicate to test each symbol with. * @returns The new grid with the symbols removed. */ removeSymbolIf(predicate: (symbol: Symbol) => boolean): GridData; /** * Find the first symbol that satisfies the predicate. * @param predicate The predicate to test each symbol with. * @returns The first symbol that satisfies the predicate, or undefined if no symbol is found. */ findSymbol(predicate: (symbol: Symbol) => boolean): Symbol | undefined; /** * Replace an existing symbol with a new symbol. * @param oldSymbol The symbol to replace. * @param newSymbol The new symbol to replace with. * @returns The new grid with the symbol replaced. */ replaceSymbol(oldSymbol: Symbol, newSymbol: Symbol): GridData; /** * Add or modify the rules in the grid. * @param rules The new rules to add or modify. * @returns The new grid with the new rules. */ withRules(rules: readonly Rule[] | ((value: readonly Rule[]) => readonly Rule[])): GridData; /** * Add a new rule to the grid. * @param rule The rule to add. * @returns The new grid with the new rule. */ addRule(rule: Rule): GridData; /** * Remove an instance of the rule from the grid. * @param rule The rule to remove. * @returns The new grid with the rule removed. */ removeRule(rule: Rule): GridData; /** * Remove all rules that satisfy the predicate. * @param predicate The predicate to test each rule with. * @returns The new grid with the rules removed. */ removeRuleIf(predicate: (rule: Rule) => boolean): GridData; /** * Find the first rule that satisfies the predicate. * @param predicate The predicate to test each rule with. * @returns The first rule that satisfies the predicate, or undefined if no rule is found. */ findRule(predicate: (rule: Rule) => boolean): Rule | undefined; /** * Replace an existing rule with a new rule. * @param oldRule The rule to replace. * @param newRule The new rule to replace with. * @returns The new grid with the rule replaced. */ replaceRule(oldRule: Rule, newRule: Rule): GridData; /** * Insert a new column at the given index, shifting all components of the grid accordingly. Newly inserted tiles are gray. * @param index The index to insert the column at. * @returns The new grid with the new column inserted. */ insertColumn(index: number): GridData; /** * Insert a new row at the given index, shifting all components of the grid accordingly. Newly inserted tiles are gray. * @param index The index to insert the row at. * @returns The new grid with the new row inserted. */ insertRow(index: number): GridData; /** * Remove a column at the given index, shifting all components of the grid accordingly. * @param index The index to remove the column at. * @returns The new grid with the column removed. */ removeColumn(index: number): GridData; /** * Remove a row at the given index, shifting all components of the grid accordingly. * @param index The index to remove the row at. * @returns The new grid with the row removed. */ removeRow(index: number): GridData; /** * Resize the grid to the new width and height, shifting all components of the grid accordingly. Newly inserted tiles are gray. * @param width The new width of the grid. * @param height The new height of the grid. * @returns The new grid with the new dimensions. */ resize(width: number, height: number): this; /** * Create a new mutable TileData array from a string array. * * - Use `b` for dark cells, `w` for light cells, and `n` for gray cells. * - Capitalize the letter to make the tile fixed. * - Use `.` to represent empty space. * * @param array - The string array to create the tiles from. * @returns The created tile array. */ static createTiles(array: string[]): TileData[][]; /** * Find a tile in the grid that satisfies the predicate. * * @param predicate The predicate to test each tile with. * @returns The position of the first tile that satisfies the predicate, or undefined if no tile is found. */ find(predicate: (tile: TileData, x: number, y: number) => boolean): Position | undefined; /** * Iterate over all tiles in the same region as the given position that satisfy the predicate. * The iteration stops when the callback returns a value that is not undefined. * Non-existent tiles are not included in the iteration. * * @param position The position to start the iteration from. This position is included in the iteration. * @param predicate The predicate to test each tile with. The callback is only called for tiles that satisfy this predicate. * @param callback The callback to call for each tile that satisfies the predicate. The iteration stops when this callback returns a value that is not undefined. * @param visited A 2D array to keep track of visited tiles. This array is modified by the function. * @returns The value returned by the callback that stopped the iteration, or undefined if the iteration completed. */ iterateArea<T>(position: Position, predicate: (tile: TileData) => boolean, callback: (tile: TileData, x: number, y: number, logicalX: number, logicalY: number) => undefined | T, visited?: boolean[][]): T | undefined; /** * Iterate over all tiles in a straight line from the given position in the given direction that satisfy the predicate. * The iteration stops when the callback returns a value that is not undefined. * Non-existent tiles break the iteration. * * @param position The position to start the iteration from. This position is included in the iteration. * @param direction The direction to iterate in. * @param predicate The predicate to test each tile with. The callback is only called for tiles that satisfy this predicate. * @param callback The callback to call for each tile that satisfies the predicate. The iteration stops when this callback returns a value that is not undefined. * @param visited A 2D array to keep track of visited tiles. This array is modified by the function. * @returns The value returned by the callback that stopped the iteration, or undefined if the iteration completed. */ iterateDirection<T>(position: Position, direction: Direction | Orientation, predicate: (tile: TileData) => boolean, callback: (tile: TileData, x: number, y: number, logicalX: number, logicalY: number) => T | undefined, visited?: boolean[][]): T | undefined; /** * Iterate over all tiles in a straight line from the given position in the given direction that satisfy the predicate. * The iteration stops when the callback returns a value that is not undefined. * Non-existent tiles are included in the iteration. * * @param position The position to start the iteration from. This position is included in the iteration. * @param direction The direction to iterate in. * @param predicate The predicate to test each tile with. The callback is only called for tiles that satisfy this predicate. * @param callback The callback to call for each tile that satisfies the predicate. The iteration stops when this callback returns a value that is not undefined. * @param visited A 2D array to keep track of visited tiles. This array is modified by the function. * @returns The value returned by the callback that stopped the iteration, or undefined if the iteration completed. */ iterateDirectionAll<T>(position: Position, direction: Direction | Orientation, predicate: (tile: TileData) => boolean, callback: (tile: TileData, x: number, y: number, logicalX: number, logicalY: number) => T | undefined, visited?: boolean[][]): T | undefined; /** * Check if every tile in the grid is filled with a color other than gray. * * @returns True if every tile is filled with a color other than gray, false otherwise. */ isComplete(): boolean; /** * Iterate over all tiles in the grid. * The iteration stops when the callback returns a value that is not undefined. * * @param callback The callback to call for each tile. * @returns The value returned by the callback that stopped the iteration, or undefined if the iteration completed. */ forEach<T>(callback: (tile: TileData, x: number, y: number) => T | undefined): T | undefined; /** * Flood fill a continuous region starting from the given position with the given color. * * @param position The position to start the flood fill from. * @param from The color of the tiles to fill. * @param to The color to fill the tiles with. * @param allowFixed Whether to fill fixed tiles. * @returns The new grid with the region filled with the new color. */ floodFill(position: Position, from: Color, to: Color, allowFixed: boolean): GridData; /** * Flood fill all tiles with the given color to a new color, even if they are not connected. * * @param from The color of the tiles to fill. * @param to The color to fill the tiles with. * @param allowFixed Whether to fill fixed tiles. * @returns The new grid with all tiles filled with the new color. */ floodFillAll(from: Color, to: Color, allowFixed: boolean): GridData; /** * Check if the grid has any instructions that require a custom solution. * @returns True if the grid has any instructions that require a custom solution, false otherwise. */ requireSolution(): boolean; /** * Reset all non-fixed tiles to gray. * * @returns The new grid with all non-fixed tiles reset to gray. */ resetTiles(): this; /** * Copy the tiles in the given region to a new grid. * All connections and symbols within the selected region are copied. * All rules are included as well. * * @param origin The top-left corner of the region to copy. * @param width The width of the region to copy. * @param height The height of the region to copy. * @returns The new grid with the copied tiles. */ copyTiles(origin: Position, width: number, height: number): GridData; /** * Paste the tiles from the given grid to the current grid at the given position. * All connections, symbols, and rules are merged. * * @param origin The top-left corner of the region to paste the tiles to. * @param grid The grid to paste the tiles from. * @returns The new grid with the pasted tiles. */ pasteTiles(origin: Position, grid: GridData): GridData; /** * Paste the tiles from the given array to the current grid at the given position. * * @param origin The top-left corner of the region to paste the tiles to. * @param tile The array of tiles to paste. * @returns The new grid with the pasted tiles. */ pasteTiles(origin: Position, tile: readonly (readonly TileData[])[]): GridData; /** * Check if this grid is equal to another grid in terms of size and tile colors. * Rules, symbols, and connections are not compared. * * @param grid The grid to compare with. * @returns True if the grids are equal in size and tile colors, false otherwise. */ colorEquals(grid: GridData): boolean; /** * Check if this grid is equal to another grid in terms of size, tile colors, connections, symbols, and rules. * * @param other The grid to compare with. * @returns True if the grids are equal, false otherwise. */ equals(other: GridData): boolean; /** * Get the count of tiles that satisfy the given conditions. * @param exists Whether the tile exists or not. * @param fixed Whether the tile is fixed or not. If undefined, the fixed state is ignored. * @param color The color of the tile. If undefined, all colors are included. * @returns The count of tiles that satisfy the given conditions. */ getTileCount(exists: boolean, fixed?: boolean | undefined, color?: Color | undefined): number; /** * Get the count of tiles that satisfy the given conditions for each color. * @param color The color of the tiles. * @returns The count of tiles that satisfy the given conditions for each color. */ getColorCount(color: Color): { min: number; max: number; }; /** * Deduplicate the rules in the given list. * * @param rules The list of rules to deduplicate. * @returns The deduplicated list of rules. */ static deduplicateRules(rules: readonly Rule[]): Rule[]; /** * Deduplicate the singleton rules in the given list. * * @param rules The list of rules to deduplicate. * @returns The deduplicated list of rules. */ static deduplicateSingletonRules(rules: readonly Rule[]): Rule[]; /** * Deduplicate the symbols in the given map. * * @param symbols The map of symbols to deduplicate. * @returns The deduplicated map of symbols. */ static deduplicateSymbols(symbols: ReadonlyMap<string, readonly Symbol[]>): Map<string, Symbol[]>; }