import GridConnections from './gridConnections.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';
export default class GridData {
    readonly width: number;
    readonly height: number;
    readonly tiles: readonly (readonly TileData[])[];
    readonly connections: GridConnections;
    readonly symbols: ReadonlyMap<string, readonly Symbol[]>;
    readonly rules: readonly Rule[];
    /**
     * 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 symbols The symbols in the grid.
     * @param rules The rules of the grid.
     */
    constructor(width: number, height: number, tiles?: readonly (readonly TileData[])[], connections?: GridConnections, symbols?: ReadonlyMap<string, readonly Symbol[]>, rules?: readonly Rule[]);
    /**
     * 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, symbols, rules, }: {
        width?: number;
        height?: number;
        tiles?: readonly (readonly TileData[])[];
        connections?: GridConnections;
        symbols?: ReadonlyMap<string, readonly Symbol[]>;
        rules?: readonly Rule[];
    }): GridData;
    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 grid 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 grid with the tile set at the given position.
     */
    setTile(x: number, y: number, tile: TileData | ((tile: TileData) => TileData)): GridData;
    /**
     * 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 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[][];
    /**
     * 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;
    /**
     * 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.
     * @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) => undefined | T): 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.
     * @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) => T | undefined): 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.
     * @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) => T | undefined): 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[]>;
}
